From 36ca2ee309b4fff304e3d581e925a0e63547dcd7 Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Fri, 29 May 2020 23:01:25 +0200
Subject: [PATCH 1/8] Cleane dup project open and handling of legacy project
content
---
nw/constants/constants.py | 2 +
nw/core/__init__.py | 2 -
nw/core/project.py | 209 ++++++++++++++++++++++---------
nw/core/tools.py | 40 ------
sample/content/ae7339df26ded.nwd | 2 +-
sample/content/b8136a5a774a0.nwd | 2 +-
sample/content/edca4be2fcaf8.nwd | 2 +-
sample/content/f1471bef9f2ae.nwd | 6 -
sample/nwProject.nwx | 34 ++---
9 files changed, 172 insertions(+), 127 deletions(-)
diff --git a/nw/constants/constants.py b/nw/constants/constants.py
index bc20af31..cf0ab4eb 100644
--- a/nw/constants/constants.py
+++ b/nw/constants/constants.py
@@ -39,6 +39,8 @@ class nwFiles():
PROJ_FILE = "nwProject.nwx"
PROJ_DICT = "wordlist.txt"
PROJ_LOCK = "nwProject.lock"
+ TOC_TXT = "ToC.txt"
+ TOC_JSON = "ToC.json"
SESS_INFO = "sessionInfo.log"
INDEX_FILE = "tagsIndex.json"
OPTS_FILE = "guiOptions.json"
diff --git a/nw/core/__init__.py b/nw/core/__init__.py
index 6dd65fd2..0107dac2 100644
--- a/nw/core/__init__.py
+++ b/nw/core/__init__.py
@@ -9,7 +9,6 @@ from nw.core.spellcheck import NWSpellSimple
from nw.core.tokenizer import Tokenizer
from nw.core.tohtml import ToHtml
from nw.core.tools import countWords
-from nw.core.tools import projectMaintenance
from nw.core.tools import numberToWord
__all__ = [
@@ -22,6 +21,5 @@ __all__ = [
"Tokenizer",
"ToHtml",
"countWords",
- "projectMaintenance",
"numberToWord",
]
diff --git a/nw/core/project.py b/nw/core/project.py
index cf35f629..c89bb645 100644
--- a/nw/core/project.py
+++ b/nw/core/project.py
@@ -42,7 +42,6 @@ from shutil import make_archive
from PyQt5.QtWidgets import QMessageBox
from nw.gui.tools import OptionState
-from nw.core.tools import projectMaintenance
from nw.core.document import NWDoc
from nw.common import checkString, checkBool, checkInt, formatTimeStamp
from nw.constants import (
@@ -72,11 +71,12 @@ class NWProject():
self.autoCount = 0 # Meta data: number of automatic saves
# Class Settings
- self.projPath = None # The full path to where the currently open project is saved
- self.projMeta = None # The full path to the project's meta data folder
- self.projData = None # The full path to the project's data folder
- self.projDict = None # The spell check dictionary
- self.projFile = None # The file name of the project main XML file
+ self.projPath = None # The full path to where the currently open project is saved
+ self.projMeta = None # The full path to the project's meta data folder
+ self.projCache = None # The full path to the project's cache folder
+ self.projContent = None # The full path to the project's content folder
+ self.projDict = None # The spell check dictionary
+ self.projFile = None # The file name of the project main XML file
# Project Meta
self.projName = "" # Project name (working title)
@@ -196,7 +196,8 @@ class NWProject():
# Project Settings
self.projPath = None
self.projMeta = None
- self.projData = None
+ self.projCache = None
+ self.projContent = None
self.projDict = None
self.projFile = nwFiles.PROJ_FILE
self.projName = ""
@@ -248,14 +249,37 @@ class NWProject():
self.projPath = path.abspath(path.dirname(fileName))
logger.debug("Opening project: %s" % self.projPath)
- self.projMeta = path.join(self.projPath,"meta")
- self.projData = path.join(self.projPath,"content")
- self.projDict = path.join(self.projMeta, nwFiles.PROJ_DICT)
+ # Standard Folders and Files
+ # ==========================
+
+ self.projMeta = path.join(self.projPath, "meta")
+ self.projCache = path.join(self.projPath, "cache")
+ self.projContent = path.join(self.projPath, "content")
+ self.projDict = path.join(self.projMeta, nwFiles.PROJ_DICT)
if not self._checkFolder(self.projMeta):
return False
- if not self._checkFolder(self.projData):
+ if not self._checkFolder(self.projCache):
return False
+ if not self._checkFolder(self.projContent):
+ return False
+
+ # Check for Old Legacy Data
+ # =========================
+
+ errList = []
+ for projItem in listdir(self.projPath):
+ logger.verbose("Project contains: %s" % projItem)
+ if projItem.startswith("data_"):
+ self._legacyDataFolder(projItem)
+
+ if errList:
+ self.makeAlert(errList, nwAlert.ERROR)
+
+ self._deprecatedFiles()
+
+ # Project Lock
+ # ============
if overrideLock:
self._clearLockFile()
@@ -272,10 +296,8 @@ class NWProject():
else:
logger.verbose("Project is not locked")
- try:
- projectMaintenance(self)
- except Exception as E:
- logger.error(str(E))
+ # Open The Project XML File
+ # =========================
try:
nwXML = etree.parse(fileName)
@@ -321,6 +343,7 @@ class NWProject():
# Check File Type
# ===============
+
if not nwxRoot == "novelWriterXML":
self.makeAlert(
"Project file does not appear to be a novelWriterXML file.",
@@ -330,14 +353,17 @@ class NWProject():
# Check Project Storage Version
# =============================
+
if fileVersion == "1.0":
msgBox = QMessageBox()
msgRes = msgBox.question(self.theParent, "Old Project Version", (
"The project file and data is created by a %s version lower than 0.7. "
"Do you want to upgrade the project to the most recent format?
"
"Note that after the upgrade, you cannot open the project with an older "
- "version of novelWriter any more, so make sure you have a recent backup."
- ) % nw.__package__)
+ "version of %s any more, so make sure you have a recent backup."
+ ) % (
+ nw.__package__, nw.__package__
+ ))
if msgRes == QMessageBox.Yes:
self._updateStorage()
else:
@@ -353,6 +379,7 @@ class NWProject():
# Check novelWriter Version
# =========================
+
if int(hexVersion, 16) > int(nw.__hexversion__, 16) and self.mainConf.showGUI:
msgBox = QMessageBox()
msgRes = msgBox.question(self.theParent, "Version Conflict", (
@@ -367,6 +394,7 @@ class NWProject():
# Start Parsing XML
# =================
+
for xChild in xRoot:
if xChild.tag == "project":
logger.debug("Found project meta")
@@ -384,6 +412,7 @@ class NWProject():
self.bookAuthors.append(xItem.text)
elif xItem.tag == "backup":
self.doBackup = checkBool(xItem.text, False)
+
elif xChild.tag == "settings":
logger.debug("Found project settings")
for xItem in xChild:
@@ -411,6 +440,7 @@ class NWProject():
for xEntry in xItem:
titleFormat[xEntry.tag] = checkString(xEntry.text, "", False)
self.setTitleFormat(titleFormat)
+
elif xChild.tag == "content":
logger.debug("Found project content")
self.projTree.unpackXML(xChild)
@@ -444,14 +474,14 @@ class NWProject():
return False
self.projMeta = path.join(self.projPath, "meta")
- self.projData = path.join(self.projPath, "content")
+ self.projContent = path.join(self.projPath, "content")
saveTime = time()
if not self._checkFolder(self.projPath):
return False
if not self._checkFolder(self.projMeta):
return False
- if not self._checkFolder(self.projData):
+ if not self._checkFolder(self.projContent):
return False
logger.debug("Saving project: %s" % self.projPath)
@@ -978,7 +1008,7 @@ class NWProject():
# Then check the files in the data folder
orphanFiles = []
- for fileItem in listdir(self.projData):
+ for fileItem in listdir(self.projContent):
if not fileItem.endswith(".nwd"):
logger.warning("Skipping file %s" % fileItem)
continue
@@ -1046,52 +1076,113 @@ class NWProject():
return True
- def _updateStorage(self):
- """Updates the project storage folder from 1.0 to 1.1.
+ ##
+ # Legacy Data Structure Handlers
+ ##
+
+ def _legacyDataFolder(self, theFolder):
+ """Clean up legacy data folders.
"""
- contDir = path.join(self.projPath, "content")
- self._checkFolder(contDir)
errList = []
+ theData = path.join(self.projPath, theFolder)
+ if not path.isdir(theData):
+ errList.append("Not a folder: %s" % theData)
+ return errList
- for projItem in listdir(self.projPath):
- itemPath = path.join(self.projPath, projItem)
- if not path.isdir(itemPath) or not projItem.startswith("data_"):
+ logger.info("Old data folder %s found" % theFolder)
+
+ # Move Documents to Content
+ # =========================
+ for dataItem in listdir(theData):
+ theFile = path.join(theData, dataItem)
+ if not path.isfile(theFile):
+ theErr = self._moveUnknownItem(theData, dataItem)
+ if theErr:
+ errList.append(theErr)
continue
- for dataFile in listdir(itemPath):
- dataPath = path.join(itemPath, dataFile)
- if dataFile.endswith(".bak"):
- try:
- unlink(dataPath)
- logger.info("Deleted file: %s" % dataPath)
- except:
- errList.append("Failed to delete: %s" % dataPath)
- elif dataFile.endswith(".nwd") and len(dataFile) == 21:
- tHandle = projItem[-1]+dataFile[:12]
- newPath = path.join(contDir, tHandle+".nwd")
- try:
- rename(dataPath, newPath)
- logger.info("Moved file: %s" % dataPath)
- logger.info("New location: %s" % newPath)
- except:
- errList.append("Failed to move: %s" % dataPath)
+ if len(dataItem) == 21 and dataItem.endswith("_main.nwd"):
+ tHandle = theFolder[-1]+dataItem[:12]
+ newPath = path.join(self.projContent, tHandle+".nwd")
+ try:
+ rename(theFile, newPath)
+ logger.info("Moved file: %s" % theFile)
+ logger.info("New location: %s" % newPath)
+ except Exception as e:
+ logger.error(str(e))
+ errList.append("Could not move: %s" % theFile)
- else:
- newPath = path.join(self.projPath, "unknown_"+dataFile)
- try:
- rename(dataPath, newPath)
- logger.info("Moved file: %s" % dataPath)
- logger.info("New location: %s" % newPath)
- except:
- errList.append("Failed to move: %s" % dataPath)
- try:
- rmdir(itemPath)
- logger.info("Removed folder: %s" % itemPath)
- except:
- errList.append("Failed to delete: %s" % itemPath)
+ elif len(dataItem) == 21 and dataItem.endswith("_main.bak"):
+ try:
+ unlink(theFile)
+ logger.info("Deleted file: %s" % theFile)
+ except Exception as e:
+ logger.error(str(e))
+ errList.append("Could not delete: %s" % theFile)
- if errList:
- self.makeAlert(errList, nwAlert.ERROR)
+ else:
+ theErr = self._moveUnknownItem(theData, dataItem)
+ if theErr:
+ errList.append(theErr)
+
+ # Remove Data Folder
+ # ==================
+ try:
+ rmdir(theData)
+ logger.info("Removed folder: %s" % theFolder)
+ except:
+ errList.append("Failed to remove: %s" % theFolder)
+
+ return errList
+
+ def _moveUnknownItem(self, theDir, theItem):
+ """Move an item that doesn't belong in the project folder to
+ a junk folder.
+ """
+ theJunk = path.join(self.projPath, "junk")
+ if not self._checkFolder(theJunk):
+ return "Could not make folder: %s" % theJunk
+
+ theSrc = path.join(theDir, theItem)
+ theDst = path.join(theJunk, theItem)
+
+ try:
+ rename(theSrc, theDst)
+ logger.info("Moved to junk: %s" % theSrc)
+ except Exception as e:
+ logger.error(str(e))
+ return "Could not move item %s to junk." % theSrc
+
+ return ""
+
+ def _deprecatedFiles(self):
+ """Delete files that are no longer used by novelWriter.
+ """
+ rmList = []
+ rmList.append(path.join(self.projCache, "nwProject.nwx.0"))
+ rmList.append(path.join(self.projCache, "nwProject.nwx.1"))
+ rmList.append(path.join(self.projCache, "nwProject.nwx.2"))
+ rmList.append(path.join(self.projCache, "nwProject.nwx.3"))
+ rmList.append(path.join(self.projCache, "nwProject.nwx.4"))
+ rmList.append(path.join(self.projCache, "nwProject.nwx.5"))
+ rmList.append(path.join(self.projCache, "nwProject.nwx.6"))
+ rmList.append(path.join(self.projCache, "nwProject.nwx.7"))
+ rmList.append(path.join(self.projCache, "nwProject.nwx.8"))
+ rmList.append(path.join(self.projCache, "nwProject.nwx.9"))
+ rmList.append(path.join(self.projMeta, "mainOptions.json"))
+ rmList.append(path.join(self.projMeta, "exportOptions.json"))
+ rmList.append(path.join(self.projMeta, "outlineOptions.json"))
+ rmList.append(path.join(self.projMeta, "timelineOptions.json"))
+ rmList.append(path.join(self.projMeta, "docMergeOptions.json"))
+ rmList.append(path.join(self.projMeta, "sessionLogOptions.json"))
+
+ for rmFile in rmList:
+ if path.isfile(rmFile):
+ logger.info("Deleting: %s" % rmFile)
+ try:
+ unlink(rmFile)
+ except Exception as e:
+ logger.error(str(e))
return
diff --git a/nw/core/tools.py b/nw/core/tools.py
index 8aa81d7b..8115105d 100644
--- a/nw/core/tools.py
+++ b/nw/core/tools.py
@@ -8,7 +8,6 @@
File History:
Created: 2019-04-22 [0.0.1] countWords
Created: 2019-10-13 [0.2.3] numberToWord, _numberToWordEN
- Created: 2020-02-13 [0.4.3] projectMaintenance
Merged: 2020-05-08 [0.4.5] All of the above into this file
This file is a part of novelWriter
@@ -81,45 +80,6 @@ def countWords(theText):
return charCount, wordCount, paraCount
-def projectMaintenance(theProject):
- """Wrapper class for handling various tasks related to managing old
- projects with content from older versions of novelWriter.
- """
- # Remove no longer used project cache folder
- if path.isdir(theProject.projPath):
- cacheDir = path.join(theProject.projPath, "cache")
- if path.isdir(cacheDir):
- logger.info("Deprecated cache folder content found")
- rmList = []
- for i in range(10):
- rmList.append(path.join(cacheDir, "nwProject.nwx.%d" % i))
- rmList.append(path.join(cacheDir, "projCount.txt"))
- for rmFile in rmList:
- if path.isfile(rmFile):
- logger.info("Deleting: %s" % rmFile)
- try:
- unlink(rmFile)
- except Exception as e:
- logger.error(str(e))
-
- # Remove no longer used meta files
- rmList = []
- rmList.append(path.join(theProject.projMeta, "mainOptions.json"))
- rmList.append(path.join(theProject.projMeta, "exportOptions.json"))
- rmList.append(path.join(theProject.projMeta, "outlineOptions.json"))
- rmList.append(path.join(theProject.projMeta, "timelineOptions.json"))
- rmList.append(path.join(theProject.projMeta, "docMergeOptions.json"))
- rmList.append(path.join(theProject.projMeta, "sessionLogOptions.json"))
- for rmFile in rmList:
- if path.isfile(rmFile):
- logger.info("Deleting: %s" % rmFile)
- try:
- unlink(rmFile)
- except Exception as e:
- logger.error(str(e))
-
- return
-
def numberToWord(numVal, theLanguage):
"""Wrapper for converting numbers to words for chapter headings.
"""
diff --git a/sample/content/ae7339df26ded.nwd b/sample/content/ae7339df26ded.nwd
index 8b92a69c..05ed60d5 100644
--- a/sample/content/ae7339df26ded.nwd
+++ b/sample/content/ae7339df26ded.nwd
@@ -2,6 +2,6 @@
### We Found John!
@pov: John
-@location: Mars, OuterSpace
+@location: Mars
Jane has been searching for a while, and she finally found John on Mars. He was indeed in space! What was he doing on Mars anyway? Well, it turns out, he was farming potatoes.
diff --git a/sample/content/b8136a5a774a0.nwd b/sample/content/b8136a5a774a0.nwd
index a304cb35..4e63373d 100644
--- a/sample/content/b8136a5a774a0.nwd
+++ b/sample/content/b8136a5a774a0.nwd
@@ -1,4 +1,4 @@
-%%~ b8136a5a774a0:7031beac91f75:Delete Me!
+%%~ b8136a5a774a0:98acd8c76c93a:Delete Me!
### Delete Me!
This scene is trash.
\ No newline at end of file
diff --git a/sample/content/edca4be2fcaf8.nwd b/sample/content/edca4be2fcaf8.nwd
index 5fef1f34..679e4e27 100644
--- a/sample/content/edca4be2fcaf8.nwd
+++ b/sample/content/edca4be2fcaf8.nwd
@@ -1,4 +1,4 @@
-%%~ edca4be2fcaf8:7031beac91f75:Part One
+%%~ edca4be2fcaf8:7031beac91f75:Part 1
# Part One
The first part.
\ No newline at end of file
diff --git a/sample/content/f1471bef9f2ae.nwd b/sample/content/f1471bef9f2ae.nwd
index 3bd03e9d..9b2d9368 100644
--- a/sample/content/f1471bef9f2ae.nwd
+++ b/sample/content/f1471bef9f2ae.nwd
@@ -5,10 +5,4 @@
Space … it’s an awful lot of nothing, with bits in it here and there. Some of which, people like to call home.
-## Outer Space
-@tag: OuterSpace
-
-Now even further into space!
-
-You can have more than one tag in a file, as long as there is only one tag per heading.
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index b6f63962..58b97959 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Sample Project
Sample Project
@@ -11,8 +11,8 @@
True
True
636b6aa9b697b
- bc0cbd2a407f3
- 941
+ ba8a28a246524
+ 914
B
E
@@ -73,7 +73,7 @@
False
True
PAGE
- 210
+ 208
40
2
213
@@ -89,7 +89,7 @@
23
5
1
- 27
+ 0
-
A Folder
@@ -122,7 +122,7 @@
1199
216
7
- 1066
+ 1266
-
Another Scene
@@ -135,7 +135,7 @@
476
93
3
- 428
+ 551
-
Interlude
@@ -148,7 +148,7 @@
633
101
3
- 752
+ 1238
-
A Note on Structure
@@ -161,7 +161,7 @@
1692
313
6
- 551
+ 1721
-
Chapter Two
@@ -174,7 +174,7 @@
139
28
1
- 242
+ 343
-
We Found John!
@@ -214,7 +214,7 @@
49
9
1
- 65
+ 24
-
Jane Smith
@@ -227,7 +227,7 @@
55
9
1
- 71
+ 25
-
Locations
@@ -247,7 +247,7 @@
76
15
1
- 93
+ 20
-
Space
@@ -257,10 +257,10 @@
False
True
NOTE
- 241
- 51
- 3
- 135
+ 115
+ 24
+ 1
+ 133
-
Mars
From cae9705e4f0fe7f09e1736ba010aa781f2edf09d Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Fri, 29 May 2020 23:03:04 +0200
Subject: [PATCH 2/8] Files don't need the expanded flag saved to XML
---
nw/core/project.py | 3 ++-
sample/nwProject.nwx | 18 +-----------------
2 files changed, 3 insertions(+), 18 deletions(-)
diff --git a/nw/core/project.py b/nw/core/project.py
index c89bb645..abaed265 100644
--- a/nw/core/project.py
+++ b/nw/core/project.py
@@ -1572,7 +1572,6 @@ class NWItem():
xSub = self._subPack(xPack,"type", text=str(self.itemType.name))
xSub = self._subPack(xPack,"class", text=str(self.itemClass.name))
xSub = self._subPack(xPack,"status", text=str(self.itemStatus))
- xSub = self._subPack(xPack,"expanded", text=str(self.isExpanded))
if self.itemType == nwItemType.FILE:
xSub = self._subPack(xPack,"exported", text=str(self.isExported))
xSub = self._subPack(xPack,"layout", text=str(self.itemLayout.name))
@@ -1580,6 +1579,8 @@ class NWItem():
xSub = self._subPack(xPack,"wordCount", text=str(self.wordCount), none=False)
xSub = self._subPack(xPack,"paraCount", text=str(self.paraCount), none=False)
xSub = self._subPack(xPack,"cursorPos", text=str(self.cursorPos), none=False)
+ else:
+ xSub = self._subPack(xPack,"expanded", text=str(self.isExpanded))
return
def unpackXML(self, xItem):
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index 58b97959..60752873 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Sample Project
Sample Project
@@ -57,7 +57,6 @@
FILE
NOVEL
Started
- False
True
TITLE
72
@@ -70,7 +69,6 @@
FILE
NOVEL
New
- False
True
PAGE
208
@@ -83,7 +81,6 @@
FILE
NOVEL
New
- False
True
PARTITION
23
@@ -103,7 +100,6 @@
FILE
NOVEL
Notes
- False
True
CHAPTER
12
@@ -116,7 +112,6 @@
FILE
NOVEL
1st Draft
- False
True
SCENE
1199
@@ -129,7 +124,6 @@
FILE
NOVEL
1st Draft
- False
True
SCENE
476
@@ -142,7 +136,6 @@
FILE
NOVEL
Finished
- False
True
UNNUMBERED
633
@@ -155,7 +148,6 @@
FILE
NOVEL
2nd Draft
- False
False
NOTE
1692
@@ -168,7 +160,6 @@
FILE
NOVEL
1st Draft
- False
True
CHAPTER
139
@@ -181,7 +172,6 @@
FILE
NOVEL
1st Draft
- False
True
SCENE
189
@@ -208,7 +198,6 @@
FILE
CHARACTER
Minor
- False
True
NOTE
49
@@ -221,7 +210,6 @@
FILE
CHARACTER
Major
- False
True
NOTE
55
@@ -241,7 +229,6 @@
FILE
WORLD
Main
- False
True
NOTE
76
@@ -254,7 +241,6 @@
FILE
WORLD
Minor
- False
True
NOTE
115
@@ -267,7 +253,6 @@
FILE
WORLD
Major
- False
True
NOTE
28
@@ -287,7 +272,6 @@
FILE
NOVEL
New
- False
True
SCENE
0
From 421c40c288508f551c4875aa3c88b097d52aa280 Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Fri, 29 May 2020 23:08:27 +0200
Subject: [PATCH 3/8] Fixed tests
---
tests/reference/gui/0_nwProject.nwx | 3 +--
tests/reference/gui/1_nwProject.nwx | 6 +-----
tests/reference/gui/2_nwProject.nwx | 3 +--
tests/reference/gui/3_nwProject.nwx | 3 +--
tests/reference/proj/1_nwProject.nwx | 3 +--
tests/reference/proj/2_nwProject.nwx | 3 +--
tests/reference/proj/3_nwProject.nwx | 5 +----
7 files changed, 7 insertions(+), 19 deletions(-)
diff --git a/tests/reference/gui/0_nwProject.nwx b/tests/reference/gui/0_nwProject.nwx
index 99ea2a3d..6d2bf739 100644
--- a/tests/reference/gui/0_nwProject.nwx
+++ b/tests/reference/gui/0_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
@@ -55,7 +55,6 @@
FILE
NOVEL
New
- False
True
SCENE
0
diff --git a/tests/reference/gui/1_nwProject.nwx b/tests/reference/gui/1_nwProject.nwx
index c9bb4dad..112a4be0 100644
--- a/tests/reference/gui/1_nwProject.nwx
+++ b/tests/reference/gui/1_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
@@ -55,7 +55,6 @@
FILE
NOVEL
New
- False
True
SCENE
331
@@ -75,7 +74,6 @@
FILE
CHARACTER
New
- False
True
NOTE
34
@@ -95,7 +93,6 @@
FILE
PLOT
New
- False
True
NOTE
48
@@ -115,7 +112,6 @@
FILE
WORLD
New
- False
True
NOTE
51
diff --git a/tests/reference/gui/2_nwProject.nwx b/tests/reference/gui/2_nwProject.nwx
index bf3c5b61..c4668fe4 100644
--- a/tests/reference/gui/2_nwProject.nwx
+++ b/tests/reference/gui/2_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Project Name
Project Title
@@ -59,7 +59,6 @@
FILE
NOVEL
New
- False
True
SCENE
0
diff --git a/tests/reference/gui/3_nwProject.nwx b/tests/reference/gui/3_nwProject.nwx
index f7db491f..35e1b8df 100644
--- a/tests/reference/gui/3_nwProject.nwx
+++ b/tests/reference/gui/3_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
@@ -55,7 +55,6 @@
FILE
NOVEL
Note
- False
False
PAGE
0
diff --git a/tests/reference/proj/1_nwProject.nwx b/tests/reference/proj/1_nwProject.nwx
index 651ae852..53499ddc 100644
--- a/tests/reference/proj/1_nwProject.nwx
+++ b/tests/reference/proj/1_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
@@ -76,7 +76,6 @@
FILE
NOVEL
New
- False
True
SCENE
0
diff --git a/tests/reference/proj/2_nwProject.nwx b/tests/reference/proj/2_nwProject.nwx
index 7bd8d7cb..22a9e0fb 100644
--- a/tests/reference/proj/2_nwProject.nwx
+++ b/tests/reference/proj/2_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
@@ -76,7 +76,6 @@
FILE
NOVEL
New
- False
True
SCENE
0
diff --git a/tests/reference/proj/3_nwProject.nwx b/tests/reference/proj/3_nwProject.nwx
index 94f11ba7..ee8f6e1a 100644
--- a/tests/reference/proj/3_nwProject.nwx
+++ b/tests/reference/proj/3_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
@@ -76,7 +76,6 @@
FILE
NOVEL
New
- False
True
SCENE
0
@@ -117,7 +116,6 @@
FILE
NOVEL
New
- False
True
SCENE
0
@@ -130,7 +128,6 @@
FILE
CHARACTER
New
- False
True
NOTE
0
From 5d2f6d33b5785c606f0d6f5c33e62a79928ef999 Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Fri, 29 May 2020 23:31:38 +0200
Subject: [PATCH 4/8] Also updated the documen class with new project variables
---
.gitignore | 10 ++++------
nw/core/document.py | 41 +++++++++++++++++++----------------------
nw/core/project.py | 44 +++++++++++++++++++++++++-------------------
sample/nwProject.nwx | 6 +++---
4 files changed, 51 insertions(+), 50 deletions(-)
diff --git a/.gitignore b/.gitignore
index 2905634a..c87816d0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,12 +14,10 @@ docs/source/_*
__pycache__
# Sample Project
-sample/**/cache
-sample/**/wordlist.txt
-sample/**/sessionInfo.log
-sample/**/*.bak
-sample/**/*.json
-sample/**/*.lock
+sample/cache
+sample/meta
+sample/*.bak
+sample/*.lock
# PyTest
tests/temp
diff --git a/nw/core/document.py b/nw/core/document.py
index 7ce4de4e..6ab4d500 100644
--- a/nw/core/document.py
+++ b/nw/core/document.py
@@ -91,18 +91,17 @@ class NWDoc():
if self.theItem.parHandle == self.theProject.projTree.trashRoot():
self.docEditable = False
- docDir = "content"
docFile = self.docHandle+".nwd"
- self.fileLoc = path.join(docDir, docFile)
- logger.debug("Opening document %s" % self.fileLoc)
- dataDir = path.join(self.theProject.projPath, docDir)
- docPath = path.join(dataDir, docFile)
+ logger.debug("Opening document %s" % docFile)
+
+ docPath = path.join(self.theProject.projContent, docFile)
+ self.fileLoc = docPath
theText = ""
self.docMeta = ""
if path.isfile(docPath):
try:
- with open(docPath,mode="r",encoding="utf8") as inFile:
+ with open(docPath, mode="r", encoding="utf8") as inFile:
fstLine = inFile.readline()
if fstLine.startswith("%%~ "):
# This is the meta line
@@ -112,7 +111,7 @@ class NWDoc():
theText += inFile.read()
except Exception as e:
- self.makeAlert(["Failed to open document file.",str(e)], nwAlert.ERROR)
+ self.makeAlert(["Failed to open document file.", str(e)], nwAlert.ERROR)
# Note: Document must be cleared in case of an io error,
# or else the auto-save or save will try to overwrite it
# with an empty file. Return None to alert the caller.
@@ -138,25 +137,23 @@ class NWDoc():
if self.docHandle is None or not self.docEditable:
return False
- docDir = "content"
+ self.theProject.ensureFolderStructure()
+
docFile = self.docHandle+".nwd"
- logger.debug("Saving document %s" % path.join(docDir, docFile))
- dataPath = path.join(self.theProject.projPath, docDir)
- docPath = path.join(dataPath, docFile)
- if not path.isdir(dataPath):
- mkdir(dataPath)
- logger.debug("Created folder %s" % dataPath)
+ logger.debug("Saving document %s" % docFile)
+
+ docPath = path.join(self.theProject.projContent, docFile)
+ docTemp = path.join(self.theProject.projContent, docFile+"~")
itemPath = self.theProject.projTree.getItemPath(self.docHandle)
docMeta = "%%~ "+":".join(itemPath)+":"+self.theItem.itemName+"\n"
- docTemp = path.join(dataPath, docFile+"~")
try:
- with open(docTemp,mode="w",encoding="utf8") as outFile:
+ with open(docTemp, mode="w", encoding="utf8") as outFile:
outFile.write(docMeta)
outFile.write(docText)
except Exception as e:
- self.makeAlert(["Could not save document.",str(e)], nwAlert.ERROR)
+ self.makeAlert(["Could not save document.", str(e)], nwAlert.ERROR)
return False
# If we're here, the file was successfully saved, so we can
@@ -173,13 +170,12 @@ class NWDoc():
"""Permanently delete a document source file and its backups
from the project data folder.
"""
- docDir = "content"
docFile = self.docHandle+".nwd"
- dataPath = path.join(self.theProject.projPath, docDir)
+
chkList = []
- chkList.append(path.join(dataPath, docFile))
- chkList.append(path.join(dataPath, docFile+"~"))
- chkList.append(path.join(dataPath, docFile[:-3]+"bak"))
+ chkList.append(path.join(self.theProject.projContent, docFile))
+ chkList.append(path.join(self.theProject.projContent, docFile+"~"))
+
for chkFile in chkList:
if path.isfile(chkFile):
try:
@@ -188,6 +184,7 @@ class NWDoc():
except Exception as e:
self.makeAlert(["Could not delete document file.",str(e)], nwAlert.ERROR)
return False
+
return True
##
diff --git a/nw/core/project.py b/nw/core/project.py
index abaed265..d7ab3c2d 100644
--- a/nw/core/project.py
+++ b/nw/core/project.py
@@ -252,17 +252,10 @@ class NWProject():
# Standard Folders and Files
# ==========================
- self.projMeta = path.join(self.projPath, "meta")
- self.projCache = path.join(self.projPath, "cache")
- self.projContent = path.join(self.projPath, "content")
- self.projDict = path.join(self.projMeta, nwFiles.PROJ_DICT)
+ if not self.ensureFolderStructure():
+ return False
- if not self._checkFolder(self.projMeta):
- return False
- if not self._checkFolder(self.projCache):
- return False
- if not self._checkFolder(self.projContent):
- return False
+ self.projDict = path.join(self.projMeta, nwFiles.PROJ_DICT)
# Check for Old Legacy Data
# =========================
@@ -473,15 +466,8 @@ class NWProject():
)
return False
- self.projMeta = path.join(self.projPath, "meta")
- self.projContent = path.join(self.projPath, "content")
saveTime = time()
-
- if not self._checkFolder(self.projPath):
- return False
- if not self._checkFolder(self.projMeta):
- return False
- if not self._checkFolder(self.projContent):
+ if not self.ensureFolderStructure():
return False
logger.debug("Saving project: %s" % self.projPath)
@@ -582,6 +568,26 @@ class NWProject():
self.lockedBy = None
return True
+ def ensureFolderStructure(self):
+ """Ensure that all necessary folders exist in the project
+ folder.
+ """
+ if self.projPath is None or self.projPath == "":
+ return False
+
+ self.projMeta = path.join(self.projPath, "meta")
+ self.projCache = path.join(self.projPath, "cache")
+ self.projContent = path.join(self.projPath, "content")
+
+ if not self._checkFolder(self.projMeta):
+ return False
+ if not self._checkFolder(self.projCache):
+ return False
+ if not self._checkFolder(self.projContent):
+ return False
+
+ return True
+
##
# Backup Project
##
@@ -1058,7 +1064,7 @@ class NWProject():
def _appendSessionStats(self):
"""Append session statistics to the sessions log file.
"""
- if self.projMeta is None:
+ if not self.ensureFolderStructure():
return False
sessionFile = path.join(self.projMeta, nwFiles.SESS_INFO)
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index 60752873..a0d7f3ce 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Sample Project
Sample Project
@@ -11,7 +11,7 @@
True
True
636b6aa9b697b
- ba8a28a246524
+ b3e74dbc1f584
914
B
@@ -71,7 +71,7 @@
New
True
PAGE
- 208
+ 210
40
2
213
From 7b8a852101fb631688a70124c03f0fb1221d368b Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Fri, 29 May 2020 23:46:13 +0200
Subject: [PATCH 5/8] Corrected default title formats, and added editTime meta
data
---
nw/core/project.py | 8 ++++++--
sample/nwProject.nwx | 2 +-
tests/reference/gui/0_nwProject.nwx | 2 +-
tests/reference/gui/1_nwProject.nwx | 2 +-
tests/reference/gui/2_nwProject.nwx | 2 +-
tests/reference/gui/3_nwProject.nwx | 2 +-
tests/reference/proj/1_nwProject.nwx | 2 +-
tests/reference/proj/2_nwProject.nwx | 2 +-
tests/reference/proj/3_nwProject.nwx | 2 +-
9 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/nw/core/project.py b/nw/core/project.py
index d7ab3c2d..132066b3 100644
--- a/nw/core/project.py
+++ b/nw/core/project.py
@@ -69,6 +69,7 @@ class NWProject():
self.lockedBy = None # Data on which computer has the project open
self.saveCount = 0 # Meta data: number of saves
self.autoCount = 0 # Meta data: number of automatic saves
+ self.editTime = 0 # The accumulated edit time read from the project file
# Class Settings
self.projPath = None # The full path to where the currently open project is saved
@@ -206,7 +207,7 @@ class NWProject():
self.autoReplace = {}
self.titleFormat = {
"title" : r"%title%",
- "chapter" : r"Chapter %num%\\%title%",
+ "chapter" : r"Chapter %ch%: %title%",
"unnumbered" : r"%title%",
"scene" : r"* * *",
"section" : r"",
@@ -330,6 +331,8 @@ class NWProject():
self.saveCount = checkInt(xRoot.attrib["saveCount"], 0, False)
if "autoCount" in xRoot.attrib:
self.autoCount = checkInt(xRoot.attrib["autoCount"], 0, False)
+ if "editTime" in xRoot.attrib:
+ self.editTime = checkInt(xRoot.attrib["editTime"], 0, False)
logger.verbose("XML root is %s" % nwxRoot)
logger.verbose("File version is %s" % fileVersion)
@@ -486,6 +489,7 @@ class NWProject():
"saveCount" : str(self.saveCount),
"autoCount" : str(self.autoCount),
"timeStamp" : formatTimeStamp(saveTime),
+ "editTime" : str(int(self.editTime + saveTime - self.projOpened)),
})
# Save Project Meta
@@ -535,7 +539,7 @@ class NWProject():
xml_declaration = True
))
except Exception as e:
- self.makeAlert(["Failed to save project.",str(e)], nwAlert.ERROR)
+ self.makeAlert(["Failed to save project.", str(e)], nwAlert.ERROR)
return False
# If we're here, the file was successfully saved,
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index a0d7f3ce..b70706eb 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Sample Project
Sample Project
diff --git a/tests/reference/gui/0_nwProject.nwx b/tests/reference/gui/0_nwProject.nwx
index 6d2bf739..dcf46837 100644
--- a/tests/reference/gui/0_nwProject.nwx
+++ b/tests/reference/gui/0_nwProject.nwx
@@ -14,7 +14,7 @@
%title%
- Chapter %num%\\%title%
+ Chapter %ch%: %title%
%title%
* * *
diff --git a/tests/reference/gui/1_nwProject.nwx b/tests/reference/gui/1_nwProject.nwx
index 112a4be0..a09a089f 100644
--- a/tests/reference/gui/1_nwProject.nwx
+++ b/tests/reference/gui/1_nwProject.nwx
@@ -14,7 +14,7 @@
%title%
- Chapter %num%\\%title%
+ Chapter %ch%: %title%
%title%
* * *
diff --git a/tests/reference/gui/2_nwProject.nwx b/tests/reference/gui/2_nwProject.nwx
index c4668fe4..11fc5dbe 100644
--- a/tests/reference/gui/2_nwProject.nwx
+++ b/tests/reference/gui/2_nwProject.nwx
@@ -18,7 +18,7 @@
%title%
- Chapter %num%\\%title%
+ Chapter %ch%: %title%
%title%
* * *
diff --git a/tests/reference/gui/3_nwProject.nwx b/tests/reference/gui/3_nwProject.nwx
index 35e1b8df..e7f9e514 100644
--- a/tests/reference/gui/3_nwProject.nwx
+++ b/tests/reference/gui/3_nwProject.nwx
@@ -14,7 +14,7 @@
%title%
- Chapter %num%\\%title%
+ Chapter %ch%: %title%
%title%
* * *
diff --git a/tests/reference/proj/1_nwProject.nwx b/tests/reference/proj/1_nwProject.nwx
index 53499ddc..5ba28cae 100644
--- a/tests/reference/proj/1_nwProject.nwx
+++ b/tests/reference/proj/1_nwProject.nwx
@@ -14,7 +14,7 @@
%title%
- Chapter %num%\\%title%
+ Chapter %ch%: %title%
%title%
* * *
diff --git a/tests/reference/proj/2_nwProject.nwx b/tests/reference/proj/2_nwProject.nwx
index 22a9e0fb..fe5bf878 100644
--- a/tests/reference/proj/2_nwProject.nwx
+++ b/tests/reference/proj/2_nwProject.nwx
@@ -14,7 +14,7 @@
%title%
- Chapter %num%\\%title%
+ Chapter %ch%: %title%
%title%
* * *
diff --git a/tests/reference/proj/3_nwProject.nwx b/tests/reference/proj/3_nwProject.nwx
index ee8f6e1a..2e3cb6c0 100644
--- a/tests/reference/proj/3_nwProject.nwx
+++ b/tests/reference/proj/3_nwProject.nwx
@@ -14,7 +14,7 @@
%title%
- Chapter %num%\\%title%
+ Chapter %ch%: %title%
%title%
* * *
From d27e2dc60fbb86c05cc43232236f188da6c95705 Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Sat, 30 May 2020 00:15:07 +0200
Subject: [PATCH 6/8] Added code to write contents txt and json files on
project close
---
nw/constants/constants.py | 4 ++--
nw/core/project.py | 48 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/nw/constants/constants.py b/nw/constants/constants.py
index cf0ab4eb..f538f2fe 100644
--- a/nw/constants/constants.py
+++ b/nw/constants/constants.py
@@ -39,8 +39,8 @@ class nwFiles():
PROJ_FILE = "nwProject.nwx"
PROJ_DICT = "wordlist.txt"
PROJ_LOCK = "nwProject.lock"
- TOC_TXT = "ToC.txt"
- TOC_JSON = "ToC.json"
+ TOC_TXT = "content.txt"
+ TOC_JSON = "content.json"
SESS_INFO = "sessionInfo.log"
INDEX_FILE = "tagsIndex.json"
OPTS_FILE = "guiOptions.json"
diff --git a/nw/core/project.py b/nw/core/project.py
index 132066b3..f2abbcf4 100644
--- a/nw/core/project.py
+++ b/nw/core/project.py
@@ -31,6 +31,7 @@
"""
import logging
+import json
import nw
from os import path, mkdir, listdir, unlink, rename, rmdir
@@ -566,6 +567,7 @@ class NWProject():
def closeProject(self):
"""Close the current project and clear all meta data.
"""
+ self.projTree.writeToCFiles()
self._appendSessionStats()
self._clearLockFile()
self.clearProject()
@@ -1282,7 +1284,7 @@ class NWTree():
for tHandle in self._treeOrder:
tItem = self.__getitem__(tHandle)
tItem.packXML(xContent)
- return
+ return
def unpackXML(self, xContent):
"""Iterate through all items of a content XML object and add
@@ -1300,6 +1302,50 @@ class NWTree():
return True
+ def writeToCFiles(self):
+ """Write the convenience table of contents files in the root of
+ the project directory. These files are there to assist the user
+ if they wish to browse the stored files.
+ """
+ tocText = path.join(self.theProject.projPath, nwFiles.TOC_TXT)
+ tocJson = path.join(self.theProject.projPath, nwFiles.TOC_JSON)
+
+ jsonData = []
+ try:
+ # Dump the text
+ with open(tocText, mode="w", encoding="utf8") as outFile:
+ outFile.write("\n")
+ outFile.write(" Table of Contents\n")
+ outFile.write("===================\n")
+ outFile.write("\n")
+ outFile.write(" %-25s %-9s %s\n" %("File Name","Class","Document Label"))
+ outFile.write("-"*80+"\n")
+ for tHandle in sorted(self._treeOrder):
+ tItem = self.__getitem__(tHandle)
+ if tItem is None:
+ continue
+ tFile = tHandle+".nwd"
+ if path.isfile(path.join(self.theProject.projContent, tFile)):
+ outFile.write(" %-25s %-9s %s\n" %(
+ path.join("content", tFile),
+ tItem.itemClass.name,
+ tItem.itemName,
+ ))
+ jsonData.append([
+ path.join("content", tFile),
+ tItem.itemClass.name,
+ tItem.itemName,
+ ])
+
+ # Dump the JSON
+ with open(tocJson, mode="w+", encoding="utf8") as outFile:
+ outFile.write(json.dumps(jsonData, indent=2))
+
+ except Exception as e:
+ logger.error(str(e))
+
+ return
+
##
# Tree Structure Methods
##
From a7bca8486f32993b0438163e6be13e25ff8ab4de Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Sat, 30 May 2020 00:16:53 +0200
Subject: [PATCH 7/8] Added the ToC files as well to the repo
---
nw/constants/constants.py | 4 +-
sample/ToC.json | 82 +++++++++++++++++++++++++++++++++++++++
sample/ToC.txt | 22 +++++++++++
sample/nwProject.nwx | 2 +-
4 files changed, 107 insertions(+), 3 deletions(-)
create mode 100644 sample/ToC.json
create mode 100644 sample/ToC.txt
diff --git a/nw/constants/constants.py b/nw/constants/constants.py
index f538f2fe..cf0ab4eb 100644
--- a/nw/constants/constants.py
+++ b/nw/constants/constants.py
@@ -39,8 +39,8 @@ class nwFiles():
PROJ_FILE = "nwProject.nwx"
PROJ_DICT = "wordlist.txt"
PROJ_LOCK = "nwProject.lock"
- TOC_TXT = "content.txt"
- TOC_JSON = "content.json"
+ TOC_TXT = "ToC.txt"
+ TOC_JSON = "ToC.json"
SESS_INFO = "sessionInfo.log"
INDEX_FILE = "tagsIndex.json"
OPTS_FILE = "guiOptions.json"
diff --git a/sample/ToC.json b/sample/ToC.json
new file mode 100644
index 00000000..4e6ff3d1
--- /dev/null
+++ b/sample/ToC.json
@@ -0,0 +1,82 @@
+[
+ [
+ "content/14298de4d9524.nwd",
+ "CHARACTER",
+ "John Smith"
+ ],
+ [
+ "content/53b69b83cdafc.nwd",
+ "NOVEL",
+ "Title Page"
+ ],
+ [
+ "content/5eaea4e8cdee8.nwd",
+ "WORLD",
+ "Mars"
+ ],
+ [
+ "content/636b6aa9b697b.nwd",
+ "NOVEL",
+ "Making a Scene"
+ ],
+ [
+ "content/6a2d6d5f4f401.nwd",
+ "NOVEL",
+ "Chapter One"
+ ],
+ [
+ "content/88706ddc78b1b.nwd",
+ "NOVEL",
+ "Chapter Two"
+ ],
+ [
+ "content/96b68994dfa3d.nwd",
+ "NOVEL",
+ "A Note on Structure"
+ ],
+ [
+ "content/974e400180a99.nwd",
+ "NOVEL",
+ "Page"
+ ],
+ [
+ "content/ae7339df26ded.nwd",
+ "NOVEL",
+ "We Found John!"
+ ],
+ [
+ "content/b3e74dbc1f584.nwd",
+ "WORLD",
+ "Earth"
+ ],
+ [
+ "content/b8136a5a774a0.nwd",
+ "NOVEL",
+ "Delete Me!"
+ ],
+ [
+ "content/ba8a28a246524.nwd",
+ "NOVEL",
+ "Interlude"
+ ],
+ [
+ "content/bb2c23b3c42cc.nwd",
+ "CHARACTER",
+ "Jane Smith"
+ ],
+ [
+ "content/bc0cbd2a407f3.nwd",
+ "NOVEL",
+ "Another Scene"
+ ],
+ [
+ "content/edca4be2fcaf8.nwd",
+ "NOVEL",
+ "Part One"
+ ],
+ [
+ "content/f1471bef9f2ae.nwd",
+ "WORLD",
+ "Space"
+ ]
+]
\ No newline at end of file
diff --git a/sample/ToC.txt b/sample/ToC.txt
new file mode 100644
index 00000000..b1a7c2ed
--- /dev/null
+++ b/sample/ToC.txt
@@ -0,0 +1,22 @@
+
+ Table of Contents
+===================
+
+ File Name Class Document Label
+--------------------------------------------------------------------------------
+ content/14298de4d9524.nwd CHARACTER John Smith
+ content/53b69b83cdafc.nwd NOVEL Title Page
+ content/5eaea4e8cdee8.nwd WORLD Mars
+ content/636b6aa9b697b.nwd NOVEL Making a Scene
+ content/6a2d6d5f4f401.nwd NOVEL Chapter One
+ content/88706ddc78b1b.nwd NOVEL Chapter Two
+ content/96b68994dfa3d.nwd NOVEL A Note on Structure
+ content/974e400180a99.nwd NOVEL Page
+ content/ae7339df26ded.nwd NOVEL We Found John!
+ content/b3e74dbc1f584.nwd WORLD Earth
+ content/b8136a5a774a0.nwd NOVEL Delete Me!
+ content/ba8a28a246524.nwd NOVEL Interlude
+ content/bb2c23b3c42cc.nwd CHARACTER Jane Smith
+ content/bc0cbd2a407f3.nwd NOVEL Another Scene
+ content/edca4be2fcaf8.nwd NOVEL Part One
+ content/f1471bef9f2ae.nwd WORLD Space
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index b70706eb..f736c544 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Sample Project
Sample Project
From f3cc6359c4d731a13567dcdb1143346d00410e3a Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Sat, 30 May 2020 00:20:14 +0200
Subject: [PATCH 8/8] Add an empty line at the end of the ToC.txt file
---
nw/core/project.py | 1 +
sample/ToC.txt | 1 +
sample/nwProject.nwx | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/nw/core/project.py b/nw/core/project.py
index f2abbcf4..13fa1f08 100644
--- a/nw/core/project.py
+++ b/nw/core/project.py
@@ -1336,6 +1336,7 @@ class NWTree():
tItem.itemClass.name,
tItem.itemName,
])
+ outFile.write("\n")
# Dump the JSON
with open(tocJson, mode="w+", encoding="utf8") as outFile:
diff --git a/sample/ToC.txt b/sample/ToC.txt
index b1a7c2ed..da23e664 100644
--- a/sample/ToC.txt
+++ b/sample/ToC.txt
@@ -20,3 +20,4 @@
content/bc0cbd2a407f3.nwd NOVEL Another Scene
content/edca4be2fcaf8.nwd NOVEL Part One
content/f1471bef9f2ae.nwd WORLD Space
+
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index f736c544..4a88e0c1 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Sample Project
Sample Project