Index Updates (#840)
* Improve the index keyword checker function * Implement a more compact indented JSON encoder * Remove timestamp from reference, novel and note indices * Remove empty entries in reference index * Merge novel and note indices into a single file index
This commit is contained in:
committed by
GitHub
parent
e5c715695e
commit
c6973043e6
+58
-3
@@ -23,6 +23,7 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -224,16 +225,19 @@ def parseTimeStamp(theStamp, default, allowNone=False):
|
|||||||
# String Functions
|
# String Functions
|
||||||
# =============================================================================================== #
|
# =============================================================================================== #
|
||||||
|
|
||||||
def splitVersionNumber(vString):
|
def splitVersionNumber(value):
|
||||||
""" Splits a version string on the form aa.bb.cc into major, minor
|
"""Splits a version string on the form aa.bb.cc into major, minor
|
||||||
and patch, and computes an integer value aabbcc.
|
and patch, and computes an integer value aabbcc.
|
||||||
"""
|
"""
|
||||||
|
if not isinstance(value, str):
|
||||||
|
return [0, 0, 0, 0]
|
||||||
|
|
||||||
vMajor = 0
|
vMajor = 0
|
||||||
vMinor = 0
|
vMinor = 0
|
||||||
vPatch = 0
|
vPatch = 0
|
||||||
vInt = 0
|
vInt = 0
|
||||||
|
|
||||||
vBits = vString.split(".")
|
vBits = value.split(".")
|
||||||
nBits = len(vBits)
|
nBits = len(vBits)
|
||||||
|
|
||||||
if nBits > 0:
|
if nBits > 0:
|
||||||
@@ -355,6 +359,57 @@ def numberToRoman(numVal, isLower=False):
|
|||||||
return romNum.lower() if isLower else romNum
|
return romNum.lower() if isLower else romNum
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================================== #
|
||||||
|
# Encoder Functions
|
||||||
|
# =============================================================================================== #
|
||||||
|
|
||||||
|
def jsonEncode(data, n=0, nmax=0):
|
||||||
|
"""Encode a dictionary, list or tuple as a json object or array, and
|
||||||
|
indent from level n up to a max level nmax if nmax is larger than 0.
|
||||||
|
"""
|
||||||
|
if not isinstance(data, (dict, list, tuple)):
|
||||||
|
return "[]"
|
||||||
|
|
||||||
|
buffer = []
|
||||||
|
indent = ""
|
||||||
|
|
||||||
|
for chunk in json.JSONEncoder().iterencode(data):
|
||||||
|
if chunk == "": # pragma: no cover
|
||||||
|
# Just a precaution
|
||||||
|
continue
|
||||||
|
|
||||||
|
first = chunk[0]
|
||||||
|
if chunk in ("{}", "[]"):
|
||||||
|
buffer.append(chunk)
|
||||||
|
|
||||||
|
elif first in ("{", "["):
|
||||||
|
n += 1
|
||||||
|
indent = "\n"+" "*n
|
||||||
|
if n > nmax and nmax > 0:
|
||||||
|
buffer.append(chunk)
|
||||||
|
else:
|
||||||
|
buffer.append(chunk[0] + indent + chunk[1:])
|
||||||
|
|
||||||
|
elif first in ("}", "]"):
|
||||||
|
n -= 1
|
||||||
|
indent = "\n"+" "*n
|
||||||
|
if n >= nmax and nmax > 0:
|
||||||
|
buffer.append(chunk)
|
||||||
|
else:
|
||||||
|
buffer.append(indent + chunk)
|
||||||
|
|
||||||
|
elif first == ",":
|
||||||
|
if n > nmax and nmax > 0:
|
||||||
|
buffer.append(chunk)
|
||||||
|
else:
|
||||||
|
buffer.append(chunk[0] + indent + chunk[1:].lstrip())
|
||||||
|
|
||||||
|
else:
|
||||||
|
buffer.append(chunk)
|
||||||
|
|
||||||
|
return "".join(buffer)
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================================== #
|
# =============================================================================================== #
|
||||||
# Other Functions
|
# Other Functions
|
||||||
# =============================================================================================== #
|
# =============================================================================================== #
|
||||||
|
|||||||
+127
-197
@@ -32,18 +32,20 @@ import os
|
|||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from nw.enum import nwItemType, nwItemClass, nwItemLayout
|
from nw.enum import nwItemType, nwItemClass, nwItemLayout
|
||||||
from nw.common import isHandle, isTitleTag, isItemClass, isItemLayout
|
|
||||||
from nw.constants import nwFiles, nwKeyWords, nwUnicode
|
from nw.constants import nwFiles, nwKeyWords, nwUnicode
|
||||||
from nw.core.document import NWDoc
|
from nw.core.document import NWDoc
|
||||||
|
from nw.common import (
|
||||||
|
isHandle, isTitleTag, isItemClass, isItemLayout, jsonEncode
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
H_VALID = ("H0", "H1", "H2", "H3", "H4")
|
||||||
|
H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
|
||||||
|
|
||||||
|
|
||||||
class NWIndex():
|
class NWIndex():
|
||||||
|
|
||||||
H_VALID = ("H0", "H1", "H2", "H3", "H4")
|
|
||||||
H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
|
|
||||||
|
|
||||||
def __init__(self, theProject):
|
def __init__(self, theProject):
|
||||||
|
|
||||||
# Internal
|
# Internal
|
||||||
@@ -54,8 +56,7 @@ class NWIndex():
|
|||||||
# Indices
|
# Indices
|
||||||
self._tagIndex = {}
|
self._tagIndex = {}
|
||||||
self._refIndex = {}
|
self._refIndex = {}
|
||||||
self._novelIndex = {}
|
self._fileIndex = {}
|
||||||
self._noteIndex = {}
|
|
||||||
self._textCounts = {}
|
self._textCounts = {}
|
||||||
|
|
||||||
# TimeStamps
|
# TimeStamps
|
||||||
@@ -74,8 +75,7 @@ class NWIndex():
|
|||||||
"""
|
"""
|
||||||
self._tagIndex = {}
|
self._tagIndex = {}
|
||||||
self._refIndex = {}
|
self._refIndex = {}
|
||||||
self._novelIndex = {}
|
self._fileIndex = {}
|
||||||
self._noteIndex = {}
|
|
||||||
self._textCounts = {}
|
self._textCounts = {}
|
||||||
self._timeNovel = 0
|
self._timeNovel = 0
|
||||||
self._timeNotes = 0
|
self._timeNotes = 0
|
||||||
@@ -96,8 +96,7 @@ class NWIndex():
|
|||||||
self._tagIndex.pop(tTag, None)
|
self._tagIndex.pop(tTag, None)
|
||||||
|
|
||||||
self._refIndex.pop(tHandle, None)
|
self._refIndex.pop(tHandle, None)
|
||||||
self._novelIndex.pop(tHandle, None)
|
self._fileIndex.pop(tHandle, None)
|
||||||
self._noteIndex.pop(tHandle, None)
|
|
||||||
self._textCounts.pop(tHandle, None)
|
self._textCounts.pop(tHandle, None)
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -146,12 +145,14 @@ class NWIndex():
|
|||||||
"""
|
"""
|
||||||
theData = {}
|
theData = {}
|
||||||
indexFile = os.path.join(self.theProject.projMeta, nwFiles.INDEX_FILE)
|
indexFile = os.path.join(self.theProject.projMeta, nwFiles.INDEX_FILE)
|
||||||
|
tStart = time()
|
||||||
|
|
||||||
if os.path.isfile(indexFile):
|
if os.path.isfile(indexFile):
|
||||||
logger.debug("Loading index file")
|
logger.debug("Loading index file")
|
||||||
try:
|
try:
|
||||||
with open(indexFile, mode="r", encoding="utf-8") as inFile:
|
with open(indexFile, mode="r", encoding="utf-8") as inFile:
|
||||||
theData = json.load(inFile)
|
theData = json.load(inFile)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error("Failed to load index file")
|
logger.error("Failed to load index file")
|
||||||
nw.logException()
|
nw.logException()
|
||||||
@@ -160,8 +161,7 @@ class NWIndex():
|
|||||||
|
|
||||||
self._tagIndex = theData.get("tagIndex", {})
|
self._tagIndex = theData.get("tagIndex", {})
|
||||||
self._refIndex = theData.get("refIndex", {})
|
self._refIndex = theData.get("refIndex", {})
|
||||||
self._novelIndex = theData.get("novelIndex", {})
|
self._fileIndex = theData.get("fileIndex", {})
|
||||||
self._noteIndex = theData.get("noteIndex", {})
|
|
||||||
self._textCounts = theData.get("textCounts", {})
|
self._textCounts = theData.get("textCounts", {})
|
||||||
|
|
||||||
nowTime = round(time())
|
nowTime = round(time())
|
||||||
@@ -169,6 +169,8 @@ class NWIndex():
|
|||||||
self._timeNotes = nowTime
|
self._timeNotes = nowTime
|
||||||
self._timeIndex = nowTime
|
self._timeIndex = nowTime
|
||||||
|
|
||||||
|
logger.verbose("Index loaded in %.3f ms", (time() - tStart)*1000)
|
||||||
|
|
||||||
self.checkIndex()
|
self.checkIndex()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -179,21 +181,24 @@ class NWIndex():
|
|||||||
"""
|
"""
|
||||||
logger.debug("Saving index file")
|
logger.debug("Saving index file")
|
||||||
indexFile = os.path.join(self.theProject.projMeta, nwFiles.INDEX_FILE)
|
indexFile = os.path.join(self.theProject.projMeta, nwFiles.INDEX_FILE)
|
||||||
|
tStart = time()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(indexFile, mode="w+", encoding="utf-8") as outFile:
|
with open(indexFile, mode="w+", encoding="utf-8") as outFile:
|
||||||
json.dump({
|
outFile.write("{\n")
|
||||||
"tagIndex": self._tagIndex,
|
outFile.write(f'"tagIndex": {jsonEncode(self._tagIndex, nmax=1)},\n')
|
||||||
"refIndex": self._refIndex,
|
outFile.write(f'"refIndex": {jsonEncode(self._refIndex, nmax=2)},\n')
|
||||||
"novelIndex": self._novelIndex,
|
outFile.write(f'"fileIndex": {jsonEncode(self._fileIndex, nmax=2)},\n')
|
||||||
"noteIndex": self._noteIndex,
|
outFile.write(f'"textCounts": {jsonEncode(self._textCounts, nmax=1)}\n')
|
||||||
"textCounts": self._textCounts,
|
outFile.write("}\n")
|
||||||
}, outFile, indent=2)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error("Failed to save index file")
|
logger.error("Failed to save index file")
|
||||||
nw.logException()
|
nw.logException()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
logger.verbose("Index saved in %.3f ms", (time() - tStart)*1000)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def checkIndex(self):
|
def checkIndex(self):
|
||||||
@@ -206,8 +211,7 @@ class NWIndex():
|
|||||||
try:
|
try:
|
||||||
self._checkTagIndex()
|
self._checkTagIndex()
|
||||||
self._checkRefIndex()
|
self._checkRefIndex()
|
||||||
self._checkNovelNoteIndex("novelIndex")
|
self._checkFileIndex()
|
||||||
self._checkNovelNoteIndex("noteIndex")
|
|
||||||
self._checkTextCounts()
|
self._checkTextCounts()
|
||||||
self.indexBroken = False
|
self.indexBroken = False
|
||||||
|
|
||||||
@@ -216,8 +220,7 @@ class NWIndex():
|
|||||||
nw.logException()
|
nw.logException()
|
||||||
self.indexBroken = True
|
self.indexBroken = True
|
||||||
|
|
||||||
tEnd = time()
|
logger.verbose("Index check took %.3f ms", (time() - tStart)*1000)
|
||||||
logger.debug("Index check took %.3f ms", (tEnd - tStart)*1000)
|
|
||||||
logger.debug("Index check complete")
|
logger.debug("Index check complete")
|
||||||
|
|
||||||
if self.indexBroken:
|
if self.indexBroken:
|
||||||
@@ -268,21 +271,9 @@ class NWIndex():
|
|||||||
|
|
||||||
logger.debug("Indexing item with handle '%s'", tHandle)
|
logger.debug("Indexing item with handle '%s'", tHandle)
|
||||||
|
|
||||||
# Check file type, and reset its old index
|
# Delete or reset old entries for the file
|
||||||
# Also add a default entry T000000 in case the file has no title
|
self._refIndex.pop(tHandle, None)
|
||||||
self._refIndex[tHandle] = {}
|
self._fileIndex[tHandle] = {}
|
||||||
self._refIndex[tHandle]["T000000"] = {
|
|
||||||
"tags": [],
|
|
||||||
"updated": round(time()),
|
|
||||||
}
|
|
||||||
if itemLayout == nwItemLayout.NOTE:
|
|
||||||
self._novelIndex.pop(tHandle, None)
|
|
||||||
self._noteIndex[tHandle] = {}
|
|
||||||
isNovel = False
|
|
||||||
else:
|
|
||||||
self._novelIndex[tHandle] = {}
|
|
||||||
self._noteIndex.pop(tHandle, None)
|
|
||||||
isNovel = True
|
|
||||||
|
|
||||||
# Also clear references to file in tag index
|
# Also clear references to file in tag index
|
||||||
clearTags = []
|
clearTags = []
|
||||||
@@ -292,6 +283,7 @@ class NWIndex():
|
|||||||
for aTag in clearTags:
|
for aTag in clearTags:
|
||||||
self._tagIndex.pop(aTag)
|
self._tagIndex.pop(aTag)
|
||||||
|
|
||||||
|
# Scan the text content
|
||||||
nLine = 0
|
nLine = 0
|
||||||
nTitle = 0
|
nTitle = 0
|
||||||
theLines = theText.splitlines()
|
theLines = theText.splitlines()
|
||||||
@@ -302,11 +294,11 @@ class NWIndex():
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if aLine.startswith("#"):
|
if aLine.startswith("#"):
|
||||||
isTitle = self._indexTitle(tHandle, isNovel, aLine, nLine, itemLayout)
|
isTitle = self._indexTitle(tHandle, aLine, nLine, itemLayout)
|
||||||
if isTitle and nLine > 0:
|
if isTitle and nLine > 0:
|
||||||
if nTitle > 0:
|
if nTitle > 0:
|
||||||
lastText = "\n".join(theLines[nTitle-1:nLine-1])
|
lastText = "\n".join(theLines[nTitle-1:nLine-1])
|
||||||
self._indexWordCounts(tHandle, isNovel, lastText, nTitle)
|
self._indexWordCounts(tHandle, lastText, nTitle)
|
||||||
nTitle = nLine
|
nTitle = nLine
|
||||||
|
|
||||||
elif aLine.startswith("@"):
|
elif aLine.startswith("@"):
|
||||||
@@ -320,25 +312,25 @@ class NWIndex():
|
|||||||
cLen = len(toCheck)
|
cLen = len(toCheck)
|
||||||
cOff = tLen - cLen
|
cOff = tLen - cLen
|
||||||
if synTag == "synopsis:":
|
if synTag == "synopsis:":
|
||||||
self._indexSynopsis(tHandle, isNovel, aLine[cOff+9:].strip(), nTitle)
|
self._indexSynopsis(tHandle, aLine[cOff+9:].strip(), nTitle)
|
||||||
|
|
||||||
# Count words for remaining text after last heading
|
# Count words for remaining text after last heading
|
||||||
if nTitle > 0:
|
if nTitle > 0:
|
||||||
lastText = "\n".join(theLines[nTitle-1:])
|
lastText = "\n".join(theLines[nTitle-1:])
|
||||||
self._indexWordCounts(tHandle, isNovel, lastText, nTitle)
|
self._indexWordCounts(tHandle, lastText, nTitle)
|
||||||
|
|
||||||
# Index page with no titles and references
|
# Index page with no titles and references
|
||||||
if nTitle == 0:
|
if nTitle == 0:
|
||||||
self._indexPage(tHandle, isNovel, itemLayout)
|
self._indexPage(tHandle, itemLayout)
|
||||||
self._indexWordCounts(tHandle, isNovel, theText, nTitle)
|
self._indexWordCounts(tHandle, theText, nTitle)
|
||||||
|
|
||||||
# Update timestamps for index changes
|
# Update timestamps for index changes
|
||||||
nowTime = round(time())
|
nowTime = round(time())
|
||||||
self._timeIndex = nowTime
|
self._timeIndex = nowTime
|
||||||
if isNovel:
|
if itemLayout == nwItemLayout.NOTE:
|
||||||
self._timeNovel = nowTime
|
|
||||||
else:
|
|
||||||
self._timeNotes = nowTime
|
self._timeNotes = nowTime
|
||||||
|
else:
|
||||||
|
self._timeNovel = nowTime
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -346,7 +338,7 @@ class NWIndex():
|
|||||||
# Internal Indexers
|
# Internal Indexers
|
||||||
##
|
##
|
||||||
|
|
||||||
def _indexTitle(self, tHandle, isNovel, aLine, nLine, itemLayout):
|
def _indexTitle(self, tHandle, aLine, nLine, itemLayout):
|
||||||
"""Save information about the title and its location in the
|
"""Save information about the title and its location in the
|
||||||
file to the index.
|
file to the index.
|
||||||
"""
|
"""
|
||||||
@@ -366,89 +358,52 @@ class NWIndex():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
sTitle = "T%06d" % nLine
|
sTitle = "T%06d" % nLine
|
||||||
self._refIndex[tHandle][sTitle] = {
|
self._fileIndex[tHandle][sTitle] = {
|
||||||
"tags": [],
|
|
||||||
"updated": round(time()),
|
|
||||||
}
|
|
||||||
theData = {
|
|
||||||
"level": hDepth,
|
"level": hDepth,
|
||||||
"title": hText,
|
"title": hText,
|
||||||
"layout": itemLayout.name,
|
"layout": itemLayout.name,
|
||||||
"synopsis": "",
|
|
||||||
"cCount": 0,
|
"cCount": 0,
|
||||||
"wCount": 0,
|
"wCount": 0,
|
||||||
"pCount": 0,
|
"pCount": 0,
|
||||||
"updated": round(time()),
|
"synopsis": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
if hText != "":
|
|
||||||
if isNovel:
|
|
||||||
if tHandle in self._novelIndex:
|
|
||||||
self._novelIndex[tHandle][sTitle] = theData
|
|
||||||
else:
|
|
||||||
if tHandle in self._noteIndex:
|
|
||||||
self._noteIndex[tHandle][sTitle] = theData
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _indexPage(self, tHandle, isNovel, itemLayout):
|
def _indexPage(self, tHandle, itemLayout):
|
||||||
"""Index a page with no title.
|
"""Index a page with no title.
|
||||||
"""
|
"""
|
||||||
theData = {
|
self._fileIndex[tHandle]["T000000"] = {
|
||||||
"level": "H0",
|
"level": "H0",
|
||||||
"title": "Untitled Page",
|
"title": "",
|
||||||
"layout": itemLayout.name,
|
"layout": itemLayout.name,
|
||||||
"synopsis": "",
|
|
||||||
"cCount": 0,
|
"cCount": 0,
|
||||||
"wCount": 0,
|
"wCount": 0,
|
||||||
"pCount": 0,
|
"pCount": 0,
|
||||||
"updated": round(time()),
|
"synopsis": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
if isNovel:
|
|
||||||
if tHandle in self._novelIndex:
|
|
||||||
self._novelIndex[tHandle]["T000000"] = theData
|
|
||||||
else:
|
|
||||||
if tHandle in self._noteIndex:
|
|
||||||
self._noteIndex[tHandle]["T000000"] = theData
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def _indexWordCounts(self, tHandle, isNovel, theText, nTitle):
|
def _indexWordCounts(self, tHandle, theText, nTitle):
|
||||||
"""Count text stats and save the counts to the index.
|
"""Count text stats and save the counts to the index.
|
||||||
"""
|
"""
|
||||||
cC, wC, pC = countWords(theText)
|
cC, wC, pC = countWords(theText)
|
||||||
sTitle = "T%06d" % nTitle
|
sTitle = "T%06d" % nTitle
|
||||||
if isNovel:
|
if tHandle in self._fileIndex:
|
||||||
if tHandle in self._novelIndex:
|
if sTitle in self._fileIndex[tHandle]:
|
||||||
if sTitle in self._novelIndex[tHandle]:
|
self._fileIndex[tHandle][sTitle]["cCount"] = cC
|
||||||
self._novelIndex[tHandle][sTitle]["cCount"] = cC
|
self._fileIndex[tHandle][sTitle]["wCount"] = wC
|
||||||
self._novelIndex[tHandle][sTitle]["wCount"] = wC
|
self._fileIndex[tHandle][sTitle]["pCount"] = pC
|
||||||
self._novelIndex[tHandle][sTitle]["pCount"] = pC
|
|
||||||
self._novelIndex[tHandle][sTitle]["updated"] = round(time())
|
|
||||||
else:
|
|
||||||
if tHandle in self._noteIndex:
|
|
||||||
if sTitle in self._noteIndex[tHandle]:
|
|
||||||
self._noteIndex[tHandle][sTitle]["cCount"] = cC
|
|
||||||
self._noteIndex[tHandle][sTitle]["wCount"] = wC
|
|
||||||
self._noteIndex[tHandle][sTitle]["pCount"] = pC
|
|
||||||
self._noteIndex[tHandle][sTitle]["updated"] = round(time())
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def _indexSynopsis(self, tHandle, isNovel, theText, nTitle):
|
def _indexSynopsis(self, tHandle, theText, nTitle):
|
||||||
"""Save the synopsis to the index.
|
"""Save the synopsis to the index.
|
||||||
"""
|
"""
|
||||||
sTitle = "T%06d" % nTitle
|
sTitle = "T%06d" % nTitle
|
||||||
if isNovel:
|
if tHandle in self._fileIndex:
|
||||||
if tHandle in self._novelIndex:
|
if sTitle in self._fileIndex[tHandle]:
|
||||||
if sTitle in self._novelIndex[tHandle]:
|
self._fileIndex[tHandle][sTitle]["synopsis"] = theText
|
||||||
self._novelIndex[tHandle][sTitle]["synopsis"] = theText
|
|
||||||
self._novelIndex[tHandle][sTitle]["updated"] = round(time())
|
|
||||||
else:
|
|
||||||
if tHandle in self._noteIndex:
|
|
||||||
if sTitle in self._noteIndex[tHandle]:
|
|
||||||
self._noteIndex[tHandle][sTitle]["synopsis"] = theText
|
|
||||||
self._noteIndex[tHandle][sTitle]["updated"] = round(time())
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def _indexKeyword(self, tHandle, aLine, nLine, nTitle, itemClass):
|
def _indexKeyword(self, tHandle, aLine, nLine, nTitle, itemClass):
|
||||||
@@ -468,9 +423,13 @@ class NWIndex():
|
|||||||
if theBits[0] == nwKeyWords.TAG_KEY:
|
if theBits[0] == nwKeyWords.TAG_KEY:
|
||||||
self._tagIndex[theBits[1]] = [nLine, tHandle, itemClass.name, sTitle]
|
self._tagIndex[theBits[1]] = [nLine, tHandle, itemClass.name, sTitle]
|
||||||
|
|
||||||
elif sTitle in self._refIndex[tHandle]:
|
else:
|
||||||
|
if tHandle not in self._refIndex:
|
||||||
|
self._refIndex[tHandle] = {}
|
||||||
|
if sTitle not in self._refIndex[tHandle]:
|
||||||
|
self._refIndex[tHandle][sTitle] = []
|
||||||
for aVal in theBits[1:]:
|
for aVal in theBits[1:]:
|
||||||
self._refIndex[tHandle][sTitle]["tags"].append([nLine, theBits[0], aVal])
|
self._refIndex[tHandle][sTitle].append([nLine, theBits[0], aVal])
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -530,23 +489,19 @@ class NWIndex():
|
|||||||
if not isGood[0] or nBits == 1:
|
if not isGood[0] or nBits == 1:
|
||||||
return isGood
|
return isGood
|
||||||
|
|
||||||
# If we have a tag, only the first value is accepted, the rest
|
# For a tag, only the first value is accepted, the rest are ignored
|
||||||
# is ignored
|
|
||||||
if theBits[0] == nwKeyWords.TAG_KEY and nBits > 1:
|
if theBits[0] == nwKeyWords.TAG_KEY and nBits > 1:
|
||||||
isGood[0] = True
|
|
||||||
if theBits[1] in self._tagIndex:
|
if theBits[1] in self._tagIndex:
|
||||||
if self._tagIndex[theBits[1]][1] == tItem.itemHandle:
|
isGood[1] = self._tagIndex[theBits[1]][1] == tItem.itemHandle
|
||||||
isGood[1] = True
|
|
||||||
else:
|
|
||||||
isGood[1] = False
|
|
||||||
else:
|
else:
|
||||||
isGood[1] = True
|
isGood[1] = True
|
||||||
return isGood
|
return isGood
|
||||||
|
|
||||||
# If we're still here, we better check that the references exist
|
# If we're still here, we check that the references exist
|
||||||
|
theKey = nwKeyWords.KEY_CLASS[theBits[0]].name
|
||||||
for n in range(1, nBits):
|
for n in range(1, nBits):
|
||||||
if theBits[n] in self._tagIndex:
|
if theBits[n] in self._tagIndex:
|
||||||
isGood[n] = nwKeyWords.KEY_CLASS[theBits[0]].name == self._tagIndex[theBits[n]][2]
|
isGood[n] = theKey == self._tagIndex[theBits[n]][2]
|
||||||
|
|
||||||
return isGood
|
return isGood
|
||||||
|
|
||||||
@@ -560,17 +515,17 @@ class NWIndex():
|
|||||||
files, but skipping all note files.
|
files, but skipping all note files.
|
||||||
"""
|
"""
|
||||||
for tHandle in self._listNovelHandles(skipExcluded):
|
for tHandle in self._listNovelHandles(skipExcluded):
|
||||||
for sTitle in sorted(self._novelIndex[tHandle]):
|
for sTitle in sorted(self._fileIndex[tHandle]):
|
||||||
tKey = "%s:%s" % (tHandle, sTitle)
|
tKey = "%s:%s" % (tHandle, sTitle)
|
||||||
yield tKey, tHandle, sTitle, self._novelIndex[tHandle][sTitle]
|
yield tKey, tHandle, sTitle, self._fileIndex[tHandle][sTitle]
|
||||||
|
|
||||||
def getNovelWordCount(self, skipExcluded=True):
|
def getNovelWordCount(self, skipExcluded=True):
|
||||||
"""Count the number of words in the novel project.
|
"""Count the number of words in the novel project.
|
||||||
"""
|
"""
|
||||||
wCount = 0
|
wCount = 0
|
||||||
for tHandle in self._listNovelHandles(skipExcluded):
|
for tHandle in self._listNovelHandles(skipExcluded):
|
||||||
for sTitle in self._novelIndex[tHandle]:
|
for sTitle in self._fileIndex[tHandle]:
|
||||||
wCount += self._novelIndex[tHandle][sTitle]["wCount"]
|
wCount += self._fileIndex[tHandle][sTitle]["wCount"]
|
||||||
|
|
||||||
return wCount
|
return wCount
|
||||||
|
|
||||||
@@ -579,9 +534,9 @@ class NWIndex():
|
|||||||
"""
|
"""
|
||||||
hCount = [0, 0, 0, 0, 0]
|
hCount = [0, 0, 0, 0, 0]
|
||||||
for tHandle in self._listNovelHandles(skipExcluded):
|
for tHandle in self._listNovelHandles(skipExcluded):
|
||||||
for sTitle in self._novelIndex[tHandle]:
|
for sTitle in self._fileIndex[tHandle]:
|
||||||
theData = self._novelIndex[tHandle][sTitle]
|
theData = self._fileIndex[tHandle][sTitle]
|
||||||
iLevel = self.H_LEVEL.get(theData["level"], 0)
|
iLevel = H_LEVEL.get(theData["level"], 0)
|
||||||
hCount[iLevel] += 1
|
hCount[iLevel] += 1
|
||||||
|
|
||||||
return hCount
|
return hCount
|
||||||
@@ -590,9 +545,7 @@ class NWIndex():
|
|||||||
"""Get all header word counts for a specific handle.
|
"""Get all header word counts for a specific handle.
|
||||||
"""
|
"""
|
||||||
theCounts = []
|
theCounts = []
|
||||||
hRecord = self._novelIndex.get(tHandle, None)
|
hRecord = self._fileIndex.get(tHandle, None)
|
||||||
if hRecord is None:
|
|
||||||
hRecord = self._noteIndex.get(tHandle, None)
|
|
||||||
if hRecord is None:
|
if hRecord is None:
|
||||||
return theCounts
|
return theCounts
|
||||||
|
|
||||||
@@ -605,9 +558,7 @@ class NWIndex():
|
|||||||
"""Get all headers for a specific handle.
|
"""Get all headers for a specific handle.
|
||||||
"""
|
"""
|
||||||
theHeaders = []
|
theHeaders = []
|
||||||
hRecord = self._novelIndex.get(tHandle, None)
|
hRecord = self._fileIndex.get(tHandle, None)
|
||||||
if hRecord is None:
|
|
||||||
hRecord = self._noteIndex.get(tHandle, None)
|
|
||||||
if hRecord is None:
|
if hRecord is None:
|
||||||
return theHeaders
|
return theHeaders
|
||||||
|
|
||||||
@@ -623,10 +574,10 @@ class NWIndex():
|
|||||||
tData = {}
|
tData = {}
|
||||||
pKey = None
|
pKey = None
|
||||||
for tHandle in self._listNovelHandles(skipExcluded):
|
for tHandle in self._listNovelHandles(skipExcluded):
|
||||||
for sTitle in sorted(self._novelIndex[tHandle]):
|
for sTitle in sorted(self._fileIndex[tHandle]):
|
||||||
tKey = "%s:%s" % (tHandle, sTitle)
|
tKey = "%s:%s" % (tHandle, sTitle)
|
||||||
theData = self._novelIndex[tHandle][sTitle]
|
theData = self._fileIndex[tHandle][sTitle]
|
||||||
iLevel = self.H_LEVEL.get(theData["level"], 0)
|
iLevel = H_LEVEL.get(theData["level"], 0)
|
||||||
if iLevel > maxDepth:
|
if iLevel > maxDepth:
|
||||||
if pKey in tData:
|
if pKey in tData:
|
||||||
theData["wCount"]
|
theData["wCount"]
|
||||||
@@ -665,16 +616,11 @@ class NWIndex():
|
|||||||
wC = self._textCounts[tHandle][1]
|
wC = self._textCounts[tHandle][1]
|
||||||
pC = self._textCounts[tHandle][2]
|
pC = self._textCounts[tHandle][2]
|
||||||
else:
|
else:
|
||||||
if tHandle in self._novelIndex:
|
if tHandle in self._fileIndex:
|
||||||
if sTitle in self._novelIndex[tHandle]:
|
if sTitle in self._fileIndex[tHandle]:
|
||||||
cC = self._novelIndex[tHandle][sTitle]["cCount"]
|
cC = self._fileIndex[tHandle][sTitle]["cCount"]
|
||||||
wC = self._novelIndex[tHandle][sTitle]["wCount"]
|
wC = self._fileIndex[tHandle][sTitle]["wCount"]
|
||||||
pC = self._novelIndex[tHandle][sTitle]["pCount"]
|
pC = self._fileIndex[tHandle][sTitle]["pCount"]
|
||||||
elif tHandle in self._noteIndex:
|
|
||||||
if sTitle in self._noteIndex[tHandle]:
|
|
||||||
cC = self._noteIndex[tHandle][sTitle]["cCount"]
|
|
||||||
wC = self._noteIndex[tHandle][sTitle]["wCount"]
|
|
||||||
pC = self._noteIndex[tHandle][sTitle]["pCount"]
|
|
||||||
|
|
||||||
return cC, wC, pC
|
return cC, wC, pC
|
||||||
|
|
||||||
@@ -690,7 +636,7 @@ class NWIndex():
|
|||||||
return theRefs
|
return theRefs
|
||||||
|
|
||||||
for refTitle in self._refIndex[tHandle]:
|
for refTitle in self._refIndex[tHandle]:
|
||||||
for aTag in self._refIndex[tHandle][refTitle].get("tags", []):
|
for aTag in self._refIndex[tHandle][refTitle]:
|
||||||
if len(aTag) == 3 and (sTitle is None or sTitle == refTitle):
|
if len(aTag) == 3 and (sTitle is None or sTitle == refTitle):
|
||||||
if aTag[1] in theRefs:
|
if aTag[1] in theRefs:
|
||||||
theRefs[aTag[1]].append(aTag[2])
|
theRefs[aTag[1]].append(aTag[2])
|
||||||
@@ -700,9 +646,9 @@ class NWIndex():
|
|||||||
def getNovelData(self, tHandle, sTitle):
|
def getNovelData(self, tHandle, sTitle):
|
||||||
"""Return the novel data of a given handle and title.
|
"""Return the novel data of a given handle and title.
|
||||||
"""
|
"""
|
||||||
if tHandle in self._novelIndex:
|
if tHandle in self._fileIndex:
|
||||||
if sTitle in self._novelIndex[tHandle]:
|
if sTitle in self._fileIndex[tHandle]:
|
||||||
return self._novelIndex[tHandle][sTitle]
|
return self._fileIndex[tHandle][sTitle]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getBackReferenceList(self, tHandle):
|
def getBackReferenceList(self, tHandle):
|
||||||
@@ -721,7 +667,7 @@ class NWIndex():
|
|||||||
if theTags:
|
if theTags:
|
||||||
for tHandle in self._refIndex:
|
for tHandle in self._refIndex:
|
||||||
for sTitle in self._refIndex[tHandle]:
|
for sTitle in self._refIndex[tHandle]:
|
||||||
for _, _, tTag in self._refIndex[tHandle][sTitle]["tags"]:
|
for _, _, tTag in self._refIndex[tHandle][sTitle]:
|
||||||
if tTag in theTags and tHandle not in theRefs:
|
if tTag in theTags and tHandle not in theRefs:
|
||||||
theRefs[tHandle] = sTitle
|
theRefs[tHandle] = sTitle
|
||||||
|
|
||||||
@@ -749,7 +695,9 @@ class NWIndex():
|
|||||||
continue
|
continue
|
||||||
if not tItem.isExported and skipExcluded:
|
if not tItem.isExported and skipExcluded:
|
||||||
continue
|
continue
|
||||||
if tItem.itemHandle in self._novelIndex:
|
if tItem.itemLayout == nwItemLayout.NOTE:
|
||||||
|
continue
|
||||||
|
if tItem.itemHandle in self._fileIndex:
|
||||||
theHandles.append(tItem.itemHandle)
|
theHandles.append(tItem.itemHandle)
|
||||||
|
|
||||||
return theHandles
|
return theHandles
|
||||||
@@ -760,7 +708,7 @@ class NWIndex():
|
|||||||
|
|
||||||
def _checkTagIndex(self):
|
def _checkTagIndex(self):
|
||||||
"""Scan the tag index for errors.
|
"""Scan the tag index for errors.
|
||||||
Waring: This function raises exceptions.
|
Warning: This function raises exceptions.
|
||||||
"""
|
"""
|
||||||
for tTag in self._tagIndex:
|
for tTag in self._tagIndex:
|
||||||
if not isinstance(tTag, str):
|
if not isinstance(tTag, str):
|
||||||
@@ -782,7 +730,7 @@ class NWIndex():
|
|||||||
|
|
||||||
def _checkRefIndex(self):
|
def _checkRefIndex(self):
|
||||||
"""Scan the reference index for errors.
|
"""Scan the reference index for errors.
|
||||||
Waring: This function raises exceptions.
|
Warning: This function raises exceptions.
|
||||||
"""
|
"""
|
||||||
for tHandle in self._refIndex:
|
for tHandle in self._refIndex:
|
||||||
if not isHandle(tHandle):
|
if not isHandle(tHandle):
|
||||||
@@ -794,88 +742,70 @@ class NWIndex():
|
|||||||
raise KeyError("refIndex[a] key is not a title tag")
|
raise KeyError("refIndex[a] key is not a title tag")
|
||||||
|
|
||||||
sEntry = hEntry[sTitle]
|
sEntry = hEntry[sTitle]
|
||||||
if "tags" not in sEntry:
|
for tEntry in sEntry:
|
||||||
raise KeyError("refIndex[a][b] has no 'tag' key")
|
|
||||||
for tEntry in sEntry["tags"]:
|
|
||||||
if len(tEntry) != 3:
|
if len(tEntry) != 3:
|
||||||
raise IndexError("refIndex[a][b][tags][i] expected 3 values")
|
raise IndexError("refIndex[a][b][i] expected 3 values")
|
||||||
if not isinstance(tEntry[0], int):
|
if not isinstance(tEntry[0], int):
|
||||||
raise ValueError("refIndex[a][b][tags][i][0] is not an integer")
|
raise ValueError("refIndex[a][b][i][0] is not an integer")
|
||||||
if not tEntry[1] in nwKeyWords.VALID_KEYS:
|
if not tEntry[1] in nwKeyWords.VALID_KEYS:
|
||||||
raise ValueError("refIndex[a][b][tags][i][1] is not a keyword")
|
raise ValueError("refIndex[a][b][i][1] is not a keyword")
|
||||||
if not isinstance(tEntry[2], str):
|
if not isinstance(tEntry[2], str):
|
||||||
raise ValueError("refIndex[a][b][tags][i][2] is not a string")
|
raise ValueError("refIndex[a][b][i][2] is not a string")
|
||||||
|
|
||||||
if "updated" not in sEntry:
|
|
||||||
raise KeyError("refIndex[a][b] has no 'updated' key")
|
|
||||||
if not isinstance(sEntry["updated"], int):
|
|
||||||
raise ValueError("%refIndex[a][b][updated] is not an integer")
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def _checkNovelNoteIndex(self, idxName):
|
def _checkFileIndex(self):
|
||||||
"""Scan the novel or note index for errors.
|
"""Scan the file index for errors.
|
||||||
Waring: This function raises exceptions.
|
Warning: This function raises exceptions.
|
||||||
"""
|
"""
|
||||||
if idxName == "novelIndex":
|
for tHandle in self._fileIndex:
|
||||||
theIndex = self._novelIndex
|
|
||||||
elif idxName == "noteIndex":
|
|
||||||
theIndex = self._noteIndex
|
|
||||||
else:
|
|
||||||
raise IndexError("Unknown index %s" % idxName)
|
|
||||||
|
|
||||||
for tHandle in theIndex:
|
|
||||||
if not isHandle(tHandle):
|
if not isHandle(tHandle):
|
||||||
raise KeyError("%s key is not a handle" % idxName)
|
raise KeyError("fileIndex key is not a handle")
|
||||||
|
|
||||||
hEntry = theIndex[tHandle]
|
hEntry = self._fileIndex[tHandle]
|
||||||
for sTitle in theIndex[tHandle]:
|
for sTitle in self._fileIndex[tHandle]:
|
||||||
if not isTitleTag(sTitle):
|
if not isTitleTag(sTitle):
|
||||||
raise KeyError("%s[a] key is not a title tag" % idxName)
|
raise KeyError("fileIndex[a] key is not a title tag")
|
||||||
|
|
||||||
sEntry = hEntry[sTitle]
|
sEntry = hEntry[sTitle]
|
||||||
if len(sEntry) != 8:
|
if len(sEntry) != 7:
|
||||||
raise IndexError("%s[a][b] expected 8 values" % idxName)
|
raise IndexError("fileIndex[a][b] expected 7 values")
|
||||||
|
|
||||||
if "level" not in sEntry:
|
if "level" not in sEntry:
|
||||||
raise KeyError("%s[a][b] has no 'level' key" % idxName)
|
raise KeyError("fileIndex[a][b] has no 'level' key")
|
||||||
if "title" not in sEntry:
|
if "title" not in sEntry:
|
||||||
raise KeyError("%s[a][b] has no 'title' key" % idxName)
|
raise KeyError("fileIndex[a][b] has no 'title' key")
|
||||||
if "layout" not in sEntry:
|
if "layout" not in sEntry:
|
||||||
raise KeyError("%s[a][b] has no 'layout' key" % idxName)
|
raise KeyError("fileIndex[a][b] has no 'layout' key")
|
||||||
if "synopsis" not in sEntry:
|
|
||||||
raise KeyError("%s[a][b] has no 'synopsis' key" % idxName)
|
|
||||||
if "cCount" not in sEntry:
|
if "cCount" not in sEntry:
|
||||||
raise KeyError("%s[a][b] has no 'cCount' key" % idxName)
|
raise KeyError("fileIndex[a][b] has no 'cCount' key")
|
||||||
if "wCount" not in sEntry:
|
if "wCount" not in sEntry:
|
||||||
raise KeyError("%s[a][b] has no 'wCount' key" % idxName)
|
raise KeyError("fileIndex[a][b] has no 'wCount' key")
|
||||||
if "pCount" not in sEntry:
|
if "pCount" not in sEntry:
|
||||||
raise KeyError("%s[a][b] has no 'pCount' key" % idxName)
|
raise KeyError("fileIndex[a][b] has no 'pCount' key")
|
||||||
if "updated" not in sEntry:
|
if "synopsis" not in sEntry:
|
||||||
raise KeyError("%s[a][b] has no 'updated' key" % idxName)
|
raise KeyError("fileIndex[a][b] has no 'synopsis' key")
|
||||||
|
|
||||||
if not sEntry["level"] in self.H_VALID:
|
if not sEntry["level"] in H_VALID:
|
||||||
raise ValueError("%s[a][b][level] is not a header level" % idxName)
|
raise ValueError("fileIndex[a][b][level] is not a header level")
|
||||||
if not isinstance(sEntry["title"], str):
|
if not isinstance(sEntry["title"], str):
|
||||||
raise ValueError("%s[a][b][title] is not a string" % idxName)
|
raise ValueError("fileIndex[a][b][title] is not a string")
|
||||||
if not isItemLayout(sEntry["layout"]):
|
if not isItemLayout(sEntry["layout"]):
|
||||||
raise ValueError("%s[a][b][layout] is not an nwItemLayout" % idxName)
|
raise ValueError("fileIndex[a][b][layout] is not an nwItemLayout")
|
||||||
if not isinstance(sEntry["synopsis"], str):
|
|
||||||
raise ValueError("%s[a][b][synopsis] is not a string" % idxName)
|
|
||||||
if not isinstance(sEntry["cCount"], int):
|
if not isinstance(sEntry["cCount"], int):
|
||||||
raise ValueError("%s[a][b][cCount] is not an integer" % idxName)
|
raise ValueError("fileIndex[a][b][cCount] is not an integer")
|
||||||
if not isinstance(sEntry["wCount"], int):
|
if not isinstance(sEntry["wCount"], int):
|
||||||
raise ValueError("%s[a][b][wCount] is not an integer" % idxName)
|
raise ValueError("fileIndex[a][b][wCount] is not an integer")
|
||||||
if not isinstance(sEntry["pCount"], int):
|
if not isinstance(sEntry["pCount"], int):
|
||||||
raise ValueError("%s[a][b][pCount] is not an integer" % idxName)
|
raise ValueError("fileIndex[a][b][pCount] is not an integer")
|
||||||
if not isinstance(sEntry["updated"], int):
|
if not isinstance(sEntry["synopsis"], str):
|
||||||
raise ValueError("%s[a][b][updated] is not an integer" % idxName)
|
raise ValueError("fileIndex[a][b][synopsis] is not a string")
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def _checkTextCounts(self):
|
def _checkTextCounts(self):
|
||||||
"""Scan the text counts index for errors.
|
"""Scan the text counts index for errors.
|
||||||
Waring: This function raises exceptions.
|
Warning: This function raises exceptions.
|
||||||
"""
|
"""
|
||||||
for tHandle in self._textCounts:
|
for tHandle in self._textCounts:
|
||||||
if not isHandle(tHandle):
|
if not isHandle(tHandle):
|
||||||
|
|||||||
@@ -443,6 +443,9 @@ class GuiProjectDetailsContents(QWidget):
|
|||||||
progPage = f"{cPage:n}"
|
progPage = f"{cPage:n}"
|
||||||
progText = f"{pgProg:.1f}{nwUnicode.U_THSP}%"
|
progText = f"{pgProg:.1f}{nwUnicode.U_THSP}%"
|
||||||
|
|
||||||
|
if tTitle.strip() == "":
|
||||||
|
tTitle = self.tr("Untitled")
|
||||||
|
|
||||||
newItem.setIcon(self.C_TITLE, self.theTheme.getIcon("doc_h%d" % tLevel))
|
newItem.setIcon(self.C_TITLE, self.theTheme.getIcon("doc_h%d" % tLevel))
|
||||||
newItem.setText(self.C_TITLE, tTitle)
|
newItem.setText(self.C_TITLE, tTitle)
|
||||||
newItem.setText(self.C_WORDS, f"{wCount:n}")
|
newItem.setText(self.C_WORDS, f"{wCount:n}")
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
# Nobody Owens
|
# Nobody Owens
|
||||||
|
|
||||||
@tag: Bod
|
@tag: Bod
|
||||||
|
@plot: Main
|
||||||
|
|
||||||
Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.
|
Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.
|
||||||
|
|
||||||
|
|||||||
@@ -1,571 +1,99 @@
|
|||||||
{
|
{
|
||||||
"tagIndex": {
|
"tagIndex": {
|
||||||
"Bod": [
|
"Bod": [3, "4c4f28287af27", "CHARACTER", "T000001"],
|
||||||
3,
|
"Main": [3, "2426c6f0ca922", "PLOT", "T000001"],
|
||||||
"4c4f28287af27",
|
"Europe": [3, "04468803b92e1", "WORLD", "T000001"]
|
||||||
"CHARACTER",
|
},
|
||||||
"T000001"
|
"refIndex": {
|
||||||
],
|
"fb609cd8319dc": {
|
||||||
"Main": [
|
"T000001": [[3, "@pov", "Bod"], [4, "@plot", "Main"], [5, "@location", "Europe"]]
|
||||||
3,
|
|
||||||
"2426c6f0ca922",
|
|
||||||
"PLOT",
|
|
||||||
"T000001"
|
|
||||||
],
|
|
||||||
"Europe": [
|
|
||||||
3,
|
|
||||||
"04468803b92e1",
|
|
||||||
"WORLD",
|
|
||||||
"T000001"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"refIndex": {
|
"88243afbe5ed8": {
|
||||||
"7a992350f3eb6": {
|
"T000001": [[3, "@pov", "Bod"], [4, "@plot", "Main"], [5, "@location", "Europe"]]
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"8c58a65414c23": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"88d59a277361b": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"db7e733775d4d": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"fb609cd8319dc": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [
|
|
||||||
[
|
|
||||||
3,
|
|
||||||
"@pov",
|
|
||||||
"Bod"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
4,
|
|
||||||
"@plot",
|
|
||||||
"Main"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
"@location",
|
|
||||||
"Europe"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"88243afbe5ed8": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [
|
|
||||||
[
|
|
||||||
3,
|
|
||||||
"@pov",
|
|
||||||
"Bod"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
4,
|
|
||||||
"@plot",
|
|
||||||
"Main"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
"@location",
|
|
||||||
"Europe"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000013": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"f96ec11c6a3da": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [
|
|
||||||
[
|
|
||||||
3,
|
|
||||||
"@pov",
|
|
||||||
"Bod"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
4,
|
|
||||||
"@plot",
|
|
||||||
"Main"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
"@location",
|
|
||||||
"Europe"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000015": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"846352075de7d": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"441420a886d82": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [
|
|
||||||
[
|
|
||||||
3,
|
|
||||||
"@pov",
|
|
||||||
"Bod"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
4,
|
|
||||||
"@plot",
|
|
||||||
"Main"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
"@location",
|
|
||||||
"Europe"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"eb103bc70c90c": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [
|
|
||||||
[
|
|
||||||
3,
|
|
||||||
"@pov",
|
|
||||||
"Bod"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
4,
|
|
||||||
"@plot",
|
|
||||||
"Main"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
"@location",
|
|
||||||
"Europe"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"f8c0562e50f1b": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [
|
|
||||||
[
|
|
||||||
3,
|
|
||||||
"@pov",
|
|
||||||
"Bod"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
4,
|
|
||||||
"@plot",
|
|
||||||
"Main"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
"@location",
|
|
||||||
"Europe"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"47666c91c7ccf": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [
|
|
||||||
[
|
|
||||||
3,
|
|
||||||
"@pov",
|
|
||||||
"Bod"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
4,
|
|
||||||
"@plot",
|
|
||||||
"Main"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
"@location",
|
|
||||||
"Europe"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"4c4f28287af27": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"2426c6f0ca922": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"04468803b92e1": {
|
|
||||||
"T000000": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000001": {
|
|
||||||
"tags": [],
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"novelIndex": {
|
"f96ec11c6a3da": {
|
||||||
"7a992350f3eb6": {
|
"T000001": [[3, "@pov", "Bod"], [4, "@plot", "Main"], [5, "@location", "Europe"]]
|
||||||
"T000001": {
|
|
||||||
"level": "H1",
|
|
||||||
"title": "Lorem Ipsum",
|
|
||||||
"layout": "TITLE",
|
|
||||||
"synopsis": "",
|
|
||||||
"cCount": 230,
|
|
||||||
"wCount": 40,
|
|
||||||
"pCount": 3,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"8c58a65414c23": {
|
|
||||||
"T000000": {
|
|
||||||
"level": "H0",
|
|
||||||
"title": "Untitled Page",
|
|
||||||
"layout": "PAGE",
|
|
||||||
"synopsis": "",
|
|
||||||
"cCount": 1058,
|
|
||||||
"wCount": 176,
|
|
||||||
"pCount": 2,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"88d59a277361b": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H2",
|
|
||||||
"title": "Prologue",
|
|
||||||
"layout": "UNNUMBERED",
|
|
||||||
"synopsis": "Explanation from the lipsum.com website.",
|
|
||||||
"cCount": 584,
|
|
||||||
"wCount": 92,
|
|
||||||
"pCount": 1,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"db7e733775d4d": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H1",
|
|
||||||
"title": "Act One",
|
|
||||||
"layout": "PARTITION",
|
|
||||||
"synopsis": "",
|
|
||||||
"cCount": 35,
|
|
||||||
"wCount": 6,
|
|
||||||
"pCount": 1,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"fb609cd8319dc": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H2",
|
|
||||||
"title": "Chapter One",
|
|
||||||
"layout": "CHAPTER",
|
|
||||||
"synopsis": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque at aliquam quam.",
|
|
||||||
"cCount": 419,
|
|
||||||
"wCount": 67,
|
|
||||||
"pCount": 1,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"88243afbe5ed8": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H3",
|
|
||||||
"title": "Scene One",
|
|
||||||
"layout": "SCENE",
|
|
||||||
"synopsis": "Aenean ut placerat velit. Etiam laoreet ullamcorper risus, eget lobortis enim scelerisque non. Suspendisse id maximus nunc, et mollis sapien. Curabitur vel semper sapien, non pulvinar dolor. Etiam finibus nisi vel mi molestie consectetur.",
|
|
||||||
"cCount": 1197,
|
|
||||||
"wCount": 174,
|
|
||||||
"pCount": 2,
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000013": {
|
|
||||||
"level": "H4",
|
|
||||||
"title": "Scene One, Section Two",
|
|
||||||
"layout": "SCENE",
|
|
||||||
"synopsis": "",
|
|
||||||
"cCount": 1561,
|
|
||||||
"wCount": 230,
|
|
||||||
"pCount": 2,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"f96ec11c6a3da": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H3",
|
|
||||||
"title": "Scene Two",
|
|
||||||
"layout": "SCENE",
|
|
||||||
"synopsis": "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Integer sapien nulla, dictum at lacus a, dignissim consectetur dolor. Nunc vel eleifend lacus, eu dapibus orci.",
|
|
||||||
"cCount": 2034,
|
|
||||||
"wCount": 299,
|
|
||||||
"pCount": 3,
|
|
||||||
"updated": 123
|
|
||||||
},
|
|
||||||
"T000015": {
|
|
||||||
"level": "H4",
|
|
||||||
"title": "Scene Two, Section Two",
|
|
||||||
"layout": "SCENE",
|
|
||||||
"synopsis": "",
|
|
||||||
"cCount": 2009,
|
|
||||||
"wCount": 301,
|
|
||||||
"pCount": 3,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"846352075de7d": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H2",
|
|
||||||
"title": "Why do we use it?",
|
|
||||||
"layout": "BOOK",
|
|
||||||
"synopsis": "",
|
|
||||||
"cCount": 631,
|
|
||||||
"wCount": 109,
|
|
||||||
"pCount": 3,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"441420a886d82": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H2",
|
|
||||||
"title": "Chapter Two",
|
|
||||||
"layout": "CHAPTER",
|
|
||||||
"synopsis": "Curabitur a elit posuere, varius ex et, convallis neque. Phasellus sagittis pharetra sem vitae dapibus. Curabitur varius lorem non pulvinar congue.",
|
|
||||||
"cCount": 477,
|
|
||||||
"wCount": 70,
|
|
||||||
"pCount": 1,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"eb103bc70c90c": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H3",
|
|
||||||
"title": "Scene Three",
|
|
||||||
"layout": "SCENE",
|
|
||||||
"synopsis": "Aenean ut libero ut lectus porttitor rhoncus vel et massa. Nam pretium, nibh et varius vehicula, urna metus blandit eros, euismod pharetra diam diam et libero. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.",
|
|
||||||
"cCount": 3006,
|
|
||||||
"wCount": 439,
|
|
||||||
"pCount": 4,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"f8c0562e50f1b": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H3",
|
|
||||||
"title": "Scene Four",
|
|
||||||
"layout": "SCENE",
|
|
||||||
"synopsis": "Nam tempor blandit magna laoreet aliquet. Vestibulum auctor posuere leo, ac gravida nisi rhoncus varius. Aenean posuere dolor vitae condimentum volutpat. Donec egestas volutpat risus, quis luctus justo.",
|
|
||||||
"cCount": 3839,
|
|
||||||
"wCount": 563,
|
|
||||||
"pCount": 6,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"47666c91c7ccf": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H3",
|
|
||||||
"title": "Scene Five",
|
|
||||||
"layout": "SCENE",
|
|
||||||
"synopsis": "Praesent eget est porta, dictum ante in, egestas risus. Mauris risus mauris, consequat aliquam mauris et, feugiat iaculis ipsum. Aliquam arcu ipsum, fermentum ut arcu sed, lobortis euismod sem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.",
|
|
||||||
"cCount": 3644,
|
|
||||||
"wCount": 543,
|
|
||||||
"pCount": 5,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"noteIndex": {
|
"441420a886d82": {
|
||||||
"4c4f28287af27": {
|
"T000001": [[3, "@pov", "Bod"], [4, "@plot", "Main"], [5, "@location", "Europe"]]
|
||||||
"T000001": {
|
|
||||||
"level": "H1",
|
|
||||||
"title": "Nobody Owens",
|
|
||||||
"layout": "NOTE",
|
|
||||||
"synopsis": "",
|
|
||||||
"cCount": 1864,
|
|
||||||
"wCount": 284,
|
|
||||||
"pCount": 3,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"2426c6f0ca922": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H1",
|
|
||||||
"title": "Main Plot",
|
|
||||||
"layout": "NOTE",
|
|
||||||
"synopsis": "",
|
|
||||||
"cCount": 1369,
|
|
||||||
"wCount": 195,
|
|
||||||
"pCount": 2,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"04468803b92e1": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H1",
|
|
||||||
"title": "Ancient Europe",
|
|
||||||
"layout": "NOTE",
|
|
||||||
"synopsis": "",
|
|
||||||
"cCount": 1770,
|
|
||||||
"wCount": 259,
|
|
||||||
"pCount": 3,
|
|
||||||
"updated": 123
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"textCounts": {
|
"eb103bc70c90c": {
|
||||||
"7a992350f3eb6": [
|
"T000001": [[3, "@pov", "Bod"], [4, "@plot", "Main"], [5, "@location", "Europe"]]
|
||||||
230,
|
},
|
||||||
40,
|
"f8c0562e50f1b": {
|
||||||
3
|
"T000001": [[3, "@pov", "Bod"], [4, "@plot", "Main"], [5, "@location", "Europe"]]
|
||||||
],
|
},
|
||||||
"8c58a65414c23": [
|
"47666c91c7ccf": {
|
||||||
1058,
|
"T000001": [[3, "@pov", "Bod"], [4, "@plot", "Main"], [5, "@location", "Europe"]]
|
||||||
176,
|
},
|
||||||
2
|
"4c4f28287af27": {
|
||||||
],
|
"T000001": [[4, "@plot", "Main"]]
|
||||||
"88d59a277361b": [
|
|
||||||
584,
|
|
||||||
92,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"db7e733775d4d": [
|
|
||||||
35,
|
|
||||||
6,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"fb609cd8319dc": [
|
|
||||||
419,
|
|
||||||
67,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"88243afbe5ed8": [
|
|
||||||
2758,
|
|
||||||
404,
|
|
||||||
4
|
|
||||||
],
|
|
||||||
"f96ec11c6a3da": [
|
|
||||||
4043,
|
|
||||||
600,
|
|
||||||
6
|
|
||||||
],
|
|
||||||
"846352075de7d": [
|
|
||||||
631,
|
|
||||||
109,
|
|
||||||
3
|
|
||||||
],
|
|
||||||
"441420a886d82": [
|
|
||||||
477,
|
|
||||||
70,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"eb103bc70c90c": [
|
|
||||||
3006,
|
|
||||||
439,
|
|
||||||
4
|
|
||||||
],
|
|
||||||
"f8c0562e50f1b": [
|
|
||||||
3839,
|
|
||||||
563,
|
|
||||||
6
|
|
||||||
],
|
|
||||||
"47666c91c7ccf": [
|
|
||||||
3644,
|
|
||||||
543,
|
|
||||||
5
|
|
||||||
],
|
|
||||||
"4c4f28287af27": [
|
|
||||||
1864,
|
|
||||||
284,
|
|
||||||
3
|
|
||||||
],
|
|
||||||
"2426c6f0ca922": [
|
|
||||||
1369,
|
|
||||||
195,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
"04468803b92e1": [
|
|
||||||
1770,
|
|
||||||
259,
|
|
||||||
3
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"fileIndex": {
|
||||||
|
"7a992350f3eb6": {
|
||||||
|
"T000001": {"level": "H1", "title": "Lorem Ipsum", "layout": "TITLE", "cCount": 230, "wCount": 40, "pCount": 3, "synopsis": ""}
|
||||||
|
},
|
||||||
|
"8c58a65414c23": {
|
||||||
|
"T000000": {"level": "H0", "title": "", "layout": "PAGE", "cCount": 1058, "wCount": 176, "pCount": 2, "synopsis": ""}
|
||||||
|
},
|
||||||
|
"88d59a277361b": {
|
||||||
|
"T000001": {"level": "H2", "title": "Prologue", "layout": "UNNUMBERED", "cCount": 584, "wCount": 92, "pCount": 1, "synopsis": "Explanation from the lipsum.com website."}
|
||||||
|
},
|
||||||
|
"db7e733775d4d": {
|
||||||
|
"T000001": {"level": "H1", "title": "Act One", "layout": "PARTITION", "cCount": 35, "wCount": 6, "pCount": 1, "synopsis": ""}
|
||||||
|
},
|
||||||
|
"fb609cd8319dc": {
|
||||||
|
"T000001": {"level": "H2", "title": "Chapter One", "layout": "CHAPTER", "cCount": 419, "wCount": 67, "pCount": 1, "synopsis": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque at aliquam quam."}
|
||||||
|
},
|
||||||
|
"88243afbe5ed8": {
|
||||||
|
"T000001": {"level": "H3", "title": "Scene One", "layout": "SCENE", "cCount": 1197, "wCount": 174, "pCount": 2, "synopsis": "Aenean ut placerat velit. Etiam laoreet ullamcorper risus, eget lobortis enim scelerisque non. Suspendisse id maximus nunc, et mollis sapien. Curabitur vel semper sapien, non pulvinar dolor. Etiam finibus nisi vel mi molestie consectetur."},
|
||||||
|
"T000013": {"level": "H4", "title": "Scene One, Section Two", "layout": "SCENE", "cCount": 1561, "wCount": 230, "pCount": 2, "synopsis": ""}
|
||||||
|
},
|
||||||
|
"f96ec11c6a3da": {
|
||||||
|
"T000001": {"level": "H3", "title": "Scene Two", "layout": "SCENE", "cCount": 2034, "wCount": 299, "pCount": 3, "synopsis": "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Integer sapien nulla, dictum at lacus a, dignissim consectetur dolor. Nunc vel eleifend lacus, eu dapibus orci."},
|
||||||
|
"T000015": {"level": "H4", "title": "Scene Two, Section Two", "layout": "SCENE", "cCount": 2009, "wCount": 301, "pCount": 3, "synopsis": ""}
|
||||||
|
},
|
||||||
|
"846352075de7d": {
|
||||||
|
"T000001": {"level": "H2", "title": "Why do we use it?", "layout": "BOOK", "cCount": 631, "wCount": 109, "pCount": 3, "synopsis": ""}
|
||||||
|
},
|
||||||
|
"441420a886d82": {
|
||||||
|
"T000001": {"level": "H2", "title": "Chapter Two", "layout": "CHAPTER", "cCount": 477, "wCount": 70, "pCount": 1, "synopsis": "Curabitur a elit posuere, varius ex et, convallis neque. Phasellus sagittis pharetra sem vitae dapibus. Curabitur varius lorem non pulvinar congue."}
|
||||||
|
},
|
||||||
|
"eb103bc70c90c": {
|
||||||
|
"T000001": {"level": "H3", "title": "Scene Three", "layout": "SCENE", "cCount": 3006, "wCount": 439, "pCount": 4, "synopsis": "Aenean ut libero ut lectus porttitor rhoncus vel et massa. Nam pretium, nibh et varius vehicula, urna metus blandit eros, euismod pharetra diam diam et libero. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos."}
|
||||||
|
},
|
||||||
|
"f8c0562e50f1b": {
|
||||||
|
"T000001": {"level": "H3", "title": "Scene Four", "layout": "SCENE", "cCount": 3839, "wCount": 563, "pCount": 6, "synopsis": "Nam tempor blandit magna laoreet aliquet. Vestibulum auctor posuere leo, ac gravida nisi rhoncus varius. Aenean posuere dolor vitae condimentum volutpat. Donec egestas volutpat risus, quis luctus justo."}
|
||||||
|
},
|
||||||
|
"47666c91c7ccf": {
|
||||||
|
"T000001": {"level": "H3", "title": "Scene Five", "layout": "SCENE", "cCount": 3644, "wCount": 543, "pCount": 5, "synopsis": "Praesent eget est porta, dictum ante in, egestas risus. Mauris risus mauris, consequat aliquam mauris et, feugiat iaculis ipsum. Aliquam arcu ipsum, fermentum ut arcu sed, lobortis euismod sem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus."}
|
||||||
|
},
|
||||||
|
"4c4f28287af27": {
|
||||||
|
"T000001": {"level": "H1", "title": "Nobody Owens", "layout": "NOTE", "cCount": 1864, "wCount": 284, "pCount": 3, "synopsis": ""}
|
||||||
|
},
|
||||||
|
"2426c6f0ca922": {
|
||||||
|
"T000001": {"level": "H1", "title": "Main Plot", "layout": "NOTE", "cCount": 1369, "wCount": 195, "pCount": 2, "synopsis": ""}
|
||||||
|
},
|
||||||
|
"04468803b92e1": {
|
||||||
|
"T000001": {"level": "H1", "title": "Ancient Europe", "layout": "NOTE", "cCount": 1770, "wCount": 259, "pCount": 3, "synopsis": ""}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"textCounts": {
|
||||||
|
"7a992350f3eb6": [230, 40, 3],
|
||||||
|
"8c58a65414c23": [1058, 176, 2],
|
||||||
|
"88d59a277361b": [584, 92, 1],
|
||||||
|
"db7e733775d4d": [35, 6, 1],
|
||||||
|
"fb609cd8319dc": [419, 67, 1],
|
||||||
|
"88243afbe5ed8": [2758, 404, 4],
|
||||||
|
"f96ec11c6a3da": [4043, 600, 6],
|
||||||
|
"846352075de7d": [631, 109, 3],
|
||||||
|
"441420a886d82": [477, 70, 1],
|
||||||
|
"eb103bc70c90c": [3006, 439, 4],
|
||||||
|
"f8c0562e50f1b": [3839, 563, 6],
|
||||||
|
"47666c91c7ccf": [3644, 543, 5],
|
||||||
|
"4c4f28287af27": [1864, 284, 3],
|
||||||
|
"2426c6f0ca922": [1369, 195, 2],
|
||||||
|
"04468803b92e1": [1770, 259, 3]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
|
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
|
||||||
<office:meta>
|
<office:meta>
|
||||||
<meta:creation-date>2021-04-26T23:35:34</meta:creation-date>
|
<meta:creation-date>2021-07-31T00:20:16</meta:creation-date>
|
||||||
<meta:generator>novelWriter/1.3rc1</meta:generator>
|
<meta:generator>novelWriter/1.5-alpha0</meta:generator>
|
||||||
</office:meta>
|
</office:meta>
|
||||||
<office:font-face-decls>
|
<office:font-face-decls>
|
||||||
<style:font-face style:name="DejaVu Sans" style:font-pitch="variable"/>
|
<style:font-face style:name="DejaVu Sans" style:font-pitch="variable"/>
|
||||||
@@ -187,7 +187,8 @@
|
|||||||
<text:p text:style-name="Text_Body">Integer egestas maximus leo eu facilisis. Nunc rhoncus dignissim lectus eu lacinia. Praesent lacinia urna porttitor aliquam condimentum. Nulla eu eros dictum, dictum nunc vitae, sagittis nibh. Integer ante neque, consequat nec sollicitudin id, consectetur vitae dolor. Nullam volutpat sem orci, quis viverra magna auctor a. Suspendisse potenti. Maecenas commodo sed neque pellentesque vehicula. Sed luctus nisl risus, elementum semper purus interdum vel. Ut pulvinar, massa sit amet venenatis placerat, nunc lacus hendrerit odio, non aliquet nunc risus eu lectus. Maecenas feugiat semper ligula, id lobortis sem porta eu. Integer posuere elit magna, at mollis eros bibendum et. Ut imperdiet purus vel nulla aliquam maximus. Morbi sodales purus tellus, a rhoncus sem rutrum sit amet. Quisque risus sem, laoreet nec convallis nec, rutrum vitae justo.</text:p>
|
<text:p text:style-name="Text_Body">Integer egestas maximus leo eu facilisis. Nunc rhoncus dignissim lectus eu lacinia. Praesent lacinia urna porttitor aliquam condimentum. Nulla eu eros dictum, dictum nunc vitae, sagittis nibh. Integer ante neque, consequat nec sollicitudin id, consectetur vitae dolor. Nullam volutpat sem orci, quis viverra magna auctor a. Suspendisse potenti. Maecenas commodo sed neque pellentesque vehicula. Sed luctus nisl risus, elementum semper purus interdum vel. Ut pulvinar, massa sit amet venenatis placerat, nunc lacus hendrerit odio, non aliquet nunc risus eu lectus. Maecenas feugiat semper ligula, id lobortis sem porta eu. Integer posuere elit magna, at mollis eros bibendum et. Ut imperdiet purus vel nulla aliquam maximus. Morbi sodales purus tellus, a rhoncus sem rutrum sit amet. Quisque risus sem, laoreet nec convallis nec, rutrum vitae justo.</text:p>
|
||||||
<text:h text:style-name="P8">Notes: Characters</text:h>
|
<text:h text:style-name="P8">Notes: Characters</text:h>
|
||||||
<text:h text:style-name="Heading_1" text:outline-level="1">Nobody Owens</text:h>
|
<text:h text:style-name="Heading_1" text:outline-level="1">Nobody Owens</text:h>
|
||||||
<text:p text:style-name="Text_Meta"><text:span text:style-name="T1">Tag:</text:span> Bod</text:p>
|
<text:p text:style-name="P6"><text:span text:style-name="T1">Tag:</text:span> Bod</text:p>
|
||||||
|
<text:p text:style-name="Text_Meta"><text:span text:style-name="T1">Plot:</text:span> Main</text:p>
|
||||||
<text:p text:style-name="Text_Body">Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.</text:p>
|
<text:p text:style-name="Text_Body">Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.</text:p>
|
||||||
<text:p text:style-name="Text_Body">Suspendisse faucibus est auctor orci mollis luctus. Praesent quis sodales neque. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec sodales rutrum mattis. In in sem ornare, consequat nulla ac, convallis arcu. Duis ac metus id felis commodo commodo sit amet eget diam. Curabitur rhoncus lacinia leo at sodales. Etiam finibus porta diam a viverra. Praesent nisi urna, volutpat sit amet odio at, vehicula vehicula leo. In non enim eget nisl luctus commodo. Pellentesque pellentesque at lectus at luctus. Quisque nec felis bibendum, lacinia libero ut, lacinia eros. Integer finibus ultricies nibh sit amet placerat.</text:p>
|
<text:p text:style-name="Text_Body">Suspendisse faucibus est auctor orci mollis luctus. Praesent quis sodales neque. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec sodales rutrum mattis. In in sem ornare, consequat nulla ac, convallis arcu. Duis ac metus id felis commodo commodo sit amet eget diam. Curabitur rhoncus lacinia leo at sodales. Etiam finibus porta diam a viverra. Praesent nisi urna, volutpat sit amet odio at, vehicula vehicula leo. In non enim eget nisl luctus commodo. Pellentesque pellentesque at lectus at luctus. Quisque nec felis bibendum, lacinia libero ut, lacinia eros. Integer finibus ultricies nibh sit amet placerat.</text:p>
|
||||||
<text:p text:style-name="Text_Body">Nullam scelerisque velit et tortor congue vestibulum a at nisi. Vivamus sodales ut turpis a convallis. In dignissim nibh at luctus sodales. Etiam sit amet rhoncus massa. Phasellus ligula magna, sollicitudin non imperdiet sit amet, volutpat vel magna. Nunc vestibulum tempor lectus, sit amet porta nunc hendrerit in. Curabitur non odio sit amet massa tincidunt facilisis. Integer et luctus nunc, eget euismod leo. Praesent faucibus metus sed purus convallis scelerisque. Fusce viverra lorem et placerat malesuada. In at elit malesuada, ullamcorper risus vitae, sodales dolor. Donec quis elementum lectus. Quisque eu eros at dui imperdiet euismod ut id neque.</text:p>
|
<text:p text:style-name="Text_Body">Nullam scelerisque velit et tortor congue vestibulum a at nisi. Vivamus sodales ut turpis a convallis. In dignissim nibh at luctus sodales. Etiam sit amet rhoncus massa. Phasellus ligula magna, sollicitudin non imperdiet sit amet, volutpat vel magna. Nunc vestibulum tempor lectus, sit amet porta nunc hendrerit in. Curabitur non odio sit amet massa tincidunt facilisis. Integer et luctus nunc, eget euismod leo. Praesent faucibus metus sed purus convallis scelerisque. Fusce viverra lorem et placerat malesuada. In at elit malesuada, ullamcorper risus vitae, sodales dolor. Donec quis elementum lectus. Quisque eu eros at dui imperdiet euismod ut id neque.</text:p>
|
||||||
|
|||||||
@@ -105,7 +105,8 @@ article {width: 800px; margin: 40px auto;}
|
|||||||
<p>Integer egestas maximus leo eu facilisis. Nunc rhoncus dignissim lectus eu lacinia. Praesent lacinia urna porttitor aliquam condimentum. Nulla eu eros dictum, dictum nunc vitae, sagittis nibh. Integer ante neque, consequat nec sollicitudin id, consectetur vitae dolor. Nullam volutpat sem orci, quis viverra magna auctor a. Suspendisse potenti. Maecenas commodo sed neque pellentesque vehicula. Sed luctus nisl risus, elementum semper purus interdum vel. Ut pulvinar, massa sit amet venenatis placerat, nunc lacus hendrerit odio, non aliquet nunc risus eu lectus. Maecenas feugiat semper ligula, id lobortis sem porta eu. Integer posuere elit magna, at mollis eros bibendum et. Ut imperdiet purus vel nulla aliquam maximus. Morbi sodales purus tellus, a rhoncus sem rutrum sit amet. Quisque risus sem, laoreet nec convallis nec, rutrum vitae justo.</p>
|
<p>Integer egestas maximus leo eu facilisis. Nunc rhoncus dignissim lectus eu lacinia. Praesent lacinia urna porttitor aliquam condimentum. Nulla eu eros dictum, dictum nunc vitae, sagittis nibh. Integer ante neque, consequat nec sollicitudin id, consectetur vitae dolor. Nullam volutpat sem orci, quis viverra magna auctor a. Suspendisse potenti. Maecenas commodo sed neque pellentesque vehicula. Sed luctus nisl risus, elementum semper purus interdum vel. Ut pulvinar, massa sit amet venenatis placerat, nunc lacus hendrerit odio, non aliquet nunc risus eu lectus. Maecenas feugiat semper ligula, id lobortis sem porta eu. Integer posuere elit magna, at mollis eros bibendum et. Ut imperdiet purus vel nulla aliquam maximus. Morbi sodales purus tellus, a rhoncus sem rutrum sit amet. Quisque risus sem, laoreet nec convallis nec, rutrum vitae justo.</p>
|
||||||
<h1 class='title' style='text-align: center; page-break-before: always;'>Notes: Characters</h1>
|
<h1 class='title' style='text-align: center; page-break-before: always;'>Notes: Characters</h1>
|
||||||
<h1>Nobody Owens</h1>
|
<h1>Nobody Owens</h1>
|
||||||
<p><span class='tags'>Tag:</span> <a name='tag_Bod'>Bod</a></p>
|
<p style='margin-bottom: 0;'><span class='tags'>Tag:</span> <a name='tag_Bod'>Bod</a></p>
|
||||||
|
<p style='margin-top: 0;'><span class='tags'>Plot:</span> <a href='#tag_Main'>Main</a></p>
|
||||||
<p>Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.</p>
|
<p>Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.</p>
|
||||||
<p>Suspendisse faucibus est auctor orci mollis luctus. Praesent quis sodales neque. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec sodales rutrum mattis. In in sem ornare, consequat nulla ac, convallis arcu. Duis ac metus id felis commodo commodo sit amet eget diam. Curabitur rhoncus lacinia leo at sodales. Etiam finibus porta diam a viverra. Praesent nisi urna, volutpat sit amet odio at, vehicula vehicula leo. In non enim eget nisl luctus commodo. Pellentesque pellentesque at lectus at luctus. Quisque nec felis bibendum, lacinia libero ut, lacinia eros. Integer finibus ultricies nibh sit amet placerat.</p>
|
<p>Suspendisse faucibus est auctor orci mollis luctus. Praesent quis sodales neque. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec sodales rutrum mattis. In in sem ornare, consequat nulla ac, convallis arcu. Duis ac metus id felis commodo commodo sit amet eget diam. Curabitur rhoncus lacinia leo at sodales. Etiam finibus porta diam a viverra. Praesent nisi urna, volutpat sit amet odio at, vehicula vehicula leo. In non enim eget nisl luctus commodo. Pellentesque pellentesque at lectus at luctus. Quisque nec felis bibendum, lacinia libero ut, lacinia eros. Integer finibus ultricies nibh sit amet placerat.</p>
|
||||||
<p>Nullam scelerisque velit et tortor congue vestibulum a at nisi. Vivamus sodales ut turpis a convallis. In dignissim nibh at luctus sodales. Etiam sit amet rhoncus massa. Phasellus ligula magna, sollicitudin non imperdiet sit amet, volutpat vel magna. Nunc vestibulum tempor lectus, sit amet porta nunc hendrerit in. Curabitur non odio sit amet massa tincidunt facilisis. Integer et luctus nunc, eget euismod leo. Praesent faucibus metus sed purus convallis scelerisque. Fusce viverra lorem et placerat malesuada. In at elit malesuada, ullamcorper risus vitae, sodales dolor. Donec quis elementum lectus. Quisque eu eros at dui imperdiet euismod ut id neque.</p>
|
<p>Nullam scelerisque velit et tortor congue vestibulum a at nisi. Vivamus sodales ut turpis a convallis. In dignissim nibh at luctus sodales. Etiam sit amet rhoncus massa. Phasellus ligula magna, sollicitudin non imperdiet sit amet, volutpat vel magna. Nunc vestibulum tempor lectus, sit amet porta nunc hendrerit in. Curabitur non odio sit amet massa tincidunt facilisis. Integer et luctus nunc, eget euismod leo. Praesent faucibus metus sed purus convallis scelerisque. Fusce viverra lorem et placerat malesuada. In at elit malesuada, ullamcorper risus vitae, sodales dolor. Donec quis elementum lectus. Quisque eu eros at dui imperdiet euismod ut id neque.</p>
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ Integer egestas maximus leo eu facilisis. Nunc rhoncus dignissim lectus eu lacin
|
|||||||
# Nobody Owens
|
# Nobody Owens
|
||||||
|
|
||||||
**Tag:** Bod
|
**Tag:** Bod
|
||||||
|
**Plot:** Main
|
||||||
|
|
||||||
Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.
|
Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.
|
||||||
|
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ Integer egestas maximus leo eu facilisis. Nunc rhoncus dignissim lectus eu lacin
|
|||||||
# Nobody Owens
|
# Nobody Owens
|
||||||
|
|
||||||
@tag: Bod
|
@tag: Bod
|
||||||
|
@plot: Main
|
||||||
|
|
||||||
Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.
|
Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
|
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
|
||||||
<office:meta>
|
<office:meta>
|
||||||
<meta:creation-date>2021-04-26T23:38:33</meta:creation-date>
|
<meta:creation-date>2021-07-31T00:25:38</meta:creation-date>
|
||||||
<meta:generator>novelWriter/1.3rc1</meta:generator>
|
<meta:generator>novelWriter/1.5-alpha0</meta:generator>
|
||||||
</office:meta>
|
</office:meta>
|
||||||
<office:font-face-decls>
|
<office:font-face-decls>
|
||||||
<style:font-face style:name="DejaVu Sans" style:font-pitch="variable"/>
|
<style:font-face style:name="DejaVu Sans" style:font-pitch="variable"/>
|
||||||
@@ -187,7 +187,8 @@
|
|||||||
<text:p text:style-name="Text_Body">Integer egestas maximus leo eu facilisis. Nunc rhoncus dignissim lectus eu lacinia. Praesent lacinia urna porttitor aliquam condimentum. Nulla eu eros dictum, dictum nunc vitae, sagittis nibh. Integer ante neque, consequat nec sollicitudin id, consectetur vitae dolor. Nullam volutpat sem orci, quis viverra magna auctor a. Suspendisse potenti. Maecenas commodo sed neque pellentesque vehicula. Sed luctus nisl risus, elementum semper purus interdum vel. Ut pulvinar, massa sit amet venenatis placerat, nunc lacus hendrerit odio, non aliquet nunc risus eu lectus. Maecenas feugiat semper ligula, id lobortis sem porta eu. Integer posuere elit magna, at mollis eros bibendum et. Ut imperdiet purus vel nulla aliquam maximus. Morbi sodales purus tellus, a rhoncus sem rutrum sit amet. Quisque risus sem, laoreet nec convallis nec, rutrum vitae justo.</text:p>
|
<text:p text:style-name="Text_Body">Integer egestas maximus leo eu facilisis. Nunc rhoncus dignissim lectus eu lacinia. Praesent lacinia urna porttitor aliquam condimentum. Nulla eu eros dictum, dictum nunc vitae, sagittis nibh. Integer ante neque, consequat nec sollicitudin id, consectetur vitae dolor. Nullam volutpat sem orci, quis viverra magna auctor a. Suspendisse potenti. Maecenas commodo sed neque pellentesque vehicula. Sed luctus nisl risus, elementum semper purus interdum vel. Ut pulvinar, massa sit amet venenatis placerat, nunc lacus hendrerit odio, non aliquet nunc risus eu lectus. Maecenas feugiat semper ligula, id lobortis sem porta eu. Integer posuere elit magna, at mollis eros bibendum et. Ut imperdiet purus vel nulla aliquam maximus. Morbi sodales purus tellus, a rhoncus sem rutrum sit amet. Quisque risus sem, laoreet nec convallis nec, rutrum vitae justo.</text:p>
|
||||||
<text:h text:style-name="P8">Notes: Characters</text:h>
|
<text:h text:style-name="P8">Notes: Characters</text:h>
|
||||||
<text:h text:style-name="Heading_1" text:outline-level="1">Nobody Owens</text:h>
|
<text:h text:style-name="Heading_1" text:outline-level="1">Nobody Owens</text:h>
|
||||||
<text:p text:style-name="Text_Meta"><text:span text:style-name="T1">Tag:</text:span> Bod</text:p>
|
<text:p text:style-name="P6"><text:span text:style-name="T1">Tag:</text:span> Bod</text:p>
|
||||||
|
<text:p text:style-name="Text_Meta"><text:span text:style-name="T1">Plot:</text:span> Main</text:p>
|
||||||
<text:p text:style-name="Text_Body">Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.</text:p>
|
<text:p text:style-name="Text_Body">Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.</text:p>
|
||||||
<text:p text:style-name="Text_Body">Suspendisse faucibus est auctor orci mollis luctus. Praesent quis sodales neque. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec sodales rutrum mattis. In in sem ornare, consequat nulla ac, convallis arcu. Duis ac metus id felis commodo commodo sit amet eget diam. Curabitur rhoncus lacinia leo at sodales. Etiam finibus porta diam a viverra. Praesent nisi urna, volutpat sit amet odio at, vehicula vehicula leo. In non enim eget nisl luctus commodo. Pellentesque pellentesque at lectus at luctus. Quisque nec felis bibendum, lacinia libero ut, lacinia eros. Integer finibus ultricies nibh sit amet placerat.</text:p>
|
<text:p text:style-name="Text_Body">Suspendisse faucibus est auctor orci mollis luctus. Praesent quis sodales neque. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec sodales rutrum mattis. In in sem ornare, consequat nulla ac, convallis arcu. Duis ac metus id felis commodo commodo sit amet eget diam. Curabitur rhoncus lacinia leo at sodales. Etiam finibus porta diam a viverra. Praesent nisi urna, volutpat sit amet odio at, vehicula vehicula leo. In non enim eget nisl luctus commodo. Pellentesque pellentesque at lectus at luctus. Quisque nec felis bibendum, lacinia libero ut, lacinia eros. Integer finibus ultricies nibh sit amet placerat.</text:p>
|
||||||
<text:p text:style-name="Text_Body">Nullam scelerisque velit et tortor congue vestibulum a at nisi. Vivamus sodales ut turpis a convallis. In dignissim nibh at luctus sodales. Etiam sit amet rhoncus massa. Phasellus ligula magna, sollicitudin non imperdiet sit amet, volutpat vel magna. Nunc vestibulum tempor lectus, sit amet porta nunc hendrerit in. Curabitur non odio sit amet massa tincidunt facilisis. Integer et luctus nunc, eget euismod leo. Praesent faucibus metus sed purus convallis scelerisque. Fusce viverra lorem et placerat malesuada. In at elit malesuada, ullamcorper risus vitae, sodales dolor. Donec quis elementum lectus. Quisque eu eros at dui imperdiet euismod ut id neque.</text:p>
|
<text:p text:style-name="Text_Body">Nullam scelerisque velit et tortor congue vestibulum a at nisi. Vivamus sodales ut turpis a convallis. In dignissim nibh at luctus sodales. Etiam sit amet rhoncus massa. Phasellus ligula magna, sollicitudin non imperdiet sit amet, volutpat vel magna. Nunc vestibulum tempor lectus, sit amet porta nunc hendrerit in. Curabitur non odio sit amet massa tincidunt facilisis. Integer et luctus nunc, eget euismod leo. Praesent faucibus metus sed purus convallis scelerisque. Fusce viverra lorem et placerat malesuada. In at elit malesuada, ullamcorper risus vitae, sodales dolor. Donec quis elementum lectus. Quisque eu eros at dui imperdiet euismod ut id neque.</text:p>
|
||||||
|
|||||||
@@ -105,7 +105,8 @@ article {width: 800px; margin: 40px auto;}
|
|||||||
<p>Integer egestas maximus leo eu facilisis. Nunc rhoncus dignissim lectus eu lacinia. Praesent lacinia urna porttitor aliquam condimentum. Nulla eu eros dictum, dictum nunc vitae, sagittis nibh. Integer ante neque, consequat nec sollicitudin id, consectetur vitae dolor. Nullam volutpat sem orci, quis viverra magna auctor a. Suspendisse potenti. Maecenas commodo sed neque pellentesque vehicula. Sed luctus nisl risus, elementum semper purus interdum vel. Ut pulvinar, massa sit amet venenatis placerat, nunc lacus hendrerit odio, non aliquet nunc risus eu lectus. Maecenas feugiat semper ligula, id lobortis sem porta eu. Integer posuere elit magna, at mollis eros bibendum et. Ut imperdiet purus vel nulla aliquam maximus. Morbi sodales purus tellus, a rhoncus sem rutrum sit amet. Quisque risus sem, laoreet nec convallis nec, rutrum vitae justo.</p>
|
<p>Integer egestas maximus leo eu facilisis. Nunc rhoncus dignissim lectus eu lacinia. Praesent lacinia urna porttitor aliquam condimentum. Nulla eu eros dictum, dictum nunc vitae, sagittis nibh. Integer ante neque, consequat nec sollicitudin id, consectetur vitae dolor. Nullam volutpat sem orci, quis viverra magna auctor a. Suspendisse potenti. Maecenas commodo sed neque pellentesque vehicula. Sed luctus nisl risus, elementum semper purus interdum vel. Ut pulvinar, massa sit amet venenatis placerat, nunc lacus hendrerit odio, non aliquet nunc risus eu lectus. Maecenas feugiat semper ligula, id lobortis sem porta eu. Integer posuere elit magna, at mollis eros bibendum et. Ut imperdiet purus vel nulla aliquam maximus. Morbi sodales purus tellus, a rhoncus sem rutrum sit amet. Quisque risus sem, laoreet nec convallis nec, rutrum vitae justo.</p>
|
||||||
<h1 class='title' style='text-align: center; page-break-before: always;'>Notes: Characters</h1>
|
<h1 class='title' style='text-align: center; page-break-before: always;'>Notes: Characters</h1>
|
||||||
<h1>Nobody Owens</h1>
|
<h1>Nobody Owens</h1>
|
||||||
<p><span class='tags'>Tag:</span> <a name='tag_Bod'>Bod</a></p>
|
<p style='margin-bottom: 0;'><span class='tags'>Tag:</span> <a name='tag_Bod'>Bod</a></p>
|
||||||
|
<p style='margin-top: 0;'><span class='tags'>Plot:</span> <a href='#tag_Main'>Main</a></p>
|
||||||
<p>Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.</p>
|
<p>Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.</p>
|
||||||
<p>Suspendisse faucibus est auctor orci mollis luctus. Praesent quis sodales neque. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec sodales rutrum mattis. In in sem ornare, consequat nulla ac, convallis arcu. Duis ac metus id felis commodo commodo sit amet eget diam. Curabitur rhoncus lacinia leo at sodales. Etiam finibus porta diam a viverra. Praesent nisi urna, volutpat sit amet odio at, vehicula vehicula leo. In non enim eget nisl luctus commodo. Pellentesque pellentesque at lectus at luctus. Quisque nec felis bibendum, lacinia libero ut, lacinia eros. Integer finibus ultricies nibh sit amet placerat.</p>
|
<p>Suspendisse faucibus est auctor orci mollis luctus. Praesent quis sodales neque. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec sodales rutrum mattis. In in sem ornare, consequat nulla ac, convallis arcu. Duis ac metus id felis commodo commodo sit amet eget diam. Curabitur rhoncus lacinia leo at sodales. Etiam finibus porta diam a viverra. Praesent nisi urna, volutpat sit amet odio at, vehicula vehicula leo. In non enim eget nisl luctus commodo. Pellentesque pellentesque at lectus at luctus. Quisque nec felis bibendum, lacinia libero ut, lacinia eros. Integer finibus ultricies nibh sit amet placerat.</p>
|
||||||
<p>Nullam scelerisque velit et tortor congue vestibulum a at nisi. Vivamus sodales ut turpis a convallis. In dignissim nibh at luctus sodales. Etiam sit amet rhoncus massa. Phasellus ligula magna, sollicitudin non imperdiet sit amet, volutpat vel magna. Nunc vestibulum tempor lectus, sit amet porta nunc hendrerit in. Curabitur non odio sit amet massa tincidunt facilisis. Integer et luctus nunc, eget euismod leo. Praesent faucibus metus sed purus convallis scelerisque. Fusce viverra lorem et placerat malesuada. In at elit malesuada, ullamcorper risus vitae, sodales dolor. Donec quis elementum lectus. Quisque eu eros at dui imperdiet euismod ut id neque.</p>
|
<p>Nullam scelerisque velit et tortor congue vestibulum a at nisi. Vivamus sodales ut turpis a convallis. In dignissim nibh at luctus sodales. Etiam sit amet rhoncus massa. Phasellus ligula magna, sollicitudin non imperdiet sit amet, volutpat vel magna. Nunc vestibulum tempor lectus, sit amet porta nunc hendrerit in. Curabitur non odio sit amet massa tincidunt facilisis. Integer et luctus nunc, eget euismod leo. Praesent faucibus metus sed purus convallis scelerisque. Fusce viverra lorem et placerat malesuada. In at elit malesuada, ullamcorper risus vitae, sodales dolor. Donec quis elementum lectus. Quisque eu eros at dui imperdiet euismod ut id neque.</p>
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ Integer egestas maximus leo eu facilisis. Nunc rhoncus dignissim lectus eu lacin
|
|||||||
# Nobody Owens
|
# Nobody Owens
|
||||||
|
|
||||||
**Tag:** Bod
|
**Tag:** Bod
|
||||||
|
**Plot:** Main
|
||||||
|
|
||||||
Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.
|
Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.
|
||||||
|
|
||||||
|
|||||||
@@ -76,11 +76,11 @@ Ut et consequat enim, quis ornare nibh. In lectus neque, mollis et suscipit et,
|
|||||||
|
|
||||||
% Exctracted from the lipsum.com website.
|
% Exctracted from the lipsum.com website.
|
||||||
|
|
||||||
It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.
|
It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.
|
||||||
|
|
||||||
The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.
|
The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.
|
||||||
|
|
||||||
Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).
|
Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).
|
||||||
|
|
||||||
## Chapter Two
|
## Chapter Two
|
||||||
|
|
||||||
@@ -151,6 +151,7 @@ Integer egestas maximus leo eu facilisis. Nunc rhoncus dignissim lectus eu lacin
|
|||||||
# Nobody Owens
|
# Nobody Owens
|
||||||
|
|
||||||
@tag: Bod
|
@tag: Bod
|
||||||
|
@plot: Main
|
||||||
|
|
||||||
Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.
|
Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. Maecenas suscipit porta elit, sit amet porta felis porttitor eu. Sed a dui nibh. Phasellus sed faucibus dui. Pellentesque felis nulla, ultrices non efficitur quis, rutrum id mi. Mauris tempus auctor nisl, in bibendum enim pellentesque sit amet. Proin nunc lacus, imperdiet nec posuere ac, interdum non lectus.
|
||||||
|
|
||||||
|
|||||||
@@ -28,10 +28,11 @@ from datetime import datetime
|
|||||||
from tools import writeFile
|
from tools import writeFile
|
||||||
|
|
||||||
from nw.common import (
|
from nw.common import (
|
||||||
checkString, checkBool, checkInt, formatInt, transferCase, fuzzyTime,
|
checkString, checkInt, checkBool, checkHandle, isHandle, isTitleTag,
|
||||||
checkHandle, formatTimeStamp, parseTimeStamp, formatTime, hexToInt,
|
isItemClass, isItemType, isItemLayout, hexToInt, formatInt,
|
||||||
makeFileNameSafe, isHandle, isTitleTag, isItemClass, isItemType,
|
formatTimeStamp, formatTime, parseTimeStamp, splitVersionNumber,
|
||||||
isItemLayout, numberToRoman, NWConfigParser
|
transferCase, fuzzyTime, numberToRoman, jsonEncode, makeFileNameSafe,
|
||||||
|
NWConfigParser
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -253,6 +254,25 @@ def testBaseCommon_ParseTimeStamp():
|
|||||||
# END Test testBaseCommon_ParseTimeStamp
|
# END Test testBaseCommon_ParseTimeStamp
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.base
|
||||||
|
def testBaseCommon_SplitVersionNumber():
|
||||||
|
"""Test the splitVersionNumber function.
|
||||||
|
"""
|
||||||
|
# OK Values
|
||||||
|
assert splitVersionNumber("1") == [1, 0, 0, 10000]
|
||||||
|
assert splitVersionNumber("1.2") == [1, 2, 0, 10200]
|
||||||
|
assert splitVersionNumber("1.2.3") == [1, 2, 3, 10203]
|
||||||
|
assert splitVersionNumber("1.2.3.4") == [1, 2, 3, 10203]
|
||||||
|
assert splitVersionNumber("99.99.99") == [99, 99, 99, 999999]
|
||||||
|
|
||||||
|
# Failed Values
|
||||||
|
assert splitVersionNumber(None) == [0, 0, 0, 0]
|
||||||
|
assert splitVersionNumber(1234) == [0, 0, 0, 0]
|
||||||
|
assert splitVersionNumber("1.2abc") == [1, 0, 0, 10000]
|
||||||
|
|
||||||
|
# END Test testBaseCommon_SplitVersionNumber
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.base
|
@pytest.mark.base
|
||||||
def testBaseCommon_FormatInt():
|
def testBaseCommon_FormatInt():
|
||||||
"""Test the formatInt function.
|
"""Test the formatInt function.
|
||||||
@@ -368,6 +388,90 @@ def testBaseCommon_RomanNumbers():
|
|||||||
# END Test testBaseCommon_RomanNumbers
|
# END Test testBaseCommon_RomanNumbers
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.base
|
||||||
|
def testBaseCommon_JsonEncode():
|
||||||
|
"""Test the jsonEncode function.
|
||||||
|
"""
|
||||||
|
# Wrong type
|
||||||
|
assert jsonEncode(None) == "[]"
|
||||||
|
|
||||||
|
# Correct types
|
||||||
|
assert jsonEncode([1, 2]) == "[\n 1,\n 2\n]"
|
||||||
|
assert jsonEncode((1, 2)) == "[\n 1,\n 2\n]"
|
||||||
|
assert jsonEncode({1: 2}) == "{\n \"1\": 2\n}"
|
||||||
|
|
||||||
|
tstDict = {
|
||||||
|
"null": None,
|
||||||
|
"one": 1,
|
||||||
|
"two": "2",
|
||||||
|
"three": 3.0,
|
||||||
|
"four": False,
|
||||||
|
"five": (1, 2),
|
||||||
|
"six": {"a": 1, "b": 2},
|
||||||
|
"seven": [],
|
||||||
|
"eight": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Complex Structure
|
||||||
|
assert jsonEncode(tstDict) == (
|
||||||
|
'{\n'
|
||||||
|
' "null": null,\n'
|
||||||
|
' "one": 1,\n'
|
||||||
|
' "two": "2",\n'
|
||||||
|
' "three": 3.0,\n'
|
||||||
|
' "four": false,\n'
|
||||||
|
' "five": [\n'
|
||||||
|
' 1,\n'
|
||||||
|
' 2\n'
|
||||||
|
' ],\n'
|
||||||
|
' "six": {\n'
|
||||||
|
' "a": 1,\n'
|
||||||
|
' "b": 2\n'
|
||||||
|
' },\n'
|
||||||
|
' "seven": [],\n'
|
||||||
|
' "eight": {}\n'
|
||||||
|
'}'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Additional Indent
|
||||||
|
assert jsonEncode(tstDict, n=2) == (
|
||||||
|
'{\n'
|
||||||
|
' "null": null,\n'
|
||||||
|
' "one": 1,\n'
|
||||||
|
' "two": "2",\n'
|
||||||
|
' "three": 3.0,\n'
|
||||||
|
' "four": false,\n'
|
||||||
|
' "five": [\n'
|
||||||
|
' 1,\n'
|
||||||
|
' 2\n'
|
||||||
|
' ],\n'
|
||||||
|
' "six": {\n'
|
||||||
|
' "a": 1,\n'
|
||||||
|
' "b": 2\n'
|
||||||
|
' },\n'
|
||||||
|
' "seven": [],\n'
|
||||||
|
' "eight": {}\n'
|
||||||
|
' }'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Max Indent
|
||||||
|
assert jsonEncode(tstDict, n=0, nmax=1) == (
|
||||||
|
'{\n'
|
||||||
|
' "null": null,\n'
|
||||||
|
' "one": 1,\n'
|
||||||
|
' "two": "2",\n'
|
||||||
|
' "three": 3.0,\n'
|
||||||
|
' "four": false,\n'
|
||||||
|
' "five": [1, 2],\n'
|
||||||
|
' "six": {"a": 1, "b": 2},\n'
|
||||||
|
' "seven": [],\n'
|
||||||
|
' "eight": {}\n'
|
||||||
|
'}'
|
||||||
|
)
|
||||||
|
|
||||||
|
# END Test testBaseCommon_JsonEncode
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.base
|
@pytest.mark.base
|
||||||
def testBaseCommon_NWConfigParser(fncDir):
|
def testBaseCommon_NWConfigParser(fncDir):
|
||||||
"""Test the NWConfigParser subclass.
|
"""Test the NWConfigParser subclass.
|
||||||
|
|||||||
+301
-307
@@ -46,8 +46,6 @@ def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, outDir, refDir):
|
|||||||
theProject.projTree.setSeed(42)
|
theProject.projTree.setSeed(42)
|
||||||
assert theProject.openProject(nwLipsum)
|
assert theProject.openProject(nwLipsum)
|
||||||
|
|
||||||
monkeypatch.setattr("nw.core.index.time", lambda: 123.4)
|
|
||||||
|
|
||||||
theIndex = NWIndex(theProject)
|
theIndex = NWIndex(theProject)
|
||||||
notIndexable = {
|
notIndexable = {
|
||||||
"b3643d0f92e32": False, # Novel ROOT
|
"b3643d0f92e32": False, # Novel ROOT
|
||||||
@@ -60,64 +58,61 @@ def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, outDir, refDir):
|
|||||||
for tItem in theProject.projTree:
|
for tItem in theProject.projTree:
|
||||||
assert theIndex.reIndexHandle(tItem.itemHandle) is notIndexable.get(tItem.itemHandle, True)
|
assert theIndex.reIndexHandle(tItem.itemHandle) is notIndexable.get(tItem.itemHandle, True)
|
||||||
|
|
||||||
assert not theIndex.reIndexHandle(None)
|
assert theIndex.reIndexHandle(None) is False
|
||||||
|
|
||||||
# Make the save fail
|
# Make the save fail
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(json, "dump", causeException)
|
mp.setattr("builtins.open", causeException)
|
||||||
assert not theIndex.saveIndex()
|
assert theIndex.saveIndex() is False
|
||||||
|
|
||||||
# Make the save pass
|
# Make the save pass
|
||||||
assert theIndex.saveIndex()
|
assert theIndex.saveIndex() is True
|
||||||
|
|
||||||
# Take a copy of the index
|
# Take a copy of the index
|
||||||
tagIndex = str(theIndex._tagIndex)
|
tagIndex = str(theIndex._tagIndex)
|
||||||
refIndex = str(theIndex._refIndex)
|
refIndex = str(theIndex._refIndex)
|
||||||
novelIndex = str(theIndex._novelIndex)
|
fileIndex = str(theIndex._fileIndex)
|
||||||
noteIndex = str(theIndex._noteIndex)
|
|
||||||
textCounts = str(theIndex._textCounts)
|
textCounts = str(theIndex._textCounts)
|
||||||
|
|
||||||
# Delete a handle
|
# Delete a handle
|
||||||
assert theIndex._tagIndex.get("Bod", None) is not None
|
assert theIndex._tagIndex.get("Bod", None) is not None
|
||||||
assert theIndex._refIndex.get("4c4f28287af27", None) is not None
|
assert theIndex._refIndex.get("4c4f28287af27", None) is not None
|
||||||
assert theIndex._noteIndex.get("4c4f28287af27", None) is not None
|
assert theIndex._fileIndex.get("4c4f28287af27", None) is not None
|
||||||
assert theIndex._textCounts.get("4c4f28287af27", None) is not None
|
assert theIndex._textCounts.get("4c4f28287af27", None) is not None
|
||||||
theIndex.deleteHandle("4c4f28287af27")
|
theIndex.deleteHandle("4c4f28287af27")
|
||||||
assert theIndex._tagIndex.get("Bod", None) is None
|
assert theIndex._tagIndex.get("Bod", None) is None
|
||||||
assert theIndex._refIndex.get("4c4f28287af27", None) is None
|
assert theIndex._refIndex.get("4c4f28287af27", None) is None
|
||||||
assert theIndex._noteIndex.get("4c4f28287af27", None) is None
|
assert theIndex._fileIndex.get("4c4f28287af27", None) is None
|
||||||
assert theIndex._textCounts.get("4c4f28287af27", None) is None
|
assert theIndex._textCounts.get("4c4f28287af27", None) is None
|
||||||
|
|
||||||
# Clear the index
|
# Clear the index
|
||||||
theIndex.clearIndex()
|
theIndex.clearIndex()
|
||||||
assert not theIndex._tagIndex
|
assert theIndex._tagIndex == {}
|
||||||
assert not theIndex._refIndex
|
assert theIndex._refIndex == {}
|
||||||
assert not theIndex._novelIndex
|
assert theIndex._fileIndex == {}
|
||||||
assert not theIndex._noteIndex
|
assert theIndex._textCounts == {}
|
||||||
assert not theIndex._textCounts
|
|
||||||
|
|
||||||
# Make the load fail
|
# Make the load fail
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(json, "load", causeException)
|
mp.setattr(json, "load", causeException)
|
||||||
assert not theIndex.loadIndex()
|
assert theIndex.loadIndex() is False
|
||||||
|
|
||||||
# Make the load pass
|
# Make the load pass
|
||||||
assert theIndex.loadIndex()
|
assert theIndex.loadIndex() is True
|
||||||
|
|
||||||
assert str(theIndex._tagIndex) == tagIndex
|
assert str(theIndex._tagIndex) == tagIndex
|
||||||
assert str(theIndex._refIndex) == refIndex
|
assert str(theIndex._refIndex) == refIndex
|
||||||
assert str(theIndex._novelIndex) == novelIndex
|
assert str(theIndex._fileIndex) == fileIndex
|
||||||
assert str(theIndex._noteIndex) == noteIndex
|
|
||||||
assert str(theIndex._textCounts) == textCounts
|
assert str(theIndex._textCounts) == textCounts
|
||||||
|
|
||||||
# Break the index and check that we notice
|
# Break the index and check that we notice
|
||||||
assert not theIndex.indexBroken
|
assert theIndex.indexBroken is False
|
||||||
theIndex._tagIndex["Bod"].append("Stuff")
|
theIndex._tagIndex["Bod"].append("Stuff")
|
||||||
theIndex.checkIndex()
|
theIndex.checkIndex()
|
||||||
assert theIndex.indexBroken
|
assert theIndex.indexBroken is True
|
||||||
|
|
||||||
# Finalise
|
# Finalise
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
|
|
||||||
copyfile(projFile, testFile)
|
copyfile(projFile, testFile)
|
||||||
assert cmpFiles(testFile, compFile)
|
assert cmpFiles(testFile, compFile)
|
||||||
@@ -131,48 +126,48 @@ def testCoreIndex_ScanThis(nwMinimal, mockGUI):
|
|||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
theProject.projTree.setSeed(42)
|
theProject.projTree.setSeed(42)
|
||||||
assert theProject.openProject(nwMinimal)
|
assert theProject.openProject(nwMinimal) is True
|
||||||
|
|
||||||
theIndex = NWIndex(theProject)
|
theIndex = NWIndex(theProject)
|
||||||
|
|
||||||
isValid, theBits, thePos = theIndex.scanThis("tag: this, and this")
|
isValid, theBits, thePos = theIndex.scanThis("tag: this, and this")
|
||||||
assert not isValid
|
assert isValid is False
|
||||||
|
|
||||||
isValid, theBits, thePos = theIndex.scanThis("@")
|
isValid, theBits, thePos = theIndex.scanThis("@")
|
||||||
assert not isValid
|
assert isValid is False
|
||||||
|
|
||||||
isValid, theBits, thePos = theIndex.scanThis("@:")
|
isValid, theBits, thePos = theIndex.scanThis("@:")
|
||||||
assert not isValid
|
assert isValid is False
|
||||||
|
|
||||||
isValid, theBits, thePos = theIndex.scanThis(" @a: b")
|
isValid, theBits, thePos = theIndex.scanThis(" @a: b")
|
||||||
assert not isValid
|
assert isValid is False
|
||||||
|
|
||||||
isValid, theBits, thePos = theIndex.scanThis("@a:")
|
isValid, theBits, thePos = theIndex.scanThis("@a:")
|
||||||
assert isValid
|
assert isValid is True
|
||||||
assert theBits == ["@a"]
|
assert theBits == ["@a"]
|
||||||
assert thePos == [0]
|
assert thePos == [0]
|
||||||
|
|
||||||
isValid, theBits, thePos = theIndex.scanThis("@a:b")
|
isValid, theBits, thePos = theIndex.scanThis("@a:b")
|
||||||
assert isValid
|
assert isValid is True
|
||||||
assert theBits == ["@a", "b"]
|
assert theBits == ["@a", "b"]
|
||||||
assert thePos == [0, 3]
|
assert thePos == [0, 3]
|
||||||
|
|
||||||
isValid, theBits, thePos = theIndex.scanThis("@a:b,c,d")
|
isValid, theBits, thePos = theIndex.scanThis("@a:b,c,d")
|
||||||
assert isValid
|
assert isValid is True
|
||||||
assert theBits == ["@a", "b", "c", "d"]
|
assert theBits == ["@a", "b", "c", "d"]
|
||||||
assert thePos == [0, 3, 5, 7]
|
assert thePos == [0, 3, 5, 7]
|
||||||
|
|
||||||
isValid, theBits, thePos = theIndex.scanThis("@a : b , c , d")
|
isValid, theBits, thePos = theIndex.scanThis("@a : b , c , d")
|
||||||
assert isValid
|
assert isValid is True
|
||||||
assert theBits == ["@a", "b", "c", "d"]
|
assert theBits == ["@a", "b", "c", "d"]
|
||||||
assert thePos == [0, 5, 9, 13]
|
assert thePos == [0, 5, 9, 13]
|
||||||
|
|
||||||
isValid, theBits, thePos = theIndex.scanThis("@tag: this, and this")
|
isValid, theBits, thePos = theIndex.scanThis("@tag: this, and this")
|
||||||
assert isValid
|
assert isValid is True
|
||||||
assert theBits == ["@tag", "this", "and this"]
|
assert theBits == ["@tag", "this", "and this"]
|
||||||
assert thePos == [0, 6, 12]
|
assert thePos == [0, 6, 12]
|
||||||
|
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
|
|
||||||
# END Test testCoreIndex_ScanThis
|
# END Test testCoreIndex_ScanThis
|
||||||
|
|
||||||
@@ -183,7 +178,7 @@ def testCoreIndex_CheckThese(nwMinimal, mockGUI):
|
|||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
theProject.projTree.setSeed(42)
|
theProject.projTree.setSeed(42)
|
||||||
assert theProject.openProject(nwMinimal)
|
assert theProject.openProject(nwMinimal) is True
|
||||||
|
|
||||||
theIndex = NWIndex(theProject)
|
theIndex = NWIndex(theProject)
|
||||||
nHandle = theProject.newFile("Hello", nwItemClass.NOVEL, "a508bb932959c")
|
nHandle = theProject.newFile("Hello", nwItemClass.NOVEL, "a508bb932959c")
|
||||||
@@ -191,9 +186,9 @@ def testCoreIndex_CheckThese(nwMinimal, mockGUI):
|
|||||||
nItem = theProject.projTree[nHandle]
|
nItem = theProject.projTree[nHandle]
|
||||||
cItem = theProject.projTree[cHandle]
|
cItem = theProject.projTree[cHandle]
|
||||||
|
|
||||||
assert not theIndex.novelChangedSince(0)
|
assert theIndex.novelChangedSince(0) is False
|
||||||
assert not theIndex.notesChangedSince(0)
|
assert theIndex.notesChangedSince(0) is False
|
||||||
assert not theIndex.indexChangedSince(0)
|
assert theIndex.indexChangedSince(0) is False
|
||||||
|
|
||||||
assert theIndex.scanText(cHandle, (
|
assert theIndex.scanText(cHandle, (
|
||||||
"# Jane Smith\n"
|
"# Jane Smith\n"
|
||||||
@@ -220,21 +215,33 @@ def testCoreIndex_CheckThese(nwMinimal, mockGUI):
|
|||||||
"@time": []
|
"@time": []
|
||||||
}
|
}
|
||||||
|
|
||||||
assert theIndex.novelChangedSince(0)
|
assert theIndex.novelChangedSince(0) is True
|
||||||
assert theIndex.notesChangedSince(0)
|
assert theIndex.notesChangedSince(0) is True
|
||||||
assert theIndex.indexChangedSince(0)
|
assert theIndex.indexChangedSince(0) is True
|
||||||
|
|
||||||
|
# Zero Items
|
||||||
assert theIndex.checkThese([], cItem) == []
|
assert theIndex.checkThese([], cItem) == []
|
||||||
assert theIndex.checkThese(["@tag", "Jane"], cItem) == [True, True]
|
|
||||||
assert theIndex.checkThese(["@tag", "John"], cItem) == [True, True]
|
# One Item
|
||||||
assert theIndex.checkThese(["@tag", "Jane"], nItem) == [True, False]
|
assert theIndex.checkThese(["@tag"], cItem) == [True]
|
||||||
assert theIndex.checkThese(["@tag", "John"], nItem) == [True, True]
|
assert theIndex.checkThese(["@who"], cItem) == [False]
|
||||||
assert theIndex.checkThese(["@pov", "John"], nItem) == [True, False]
|
|
||||||
assert theIndex.checkThese(["@pov", "Jane"], nItem) == [True, True]
|
# Two Items
|
||||||
|
assert theIndex.checkThese(["@tag", "Jane"], cItem) == [True, True]
|
||||||
|
assert theIndex.checkThese(["@tag", "John"], cItem) == [True, True]
|
||||||
|
assert theIndex.checkThese(["@tag", "Jane"], nItem) == [True, False]
|
||||||
|
assert theIndex.checkThese(["@tag", "John"], nItem) == [True, True]
|
||||||
|
assert theIndex.checkThese(["@pov", "John"], nItem) == [True, False]
|
||||||
|
assert theIndex.checkThese(["@pov", "Jane"], nItem) == [True, True]
|
||||||
assert theIndex.checkThese(["@ pov", "Jane"], nItem) == [False, False]
|
assert theIndex.checkThese(["@ pov", "Jane"], nItem) == [False, False]
|
||||||
assert theIndex.checkThese(["@what", "Jane"], nItem) == [False, False]
|
assert theIndex.checkThese(["@what", "Jane"], nItem) == [False, False]
|
||||||
|
|
||||||
assert theProject.closeProject()
|
# Three Items
|
||||||
|
assert theIndex.checkThese(["@tag", "Jane", "John"], cItem) == [True, True, False]
|
||||||
|
assert theIndex.checkThese(["@who", "Jane", "John"], cItem) == [False, False, False]
|
||||||
|
assert theIndex.checkThese(["@pov", "Jane", "John"], nItem) == [True, True, False]
|
||||||
|
|
||||||
|
assert theProject.closeProject() is True
|
||||||
|
|
||||||
# END Test testCoreIndex_CheckThese
|
# END Test testCoreIndex_CheckThese
|
||||||
|
|
||||||
@@ -245,7 +252,7 @@ def testCoreIndex_ScanText(nwMinimal, mockGUI):
|
|||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
theProject.projTree.setSeed(42)
|
theProject.projTree.setSeed(42)
|
||||||
assert theProject.openProject(nwMinimal)
|
assert theProject.openProject(nwMinimal) is True
|
||||||
|
|
||||||
theIndex = NWIndex(theProject)
|
theIndex = NWIndex(theProject)
|
||||||
|
|
||||||
@@ -256,25 +263,25 @@ def testCoreIndex_ScanText(nwMinimal, mockGUI):
|
|||||||
xItem.setLayout(nwItemLayout.NO_LAYOUT)
|
xItem.setLayout(nwItemLayout.NO_LAYOUT)
|
||||||
|
|
||||||
# Check invalid data
|
# Check invalid data
|
||||||
assert not theIndex.scanText(None, "Hello World!")
|
assert theIndex.scanText(None, "Hello World!") is False
|
||||||
assert not theIndex.scanText(dHandle, "Hello World!")
|
assert theIndex.scanText(dHandle, "Hello World!") is False
|
||||||
assert not theIndex.scanText(xHandle, "Hello World!")
|
assert theIndex.scanText(xHandle, "Hello World!") is False
|
||||||
|
|
||||||
xItem.setLayout(nwItemLayout.SCENE)
|
xItem.setLayout(nwItemLayout.SCENE)
|
||||||
xItem.setParent(None)
|
xItem.setParent(None)
|
||||||
assert not theIndex.scanText(xHandle, "Hello World!")
|
assert theIndex.scanText(xHandle, "Hello World!") is False
|
||||||
|
|
||||||
# Create the trash folder
|
# Create the trash folder
|
||||||
tHandle = theProject.trashFolder()
|
tHandle = theProject.trashFolder()
|
||||||
assert theProject.projTree[tHandle] is not None
|
assert theProject.projTree[tHandle] is not None
|
||||||
xItem.setParent(tHandle)
|
xItem.setParent(tHandle)
|
||||||
assert not theIndex.scanText(xHandle, "Hello World!")
|
assert theIndex.scanText(xHandle, "Hello World!") is False
|
||||||
|
|
||||||
# Create the archive root
|
# Create the archive root
|
||||||
aHandle = theProject.newRoot("Outtakes", nwItemClass.ARCHIVE)
|
aHandle = theProject.newRoot("Outtakes", nwItemClass.ARCHIVE)
|
||||||
assert theProject.projTree[aHandle] is not None
|
assert theProject.projTree[aHandle] is not None
|
||||||
xItem.setParent(aHandle)
|
xItem.setParent(aHandle)
|
||||||
assert not theIndex.scanText(xHandle, "Hello World!")
|
assert theIndex.scanText(xHandle, "Hello World!") is False
|
||||||
|
|
||||||
# Make some usable items
|
# Make some usable items
|
||||||
pHandle = theProject.newFile("Page", nwItemClass.NOVEL, "a508bb932959c")
|
pHandle = theProject.newFile("Page", nwItemClass.NOVEL, "a508bb932959c")
|
||||||
@@ -315,68 +322,42 @@ def testCoreIndex_ScanText(nwMinimal, mockGUI):
|
|||||||
"##### Title Five\n\n" # Not interpreted as a title, the hashes are counted as a word
|
"##### Title Five\n\n" # Not interpreted as a title, the hashes are counted as a word
|
||||||
"Paragraph Five.\n\n"
|
"Paragraph Five.\n\n"
|
||||||
))
|
))
|
||||||
assert theIndex._refIndex[nHandle].get("T000000", None) is not None # Always there
|
assert cHandle not in theIndex._refIndex
|
||||||
assert theIndex._refIndex[nHandle].get("T000001", None) is not None # Heading 1
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000002", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000003", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000004", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000005", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000006", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000007", None) is not None # Heading 2
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000008", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000009", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000010", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000011", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000012", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000013", None) is not None # Heading 3
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000014", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000015", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000016", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000017", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000018", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000019", None) is not None # Heading 4
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000020", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000021", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000022", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000023", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000024", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000025", None) is None
|
|
||||||
assert theIndex._refIndex[nHandle].get("T000026", None) is None
|
|
||||||
|
|
||||||
assert theIndex._novelIndex[nHandle]["T000001"]["level"] == "H1"
|
assert theIndex._fileIndex[nHandle]["T000001"]["level"] == "H1"
|
||||||
assert theIndex._novelIndex[nHandle]["T000007"]["level"] == "H2"
|
assert theIndex._fileIndex[nHandle]["T000007"]["level"] == "H2"
|
||||||
assert theIndex._novelIndex[nHandle]["T000013"]["level"] == "H3"
|
assert theIndex._fileIndex[nHandle]["T000013"]["level"] == "H3"
|
||||||
assert theIndex._novelIndex[nHandle]["T000019"]["level"] == "H4"
|
assert theIndex._fileIndex[nHandle]["T000019"]["level"] == "H4"
|
||||||
|
|
||||||
assert theIndex._novelIndex[nHandle]["T000001"]["title"] == "Title One"
|
assert theIndex._fileIndex[nHandle]["T000001"]["title"] == "Title One"
|
||||||
assert theIndex._novelIndex[nHandle]["T000007"]["title"] == "Title Two"
|
assert theIndex._fileIndex[nHandle]["T000007"]["title"] == "Title Two"
|
||||||
assert theIndex._novelIndex[nHandle]["T000013"]["title"] == "Title Three"
|
assert theIndex._fileIndex[nHandle]["T000013"]["title"] == "Title Three"
|
||||||
assert theIndex._novelIndex[nHandle]["T000019"]["title"] == "Title Four"
|
assert theIndex._fileIndex[nHandle]["T000019"]["title"] == "Title Four"
|
||||||
|
|
||||||
assert theIndex._novelIndex[nHandle]["T000001"]["layout"] == "SCENE"
|
assert theIndex._fileIndex[nHandle]["T000001"]["layout"] == "SCENE"
|
||||||
assert theIndex._novelIndex[nHandle]["T000007"]["layout"] == "SCENE"
|
assert theIndex._fileIndex[nHandle]["T000007"]["layout"] == "SCENE"
|
||||||
assert theIndex._novelIndex[nHandle]["T000013"]["layout"] == "SCENE"
|
assert theIndex._fileIndex[nHandle]["T000013"]["layout"] == "SCENE"
|
||||||
assert theIndex._novelIndex[nHandle]["T000019"]["layout"] == "SCENE"
|
assert theIndex._fileIndex[nHandle]["T000019"]["layout"] == "SCENE"
|
||||||
|
|
||||||
assert theIndex._novelIndex[nHandle]["T000001"]["synopsis"] == "Synopsis One."
|
assert theIndex._fileIndex[nHandle]["T000001"]["cCount"] == 23
|
||||||
assert theIndex._novelIndex[nHandle]["T000007"]["synopsis"] == "Synopsis Two."
|
assert theIndex._fileIndex[nHandle]["T000007"]["cCount"] == 23
|
||||||
assert theIndex._novelIndex[nHandle]["T000013"]["synopsis"] == "Synopsis Three."
|
assert theIndex._fileIndex[nHandle]["T000013"]["cCount"] == 27
|
||||||
assert theIndex._novelIndex[nHandle]["T000019"]["synopsis"] == "Synopsis Four."
|
assert theIndex._fileIndex[nHandle]["T000019"]["cCount"] == 56
|
||||||
|
|
||||||
assert theIndex._novelIndex[nHandle]["T000001"]["cCount"] == 23
|
assert theIndex._fileIndex[nHandle]["T000001"]["wCount"] == 4
|
||||||
assert theIndex._novelIndex[nHandle]["T000007"]["cCount"] == 23
|
assert theIndex._fileIndex[nHandle]["T000007"]["wCount"] == 4
|
||||||
assert theIndex._novelIndex[nHandle]["T000013"]["cCount"] == 27
|
assert theIndex._fileIndex[nHandle]["T000013"]["wCount"] == 4
|
||||||
assert theIndex._novelIndex[nHandle]["T000019"]["cCount"] == 56
|
assert theIndex._fileIndex[nHandle]["T000019"]["wCount"] == 9
|
||||||
|
|
||||||
assert theIndex._novelIndex[nHandle]["T000001"]["wCount"] == 4
|
assert theIndex._fileIndex[nHandle]["T000001"]["pCount"] == 1
|
||||||
assert theIndex._novelIndex[nHandle]["T000007"]["wCount"] == 4
|
assert theIndex._fileIndex[nHandle]["T000007"]["pCount"] == 1
|
||||||
assert theIndex._novelIndex[nHandle]["T000013"]["wCount"] == 4
|
assert theIndex._fileIndex[nHandle]["T000013"]["pCount"] == 1
|
||||||
assert theIndex._novelIndex[nHandle]["T000019"]["wCount"] == 9
|
assert theIndex._fileIndex[nHandle]["T000019"]["pCount"] == 3
|
||||||
|
|
||||||
assert theIndex._novelIndex[nHandle]["T000001"]["pCount"] == 1
|
assert theIndex._fileIndex[nHandle]["T000001"]["synopsis"] == "Synopsis One."
|
||||||
assert theIndex._novelIndex[nHandle]["T000007"]["pCount"] == 1
|
assert theIndex._fileIndex[nHandle]["T000007"]["synopsis"] == "Synopsis Two."
|
||||||
assert theIndex._novelIndex[nHandle]["T000013"]["pCount"] == 1
|
assert theIndex._fileIndex[nHandle]["T000013"]["synopsis"] == "Synopsis Three."
|
||||||
assert theIndex._novelIndex[nHandle]["T000019"]["pCount"] == 3
|
assert theIndex._fileIndex[nHandle]["T000019"]["synopsis"] == "Synopsis Four."
|
||||||
|
|
||||||
assert theIndex.scanText(cHandle, (
|
assert theIndex.scanText(cHandle, (
|
||||||
"# Title One\n\n"
|
"# Title One\n\n"
|
||||||
@@ -384,22 +365,15 @@ def testCoreIndex_ScanText(nwMinimal, mockGUI):
|
|||||||
"% synopsis: Synopsis One.\n\n"
|
"% synopsis: Synopsis One.\n\n"
|
||||||
"Paragraph One.\n\n"
|
"Paragraph One.\n\n"
|
||||||
))
|
))
|
||||||
assert theIndex._refIndex[cHandle].get("T000000", None) is not None
|
assert cHandle not in theIndex._refIndex
|
||||||
assert theIndex._refIndex[cHandle].get("T000001", None) is not None
|
|
||||||
assert theIndex._refIndex[cHandle].get("T000002", None) is None
|
|
||||||
assert theIndex._refIndex[cHandle].get("T000003", None) is None
|
|
||||||
assert theIndex._refIndex[cHandle].get("T000004", None) is None
|
|
||||||
assert theIndex._refIndex[cHandle].get("T000005", None) is None
|
|
||||||
assert theIndex._refIndex[cHandle].get("T000006", None) is None
|
|
||||||
assert theIndex._refIndex[cHandle].get("T000007", None) is None
|
|
||||||
|
|
||||||
assert theIndex._noteIndex[cHandle]["T000001"]["level"] == "H1"
|
assert theIndex._fileIndex[cHandle]["T000001"]["level"] == "H1"
|
||||||
assert theIndex._noteIndex[cHandle]["T000001"]["title"] == "Title One"
|
assert theIndex._fileIndex[cHandle]["T000001"]["title"] == "Title One"
|
||||||
assert theIndex._noteIndex[cHandle]["T000001"]["layout"] == "NOTE"
|
assert theIndex._fileIndex[cHandle]["T000001"]["layout"] == "NOTE"
|
||||||
assert theIndex._noteIndex[cHandle]["T000001"]["synopsis"] == "Synopsis One."
|
assert theIndex._fileIndex[cHandle]["T000001"]["cCount"] == 23
|
||||||
assert theIndex._noteIndex[cHandle]["T000001"]["cCount"] == 23
|
assert theIndex._fileIndex[cHandle]["T000001"]["wCount"] == 4
|
||||||
assert theIndex._noteIndex[cHandle]["T000001"]["wCount"] == 4
|
assert theIndex._fileIndex[cHandle]["T000001"]["pCount"] == 1
|
||||||
assert theIndex._noteIndex[cHandle]["T000001"]["pCount"] == 1
|
assert theIndex._fileIndex[cHandle]["T000001"]["synopsis"] == "Synopsis One."
|
||||||
|
|
||||||
assert theIndex.scanText(sHandle, (
|
assert theIndex.scanText(sHandle, (
|
||||||
"# Title One\n\n"
|
"# Title One\n\n"
|
||||||
@@ -409,7 +383,7 @@ def testCoreIndex_ScanText(nwMinimal, mockGUI):
|
|||||||
"% synopsis: Synopsis One.\n\n"
|
"% synopsis: Synopsis One.\n\n"
|
||||||
"Paragraph One.\n\n"
|
"Paragraph One.\n\n"
|
||||||
))
|
))
|
||||||
assert theIndex._refIndex[sHandle]["T000001"]["tags"] == (
|
assert theIndex._refIndex[sHandle]["T000001"] == (
|
||||||
[[3, "@pov", "One"], [5, "@char", "Two"]]
|
[[3, "@pov", "One"], [5, "@char", "Two"]]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -418,29 +392,29 @@ def testCoreIndex_ScanText(nwMinimal, mockGUI):
|
|||||||
assert theIndex.scanText(pHandle, (
|
assert theIndex.scanText(pHandle, (
|
||||||
"This is a page with some text on it.\n\n"
|
"This is a page with some text on it.\n\n"
|
||||||
))
|
))
|
||||||
assert theIndex._novelIndex[pHandle]["T000000"]["level"] == "H0"
|
assert pHandle in theIndex._fileIndex
|
||||||
assert theIndex._novelIndex[pHandle]["T000000"]["title"] == "Untitled Page"
|
assert theIndex._fileIndex[pHandle]["T000000"]["level"] == "H0"
|
||||||
assert theIndex._novelIndex[pHandle]["T000000"]["layout"] == "PAGE"
|
assert theIndex._fileIndex[pHandle]["T000000"]["title"] == ""
|
||||||
assert theIndex._novelIndex[pHandle]["T000000"]["synopsis"] == ""
|
assert theIndex._fileIndex[pHandle]["T000000"]["layout"] == "PAGE"
|
||||||
assert theIndex._novelIndex[pHandle]["T000000"]["cCount"] == 36
|
assert theIndex._fileIndex[pHandle]["T000000"]["cCount"] == 36
|
||||||
assert theIndex._novelIndex[pHandle]["T000000"]["wCount"] == 9
|
assert theIndex._fileIndex[pHandle]["T000000"]["wCount"] == 9
|
||||||
assert theIndex._novelIndex[pHandle]["T000000"]["pCount"] == 1
|
assert theIndex._fileIndex[pHandle]["T000000"]["pCount"] == 1
|
||||||
assert pHandle not in theIndex._noteIndex
|
assert theIndex._fileIndex[pHandle]["T000000"]["synopsis"] == ""
|
||||||
|
|
||||||
theProject.projTree[pHandle].itemLayout = nwItemLayout.NOTE
|
theProject.projTree[pHandle].itemLayout = nwItemLayout.NOTE
|
||||||
assert theIndex.scanText(pHandle, (
|
assert theIndex.scanText(pHandle, (
|
||||||
"This is a page with some text on it.\n\n"
|
"This is a page with some text on it.\n\n"
|
||||||
))
|
))
|
||||||
assert theIndex._noteIndex[pHandle]["T000000"]["level"] == "H0"
|
assert pHandle in theIndex._fileIndex
|
||||||
assert theIndex._noteIndex[pHandle]["T000000"]["title"] == "Untitled Page"
|
assert theIndex._fileIndex[pHandle]["T000000"]["level"] == "H0"
|
||||||
assert theIndex._noteIndex[pHandle]["T000000"]["layout"] == "NOTE"
|
assert theIndex._fileIndex[pHandle]["T000000"]["title"] == ""
|
||||||
assert theIndex._noteIndex[pHandle]["T000000"]["synopsis"] == ""
|
assert theIndex._fileIndex[pHandle]["T000000"]["layout"] == "NOTE"
|
||||||
assert theIndex._noteIndex[pHandle]["T000000"]["cCount"] == 36
|
assert theIndex._fileIndex[pHandle]["T000000"]["cCount"] == 36
|
||||||
assert theIndex._noteIndex[pHandle]["T000000"]["wCount"] == 9
|
assert theIndex._fileIndex[pHandle]["T000000"]["wCount"] == 9
|
||||||
assert theIndex._noteIndex[pHandle]["T000000"]["pCount"] == 1
|
assert theIndex._fileIndex[pHandle]["T000000"]["pCount"] == 1
|
||||||
assert pHandle not in theIndex._novelIndex
|
assert theIndex._fileIndex[pHandle]["T000000"]["synopsis"] == ""
|
||||||
|
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
|
|
||||||
# END Test testCoreIndex_ScanText
|
# END Test testCoreIndex_ScanText
|
||||||
|
|
||||||
@@ -451,7 +425,7 @@ def testCoreIndex_ExtractData(nwMinimal, mockGUI):
|
|||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
theProject.projTree.setSeed(42)
|
theProject.projTree.setSeed(42)
|
||||||
assert theProject.openProject(nwMinimal)
|
assert theProject.openProject(nwMinimal) is True
|
||||||
|
|
||||||
theIndex = NWIndex(theProject)
|
theIndex = NWIndex(theProject)
|
||||||
nHandle = theProject.newFile("Hello", nwItemClass.NOVEL, "a508bb932959c")
|
nHandle = theProject.newFile("Hello", nwItemClass.NOVEL, "a508bb932959c")
|
||||||
@@ -753,10 +727,8 @@ def testCoreIndex_CheckRefIndex(mockGUI):
|
|||||||
# Valid Index
|
# Valid Index
|
||||||
theIndex._refIndex = {
|
theIndex._refIndex = {
|
||||||
"6a2d6d5f4f401": {
|
"6a2d6d5f4f401": {
|
||||||
"T000000": {"tags": [], "updated": 1611922868},
|
"T000000": [],
|
||||||
"T000001": {"tags": [
|
"T000001": [[3, "@pov", "Jane"], [4, "@location", "Earth"]],
|
||||||
[3, "@pov", "Jane"], [4, "@location", "Earth"]
|
|
||||||
], "updated": 1611922868}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert theIndex._checkRefIndex() is None
|
assert theIndex._checkRefIndex() is None
|
||||||
@@ -764,10 +736,8 @@ def testCoreIndex_CheckRefIndex(mockGUI):
|
|||||||
# Invalid Handle
|
# Invalid Handle
|
||||||
theIndex._refIndex = {
|
theIndex._refIndex = {
|
||||||
"Ha2d6d5f4f401": {
|
"Ha2d6d5f4f401": {
|
||||||
"T000000": {"tags": [], "updated": 1611922868},
|
"T000000": [],
|
||||||
"T000001": {"tags": [
|
"T000001": [[3, "@pov", "Jane"], [4, "@location", "Earth"]],
|
||||||
[3, "@pov", "Jane"], [4, "@location", "Earth"]
|
|
||||||
], "updated": 1611922868}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
@@ -776,88 +746,48 @@ def testCoreIndex_CheckRefIndex(mockGUI):
|
|||||||
# Invalid Title
|
# Invalid Title
|
||||||
theIndex._refIndex = {
|
theIndex._refIndex = {
|
||||||
"6a2d6d5f4f401": {
|
"6a2d6d5f4f401": {
|
||||||
"T000000": {"tags": [], "updated": 1611922868},
|
"T000000": [],
|
||||||
"INVALID": {"tags": [
|
"INVALID": [[3, "@pov", "Jane"], [4, "@location", "Earth"]],
|
||||||
[3, "@pov", "Jane"], [4, "@location", "Earth"]
|
|
||||||
], "updated": 1611922868}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
theIndex._checkRefIndex()
|
theIndex._checkRefIndex()
|
||||||
|
|
||||||
# Missing 'tags'
|
# Wrong Length
|
||||||
theIndex._refIndex = {
|
theIndex._refIndex = {
|
||||||
"6a2d6d5f4f401": {
|
"6a2d6d5f4f401": {
|
||||||
"T000000": {"tags": [], "updated": 1611922868},
|
"T000000": [],
|
||||||
"T000001": {"updated": 1611922868}
|
"T000001": [[3, "@pov", "Jane"], [4, "@location", "Earth", "Stuff"]],
|
||||||
}
|
|
||||||
}
|
|
||||||
with pytest.raises(KeyError):
|
|
||||||
theIndex._checkRefIndex()
|
|
||||||
|
|
||||||
# Wrong Length of 'tags'
|
|
||||||
theIndex._refIndex = {
|
|
||||||
"6a2d6d5f4f401": {
|
|
||||||
"T000000": {"tags": [], "updated": 1611922868},
|
|
||||||
"T000001": {"tags": [
|
|
||||||
[3, "@pov", "Jane"], [4, "@location", "Earth", "Stuff"]
|
|
||||||
], "updated": 1611922868}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(IndexError):
|
with pytest.raises(IndexError):
|
||||||
theIndex._checkRefIndex()
|
theIndex._checkRefIndex()
|
||||||
|
|
||||||
# Wrong Type of 'tags' Entry 0
|
# Wrong Type of Entry 0
|
||||||
theIndex._refIndex = {
|
theIndex._refIndex = {
|
||||||
"6a2d6d5f4f401": {
|
"6a2d6d5f4f401": {
|
||||||
"T000000": {"tags": [], "updated": 1611922868},
|
"T000000": [],
|
||||||
"T000001": {"tags": [
|
"T000001": [[3, "@pov", "Jane"], ["4", "@location", "Earth"]],
|
||||||
[3, "@pov", "Jane"], ["4", "@location", "Earth"]
|
|
||||||
], "updated": 1611922868}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
theIndex._checkRefIndex()
|
theIndex._checkRefIndex()
|
||||||
|
|
||||||
# Wrong Type of 'tags' Entry 1
|
# Wrong Type of Entry 1
|
||||||
theIndex._refIndex = {
|
theIndex._refIndex = {
|
||||||
"6a2d6d5f4f401": {
|
"6a2d6d5f4f401": {
|
||||||
"T000000": {"tags": [], "updated": 1611922868},
|
"T000000": [],
|
||||||
"T000001": {"tags": [
|
"T000001": [[3, "@pov", "Jane"], [4, "@stuff", "Earth"]],
|
||||||
[3, "@pov", "Jane"], [4, "@stuff", "Earth"]
|
|
||||||
], "updated": 1611922868}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
theIndex._checkRefIndex()
|
theIndex._checkRefIndex()
|
||||||
|
|
||||||
# Wrong Type of 'tags' Entry 1
|
# Wrong Type of Entry 2
|
||||||
theIndex._refIndex = {
|
theIndex._refIndex = {
|
||||||
"6a2d6d5f4f401": {
|
"6a2d6d5f4f401": {
|
||||||
"T000000": {"tags": [], "updated": 1611922868},
|
"T000000": [],
|
||||||
"T000001": {"tags": [
|
"T000001": [[3, "@pov", "Jane"], [4, "@location", 123456]],
|
||||||
[3, "@pov", "Jane"], [4, "@location", 123456]
|
|
||||||
], "updated": 1611922868}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
theIndex._checkRefIndex()
|
|
||||||
|
|
||||||
# Missing 'updated'
|
|
||||||
theIndex._refIndex = {
|
|
||||||
"6a2d6d5f4f401": {
|
|
||||||
"T000000": {"tags": [], "updated": 1611922868},
|
|
||||||
"T000001": {"tags": []}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
with pytest.raises(KeyError):
|
|
||||||
theIndex._checkRefIndex()
|
|
||||||
|
|
||||||
# Wrong Type of 'updated' Entry 1
|
|
||||||
theIndex._refIndex = {
|
|
||||||
"6a2d6d5f4f401": {
|
|
||||||
"T000000": {"tags": [], "updated": 1611922868},
|
|
||||||
"T000001": {"tags": [], "updated": "1611922868"}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
@@ -874,253 +804,317 @@ def testCoreIndex_CheckNovelNoteIndex(mockGUI):
|
|||||||
theIndex = NWIndex(theProject)
|
theIndex = NWIndex(theProject)
|
||||||
|
|
||||||
# Valid Index
|
# Valid Index
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "updated": 1611922868
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
theIndex._noteIndex = theIndex._novelIndex.copy()
|
theIndex._fileIndex = theIndex._fileIndex.copy()
|
||||||
assert theIndex._checkNovelNoteIndex("novelIndex") is None
|
assert theIndex._checkFileIndex() is None
|
||||||
assert theIndex._checkNovelNoteIndex("noteIndex") is None
|
|
||||||
with pytest.raises(IndexError):
|
|
||||||
theIndex._checkNovelNoteIndex("notAnIndex")
|
|
||||||
|
|
||||||
# Invalid Handle
|
# Invalid Handle
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"H3b69b83cdafc": {
|
"H3b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "updated": 1611922868
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Invalid Title
|
# Invalid Title
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"INVALID": {
|
"INVALID": {
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "updated": 1611922868
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Wrong Length
|
# Wrong Length
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "updated": 1611922868, "stuff": None
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
|
"stuff": None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(IndexError):
|
with pytest.raises(IndexError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Missing Keys
|
# Missing Keys
|
||||||
# ============
|
# ============
|
||||||
|
|
||||||
# Missing 'level'
|
# Missing 'level'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"stuff": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"stuff": "H1",
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "updated": 1611922868
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Missing 'title'
|
# Missing 'title'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "stuff": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "updated": 1611922868
|
"stuff": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Missing 'layout'
|
# Missing 'layout'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": "My Novel", "stuff": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "updated": 1611922868
|
"title": "My Novel",
|
||||||
|
"stuff": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Missing 'synopsis'
|
|
||||||
theIndex._novelIndex = {
|
|
||||||
"53b69b83cdafc": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "stuff": "text",
|
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "updated": 1611922868
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
with pytest.raises(KeyError):
|
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
|
||||||
|
|
||||||
# Missing 'cCount'
|
# Missing 'cCount'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"stuff": 72, "wCount": 15, "pCount": 2, "updated": 1611922868
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"stuff": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Missing 'wCount'
|
# Missing 'wCount'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "stuff": 15, "pCount": 2, "updated": 1611922868
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"stuff": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Missing 'pCount'
|
# Missing 'pCount'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "wCount": 15, "stuff": 2, "updated": 1611922868
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"stuff": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Missing 'updated'
|
# Missing 'synopsis'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "stuff": 1611922868
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"stuff": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Wrong Types
|
# Wrong Types
|
||||||
# ===========
|
# ===========
|
||||||
|
|
||||||
# Wrong Type for 'level'
|
# Wrong Type for 'level'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "XX", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "XX",
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "updated": 1611922868
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Wrong Type for 'title'
|
# Wrong Type for 'title'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": 12345678, "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "updated": 1611922868
|
"title": 12345678,
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Wrong Type for 'layout'
|
# Wrong Type for 'layout'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": "My Novel", "layout": "INVALID", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "updated": 1611922868
|
"title": "My Novel",
|
||||||
|
"layout": "INVALID",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Wrong Type for 'synopsis'
|
|
||||||
theIndex._novelIndex = {
|
|
||||||
"53b69b83cdafc": {
|
|
||||||
"T000001": {
|
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": 123456,
|
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "updated": 1611922868
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
|
||||||
|
|
||||||
# Wrong Type for 'cCount'
|
# Wrong Type for 'cCount'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": "72", "wCount": 15, "pCount": 2, "updated": 1611922868
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": "72",
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Wrong Type for 'wCount'
|
# Wrong Type for 'wCount'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "wCount": "15", "pCount": 2, "updated": 1611922868
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": "15",
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Wrong Type for 'pCount'
|
# Wrong Type for 'pCount'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "wCount": 15, "pCount": "2", "updated": 1611922868
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": "2",
|
||||||
|
"synopsis": "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# Wrong Type for 'updated'
|
# Wrong Type for 'synopsis'
|
||||||
theIndex._novelIndex = {
|
theIndex._fileIndex = {
|
||||||
"53b69b83cdafc": {
|
"53b69b83cdafc": {
|
||||||
"T000001": {
|
"T000001": {
|
||||||
"level": "H1", "title": "My Novel", "layout": "TITLE", "synopsis": "text",
|
"level": "H1",
|
||||||
"cCount": 72, "wCount": 15, "pCount": 2, "updated": "1611922868"
|
"title": "My Novel",
|
||||||
|
"layout": "TITLE",
|
||||||
|
"cCount": 72,
|
||||||
|
"wCount": 15,
|
||||||
|
"pCount": 2,
|
||||||
|
"synopsis": 123456,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
theIndex._checkNovelNoteIndex("novelIndex")
|
theIndex._checkFileIndex()
|
||||||
|
|
||||||
# END Test testCoreIndex_CheckNovelNoteIndex
|
# END Test testCoreIndex_CheckNovelNoteIndex
|
||||||
|
|
||||||
|
|||||||
@@ -1175,7 +1175,7 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Select the Word "est"
|
# Select the Word "est"
|
||||||
assert nwGUI.docEditor.setCursorPosition(618)
|
assert nwGUI.docEditor.setCursorPosition(630)
|
||||||
nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
|
nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
|
||||||
theCursor = nwGUI.docEditor.textCursor()
|
theCursor = nwGUI.docEditor.textCursor()
|
||||||
assert theCursor.selectedText() == "est"
|
assert theCursor.selectedText() == "est"
|
||||||
@@ -1188,11 +1188,11 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
# Find Next by Enter
|
# Find Next by Enter
|
||||||
monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: True)
|
monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: True)
|
||||||
qtbot.keyClick(nwGUI.docEditor.docSearch.searchBox, Qt.Key_Return, delay=keyDelay)
|
qtbot.keyClick(nwGUI.docEditor.docSearch.searchBox, Qt.Key_Return, delay=keyDelay)
|
||||||
assert abs(nwGUI.docEditor.getCursorPosition() - 1272) < 3
|
assert abs(nwGUI.docEditor.getCursorPosition() - 1284) < 3
|
||||||
|
|
||||||
# Find Next by Button
|
# Find Next by Button
|
||||||
qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
|
qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
|
||||||
assert abs(nwGUI.docEditor.getCursorPosition() - 1486) < 3
|
assert abs(nwGUI.docEditor.getCursorPosition() - 1498) < 3
|
||||||
|
|
||||||
# Activate Loop Search
|
# Activate Loop Search
|
||||||
nwGUI.docEditor.docSearch.toggleLoop.activate(QAction.Trigger)
|
nwGUI.docEditor.docSearch.toggleLoop.activate(QAction.Trigger)
|
||||||
@@ -1201,17 +1201,17 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
|
|
||||||
# Find Next by Menu Search > Find Next
|
# Find Next by Menu Search > Find Next
|
||||||
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
||||||
assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3
|
assert abs(nwGUI.docEditor.getCursorPosition() - 632) < 3
|
||||||
|
|
||||||
# Close Search
|
# Close Search
|
||||||
nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger)
|
nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger)
|
||||||
assert not nwGUI.docEditor.docSearch.isVisible()
|
assert nwGUI.docEditor.docSearch.isVisible() is False
|
||||||
assert nwGUI.docEditor.setCursorPosition(15)
|
assert nwGUI.docEditor.setCursorPosition(15)
|
||||||
|
|
||||||
# Toggle Search Again with Header Button
|
# Toggle Search Again with Header Button
|
||||||
qtbot.mouseClick(nwGUI.docEditor.docHeader.searchButton, Qt.LeftButton, delay=keyDelay)
|
qtbot.mouseClick(nwGUI.docEditor.docHeader.searchButton, Qt.LeftButton, delay=keyDelay)
|
||||||
assert nwGUI.docEditor.docSearch.setSearchText("")
|
assert nwGUI.docEditor.docSearch.setSearchText("")
|
||||||
assert nwGUI.docEditor.docSearch.isVisible()
|
assert nwGUI.docEditor.docSearch.isVisible() is True
|
||||||
|
|
||||||
# Enable RegEx Search
|
# Enable RegEx Search
|
||||||
nwGUI.docEditor.docSearch.toggleRegEx.activate(QAction.Trigger)
|
nwGUI.docEditor.docSearch.toggleRegEx.activate(QAction.Trigger)
|
||||||
@@ -1226,13 +1226,13 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
# Set Valid RegEx
|
# Set Valid RegEx
|
||||||
assert nwGUI.docEditor.docSearch.setSearchText(r"\bSus")
|
assert nwGUI.docEditor.docSearch.setSearchText(r"\bSus")
|
||||||
qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
|
qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)
|
||||||
assert abs(nwGUI.docEditor.getCursorPosition() - 196) < 3
|
assert abs(nwGUI.docEditor.getCursorPosition() - 208) < 3
|
||||||
|
|
||||||
# Find Next and then Prev
|
# Find Next and then Prev
|
||||||
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
||||||
assert abs(nwGUI.docEditor.getCursorPosition() - 297) < 3
|
assert abs(nwGUI.docEditor.getCursorPosition() - 309) < 3
|
||||||
nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger)
|
||||||
assert abs(nwGUI.docEditor.getCursorPosition() - 196) < 3
|
assert abs(nwGUI.docEditor.getCursorPosition() - 208) < 3
|
||||||
|
|
||||||
# Make RegEx Case Sensitive
|
# Make RegEx Case Sensitive
|
||||||
nwGUI.docEditor.docSearch.toggleCase.activate(QAction.Trigger)
|
nwGUI.docEditor.docSearch.toggleCase.activate(QAction.Trigger)
|
||||||
@@ -1241,9 +1241,9 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
|
|
||||||
# Find Next (One Result)
|
# Find Next (One Result)
|
||||||
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
||||||
assert abs(nwGUI.docEditor.getCursorPosition() - 599) < 3
|
assert abs(nwGUI.docEditor.getCursorPosition() - 611) < 3
|
||||||
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
||||||
assert abs(nwGUI.docEditor.getCursorPosition() - 599) < 3
|
assert abs(nwGUI.docEditor.getCursorPosition() - 611) < 3
|
||||||
|
|
||||||
# Trigger Replace
|
# Trigger Replace
|
||||||
nwGUI.mainMenu.aReplace.activate(QAction.Trigger)
|
nwGUI.mainMenu.aReplace.activate(QAction.Trigger)
|
||||||
@@ -1261,14 +1261,14 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
|
|
||||||
# Replace "Sus" with "Foo" via Menu
|
# Replace "Sus" with "Foo" via Menu
|
||||||
nwGUI.mainMenu.aReplaceNext.activate(QAction.Trigger)
|
nwGUI.mainMenu.aReplaceNext.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[596:607] == "Foopendisse"
|
assert nwGUI.docEditor.getText()[608:619] == "Foopendisse"
|
||||||
|
|
||||||
# Find Next to Loop File
|
# Find Next to Loop File
|
||||||
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
||||||
|
|
||||||
# Replace "sus" with "foo" via Replace Button
|
# Replace "sus" with "foo" via Replace Button
|
||||||
qtbot.mouseClick(nwGUI.docEditor.docSearch.replaceButton, Qt.LeftButton, delay=keyDelay)
|
qtbot.mouseClick(nwGUI.docEditor.docSearch.replaceButton, Qt.LeftButton, delay=keyDelay)
|
||||||
assert nwGUI.docEditor.getText()[193:201] == "foocipit"
|
assert nwGUI.docEditor.getText()[205:213] == "foocipit"
|
||||||
|
|
||||||
# Revert Last Two Replaces
|
# Revert Last Two Replaces
|
||||||
assert nwGUI.docEditor.docAction(nwDocAction.UNDO)
|
assert nwGUI.docEditor.docAction(nwDocAction.UNDO)
|
||||||
@@ -1282,7 +1282,7 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
|
|
||||||
# Close Search and Select "est" Again
|
# Close Search and Select "est" Again
|
||||||
nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger)
|
nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.setCursorPosition(618)
|
assert nwGUI.docEditor.setCursorPosition(630)
|
||||||
nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
|
nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
|
||||||
theCursor = nwGUI.docEditor.textCursor()
|
theCursor = nwGUI.docEditor.textCursor()
|
||||||
assert theCursor.selectedText() == "est"
|
assert theCursor.selectedText() == "est"
|
||||||
@@ -1299,9 +1299,9 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
|
|
||||||
# Only One Match
|
# Only One Match
|
||||||
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
||||||
assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3
|
assert abs(nwGUI.docEditor.getCursorPosition() - 632) < 3
|
||||||
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
|
||||||
assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3
|
assert abs(nwGUI.docEditor.getCursorPosition() - 632) < 3
|
||||||
|
|
||||||
# Enable Next Doc Search
|
# Enable Next Doc Search
|
||||||
nwGUI.docEditor.docSearch.toggleProject.activate(QAction.Trigger)
|
nwGUI.docEditor.docSearch.toggleProject.activate(QAction.Trigger)
|
||||||
|
|||||||
@@ -54,35 +54,35 @@ def testGuiMenu_EditFormat(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
|
|
||||||
# Split By Chapter
|
# Split By Chapter
|
||||||
assert nwGUI.openDocument("4c4f28287af27") is True
|
assert nwGUI.openDocument("4c4f28287af27") is True
|
||||||
assert nwGUI.docEditor.setCursorPosition(30) is True
|
assert nwGUI.docEditor.setCursorPosition(42) is True
|
||||||
|
|
||||||
cleanText = nwGUI.docEditor.getText()[27:74]
|
cleanText = nwGUI.docEditor.getText()[39:86]
|
||||||
|
|
||||||
# Bold
|
# Bold
|
||||||
nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
|
||||||
fmtStr = "**Pellentesque** nec erat ut nulla posuere commodo."
|
fmtStr = "**Pellentesque** nec erat ut nulla posuere commodo."
|
||||||
assert nwGUI.docEditor.getText()[27:78] == fmtStr
|
assert nwGUI.docEditor.getText()[39:90] == fmtStr
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:74] == cleanText
|
assert nwGUI.docEditor.getText()[39:86] == cleanText
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Italic
|
# Italic
|
||||||
nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
|
||||||
fmtStr = "_Pellentesque_ nec erat ut nulla posuere commodo."
|
fmtStr = "_Pellentesque_ nec erat ut nulla posuere commodo."
|
||||||
assert nwGUI.docEditor.getText()[27:76] == fmtStr
|
assert nwGUI.docEditor.getText()[39:88] == fmtStr
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:74] == cleanText
|
assert nwGUI.docEditor.getText()[39:86] == cleanText
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Strikethrough
|
# Strikethrough
|
||||||
nwGUI.mainMenu.aFmtStrike.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtStrike.activate(QAction.Trigger)
|
||||||
fmtStr = "~~Pellentesque~~ nec erat ut nulla posuere commodo."
|
fmtStr = "~~Pellentesque~~ nec erat ut nulla posuere commodo."
|
||||||
assert nwGUI.docEditor.getText()[27:78] == fmtStr
|
assert nwGUI.docEditor.getText()[39:90] == fmtStr
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
nwGUI.mainMenu.aFmtStrike.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtStrike.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:74] == cleanText
|
assert nwGUI.docEditor.getText()[39:86] == cleanText
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Should get us back to plain
|
# Should get us back to plain
|
||||||
@@ -93,122 +93,122 @@ def testGuiMenu_EditFormat(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtEmph.activate(QAction.Trigger)
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtStrong.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:74] == cleanText
|
assert nwGUI.docEditor.getText()[39:86] == cleanText
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Double Quotes
|
# Double Quotes
|
||||||
nwGUI.mainMenu.aFmtDQuote.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtDQuote.activate(QAction.Trigger)
|
||||||
fmtStr = "“Pellentesque” nec erat ut nulla posuere commodo."
|
fmtStr = "“Pellentesque” nec erat ut nulla posuere commodo."
|
||||||
assert nwGUI.docEditor.getText()[27:76] == fmtStr
|
assert nwGUI.docEditor.getText()[39:88] == fmtStr
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
|
nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:74] == cleanText
|
assert nwGUI.docEditor.getText()[39:86] == cleanText
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Single Quotes
|
# Single Quotes
|
||||||
nwGUI.mainMenu.aFmtSQuote.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtSQuote.activate(QAction.Trigger)
|
||||||
fmtStr = "‘Pellentesque’ nec erat ut nulla posuere commodo."
|
fmtStr = "‘Pellentesque’ nec erat ut nulla posuere commodo."
|
||||||
assert nwGUI.docEditor.getText()[27:76] == fmtStr
|
assert nwGUI.docEditor.getText()[39:88] == fmtStr
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
|
nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:74] == cleanText
|
assert nwGUI.docEditor.getText()[39:86] == cleanText
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Block Formats
|
# Block Formats
|
||||||
# =============
|
# =============
|
||||||
assert nwGUI.docEditor.setCursorPosition(30)
|
assert nwGUI.docEditor.setCursorPosition(42)
|
||||||
|
|
||||||
# Header 1
|
# Header 1
|
||||||
nwGUI.mainMenu.aFmtHead1.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtHead1.activate(QAction.Trigger)
|
||||||
fmtStr = "# Pellentesque nec erat ut nulla posuere commodo."
|
fmtStr = "# Pellentesque nec erat ut nulla posuere commodo."
|
||||||
assert nwGUI.docEditor.getText()[27:76] == fmtStr
|
assert nwGUI.docEditor.getText()[39:88] == fmtStr
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Header 2
|
# Header 2
|
||||||
nwGUI.mainMenu.aFmtHead2.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtHead2.activate(QAction.Trigger)
|
||||||
fmtStr = "## Pellentesque nec erat ut nulla posuere commodo."
|
fmtStr = "## Pellentesque nec erat ut nulla posuere commodo."
|
||||||
assert nwGUI.docEditor.getText()[27:77] == fmtStr
|
assert nwGUI.docEditor.getText()[39:89] == fmtStr
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Header 3
|
# Header 3
|
||||||
nwGUI.mainMenu.aFmtHead3.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtHead3.activate(QAction.Trigger)
|
||||||
fmtStr = "### Pellentesque nec erat ut nulla posuere commodo."
|
fmtStr = "### Pellentesque nec erat ut nulla posuere commodo."
|
||||||
assert nwGUI.docEditor.getText()[27:78] == fmtStr
|
assert nwGUI.docEditor.getText()[39:90] == fmtStr
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Header 4
|
# Header 4
|
||||||
nwGUI.mainMenu.aFmtHead4.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtHead4.activate(QAction.Trigger)
|
||||||
fmtStr = "#### Pellentesque nec erat ut nulla posuere commodo."
|
fmtStr = "#### Pellentesque nec erat ut nulla posuere commodo."
|
||||||
assert nwGUI.docEditor.getText()[27:79] == fmtStr
|
assert nwGUI.docEditor.getText()[39:91] == fmtStr
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Clear Format
|
# Clear Format
|
||||||
nwGUI.mainMenu.aFmtNoFormat.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtNoFormat.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:74] == cleanText
|
assert nwGUI.docEditor.getText()[39:86] == cleanText
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Comment On
|
# Comment On
|
||||||
nwGUI.mainMenu.aFmtComment.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtComment.activate(QAction.Trigger)
|
||||||
fmtStr = "% Pellentesque nec erat ut nulla posuere commodo."
|
fmtStr = "% Pellentesque nec erat ut nulla posuere commodo."
|
||||||
assert nwGUI.docEditor.getText()[27:76] == fmtStr
|
assert nwGUI.docEditor.getText()[39:88] == fmtStr
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Comment Off
|
# Comment Off
|
||||||
nwGUI.mainMenu.aFmtComment.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtComment.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:74] == cleanText
|
assert nwGUI.docEditor.getText()[39:86] == cleanText
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Check comment with no space before text
|
# Check comment with no space before text
|
||||||
assert nwGUI.docEditor.setCursorPosition(27)
|
assert nwGUI.docEditor.setCursorPosition(39)
|
||||||
assert nwGUI.docEditor.insertText("%")
|
assert nwGUI.docEditor.insertText("%")
|
||||||
fmtStr = "%Pellentesque nec erat ut nulla posuere commodo."
|
fmtStr = "%Pellentesque nec erat ut nulla posuere commodo."
|
||||||
assert nwGUI.docEditor.getText()[27:75] == fmtStr
|
assert nwGUI.docEditor.getText()[39:87] == fmtStr
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
nwGUI.mainMenu.aFmtNoFormat.activate(QAction.Trigger)
|
nwGUI.mainMenu.aFmtNoFormat.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:74] == cleanText
|
assert nwGUI.docEditor.getText()[39:86] == cleanText
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Undo/Redo
|
# Undo/Redo
|
||||||
nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
|
nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
|
||||||
fmtStr = "%Pellentesque nec erat ut nulla posuere commodo."
|
fmtStr = "%Pellentesque nec erat ut nulla posuere commodo."
|
||||||
assert nwGUI.docEditor.getText()[27:75] == fmtStr
|
assert nwGUI.docEditor.getText()[39:87] == fmtStr
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
nwGUI.mainMenu.aEditRedo.activate(QAction.Trigger)
|
nwGUI.mainMenu.aEditRedo.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:74] == cleanText
|
assert nwGUI.docEditor.getText()[39:86] == cleanText
|
||||||
qtbot.wait(stepDelay)
|
qtbot.wait(stepDelay)
|
||||||
|
|
||||||
# Cut, Copy and Paste
|
# Cut, Copy and Paste
|
||||||
assert nwGUI.docEditor.setCursorPosition(27)
|
assert nwGUI.docEditor.setCursorPosition(39)
|
||||||
nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
|
nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
|
||||||
|
|
||||||
nwGUI.mainMenu.aEditCut.activate(QAction.Trigger)
|
nwGUI.mainMenu.aEditCut.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:77] == (
|
assert nwGUI.docEditor.getText()[39:89] == (
|
||||||
" nec erat ut nulla posuere commodo. Curabitur nisi"
|
" nec erat ut nulla posuere commodo. Curabitur nisi"
|
||||||
)
|
)
|
||||||
|
|
||||||
nwGUI.mainMenu.aEditPaste.activate(QAction.Trigger)
|
nwGUI.mainMenu.aEditPaste.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:77] == (
|
assert nwGUI.docEditor.getText()[39:89] == (
|
||||||
"Pellentesque nec erat ut nulla posuere commodo. Cu"
|
"Pellentesque nec erat ut nulla posuere commodo. Cu"
|
||||||
)
|
)
|
||||||
|
|
||||||
assert nwGUI.docEditor.setCursorPosition(27)
|
assert nwGUI.docEditor.setCursorPosition(39)
|
||||||
nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
|
nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
|
||||||
|
|
||||||
nwGUI.mainMenu.aEditCopy.activate(QAction.Trigger)
|
nwGUI.mainMenu.aEditCopy.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:77] == (
|
assert nwGUI.docEditor.getText()[39:89] == (
|
||||||
"Pellentesque nec erat ut nulla posuere commodo. Cu"
|
"Pellentesque nec erat ut nulla posuere commodo. Cu"
|
||||||
)
|
)
|
||||||
|
|
||||||
assert nwGUI.docEditor.setCursorPosition(27)
|
assert nwGUI.docEditor.setCursorPosition(39)
|
||||||
nwGUI.mainMenu.aEditPaste.activate(QAction.Trigger)
|
nwGUI.mainMenu.aEditPaste.activate(QAction.Trigger)
|
||||||
assert nwGUI.docEditor.getText()[27:77] == (
|
assert nwGUI.docEditor.getText()[39:89] == (
|
||||||
"PellentesquePellentesque nec erat ut nulla posuere"
|
"PellentesquePellentesque nec erat ut nulla posuere"
|
||||||
)
|
)
|
||||||
nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
|
nwGUI.mainMenu.aEditUndo.activate(QAction.Trigger)
|
||||||
|
|
||||||
# Select Paragraph/All
|
# Select Paragraph/All
|
||||||
assert nwGUI.docEditor.setCursorPosition(30)
|
assert nwGUI.docEditor.setCursorPosition(42)
|
||||||
nwGUI.mainMenu.aSelectPar.activate(QAction.Trigger)
|
nwGUI.mainMenu.aSelectPar.activate(QAction.Trigger)
|
||||||
theCursor = nwGUI.docEditor.textCursor()
|
theCursor = nwGUI.docEditor.textCursor()
|
||||||
assert theCursor.selectedText() == (
|
assert theCursor.selectedText() == (
|
||||||
@@ -221,10 +221,10 @@ def testGuiMenu_EditFormat(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
"nunc lacus, imperdiet nec posuere ac, interdum non lectus."
|
"nunc lacus, imperdiet nec posuere ac, interdum non lectus."
|
||||||
)
|
)
|
||||||
|
|
||||||
assert nwGUI.docEditor.setCursorPosition(30)
|
assert nwGUI.docEditor.setCursorPosition(42)
|
||||||
nwGUI.mainMenu.aSelectAll.activate(QAction.Trigger)
|
nwGUI.mainMenu.aSelectAll.activate(QAction.Trigger)
|
||||||
theCursor = nwGUI.docEditor.textCursor()
|
theCursor = nwGUI.docEditor.textCursor()
|
||||||
assert len(theCursor.selectedText()) == 1883
|
assert len(theCursor.selectedText()) == 1895
|
||||||
|
|
||||||
# Clear the Text
|
# Clear the Text
|
||||||
nwGUI.docEditor.clear()
|
nwGUI.docEditor.clear()
|
||||||
@@ -388,7 +388,7 @@ def testGuiMenu_ContextMenus(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
|
|
||||||
# Editor Context Menu
|
# Editor Context Menu
|
||||||
theCursor = nwGUI.docEditor.textCursor()
|
theCursor = nwGUI.docEditor.textCursor()
|
||||||
theCursor.setPosition(100)
|
theCursor.setPosition(112)
|
||||||
nwGUI.docEditor.setTextCursor(theCursor)
|
nwGUI.docEditor.setTextCursor(theCursor)
|
||||||
theRect = nwGUI.docEditor.cursorRect()
|
theRect = nwGUI.docEditor.cursorRect()
|
||||||
|
|
||||||
@@ -415,7 +415,7 @@ def testGuiMenu_ContextMenus(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
assert nwGUI.viewDocument("4c4f28287af27")
|
assert nwGUI.viewDocument("4c4f28287af27")
|
||||||
|
|
||||||
theCursor = nwGUI.docViewer.textCursor()
|
theCursor = nwGUI.docViewer.textCursor()
|
||||||
theCursor.setPosition(100)
|
theCursor.setPosition(112)
|
||||||
nwGUI.docViewer.setTextCursor(theCursor)
|
nwGUI.docViewer.setTextCursor(theCursor)
|
||||||
theRect = nwGUI.docViewer.cursorRect()
|
theRect = nwGUI.docViewer.cursorRect()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user