Refactor core and base classes (#931)
* Improve the NWIndex class * Improve the NWItem and NWDoc classes * Make some optimisations in projects and update tests * Minor changes to string formatting in main source file * Add some more protection to core classes * Make all converter class attributes private
This commit is contained in:
committed by
GitHub
parent
2f75d88694
commit
5e2ab4f612
+7
-11
@@ -110,7 +110,7 @@ CONFIG = Config()
|
|||||||
|
|
||||||
|
|
||||||
def main(sysArgs=None):
|
def main(sysArgs=None):
|
||||||
"""Parse command line, set up logging, and launches main GUI.
|
"""Parse command line, set up logging, and launch main GUI.
|
||||||
"""
|
"""
|
||||||
if sysArgs is None:
|
if sysArgs is None:
|
||||||
sysArgs = sys.argv[1:]
|
sysArgs = sys.argv[1:]
|
||||||
@@ -130,8 +130,8 @@ def main(sysArgs=None):
|
|||||||
]
|
]
|
||||||
|
|
||||||
helpMsg = (
|
helpMsg = (
|
||||||
"novelWriter {version} ({date})\n"
|
f"novelWriter {__version__} ({__date__})\n"
|
||||||
"{copyright}\n"
|
f"{__copyright__}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This program is distributed in the hope that it will be useful,\n"
|
"This program is distributed in the hope that it will be useful,\n"
|
||||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||||
@@ -147,10 +147,6 @@ def main(sysArgs=None):
|
|||||||
" --style= Sets Qt5 style flag. Defaults to 'Fusion'.\n"
|
" --style= Sets Qt5 style flag. Defaults to 'Fusion'.\n"
|
||||||
" --config= Alternative config file.\n"
|
" --config= Alternative config file.\n"
|
||||||
" --data= Alternative user data path.\n"
|
" --data= Alternative user data path.\n"
|
||||||
).format(
|
|
||||||
version=__version__,
|
|
||||||
copyright=__copyright__,
|
|
||||||
date=__date__,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Defaults
|
# Defaults
|
||||||
@@ -165,9 +161,9 @@ def main(sysArgs=None):
|
|||||||
# Parse Options
|
# Parse Options
|
||||||
try:
|
try:
|
||||||
inOpts, inRemain = getopt.getopt(sysArgs, shortOpt, longOpt)
|
inOpts, inRemain = getopt.getopt(sysArgs, shortOpt, longOpt)
|
||||||
except getopt.GetoptError as E:
|
except getopt.GetoptError as exc:
|
||||||
print(helpMsg)
|
print(helpMsg)
|
||||||
print("ERROR: %s" % str(E))
|
print(f"ERROR: {str(exc)}")
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
if len(inRemain) > 0:
|
if len(inRemain) > 0:
|
||||||
@@ -268,7 +264,7 @@ def main(sysArgs=None):
|
|||||||
elif CONFIG.osWindows:
|
elif CONFIG.osWindows:
|
||||||
try:
|
try:
|
||||||
import ctypes
|
import ctypes
|
||||||
appID = "io.novelwriter.%s" % __version__
|
appID = f"io.novelwriter.{__version__}"
|
||||||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(appID)
|
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(appID)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error("Failed to set application name")
|
logger.error("Failed to set application name")
|
||||||
@@ -281,7 +277,7 @@ def main(sysArgs=None):
|
|||||||
return nwGUI
|
return nwGUI
|
||||||
|
|
||||||
else:
|
else:
|
||||||
nwApp = QApplication([CONFIG.appName, ("-style=%s" % qtStyle)])
|
nwApp = QApplication([CONFIG.appName, (f"-style={qtStyle}")])
|
||||||
nwApp.setApplicationName(CONFIG.appName)
|
nwApp.setApplicationName(CONFIG.appName)
|
||||||
nwApp.setApplicationVersion(__version__)
|
nwApp.setApplicationVersion(__version__)
|
||||||
nwApp.setWindowIcon(QIcon(CONFIG.appIcon))
|
nwApp.setWindowIcon(QIcon(CONFIG.appIcon))
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ import logging
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
|
|
||||||
from PyQt5.QtWidgets import qApp
|
|
||||||
from PyQt5.QtCore import QCoreApplication
|
from PyQt5.QtCore import QCoreApplication
|
||||||
|
from PyQt5.QtWidgets import qApp
|
||||||
|
|
||||||
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
|
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
|
||||||
from novelwriter.error import logException
|
from novelwriter.error import logException
|
||||||
|
|||||||
@@ -56,15 +56,21 @@ class NWDoc():
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<NWDoc handle={self._docHandle}>"
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
return self._docHandle is not None and bool(self._theItem)
|
||||||
|
|
||||||
##
|
##
|
||||||
# Class Methods
|
# Class Methods
|
||||||
##
|
##
|
||||||
|
|
||||||
def readDocument(self, isOrphan=False):
|
def readDocument(self, isOrphan=False):
|
||||||
"""Read a document from set handle, capturing potential file
|
"""Read the document specified by the handle set in the
|
||||||
system errors and parse meta data. If the document doesn't exist
|
contructor, capturing potential file system errors and parse
|
||||||
on disk, return an empty string. If something went wrong, return
|
meta data. If the document doesn't exist on disk, return an
|
||||||
None.
|
empty string. If something went wrong, return None.
|
||||||
"""
|
"""
|
||||||
self._docError = ""
|
self._docError = ""
|
||||||
if self._docHandle is None:
|
if self._docHandle is None:
|
||||||
@@ -88,7 +94,6 @@ class NWDoc():
|
|||||||
if os.path.isfile(docPath):
|
if os.path.isfile(docPath):
|
||||||
try:
|
try:
|
||||||
with open(docPath, mode="r", encoding="utf-8") as inFile:
|
with open(docPath, mode="r", encoding="utf-8") as inFile:
|
||||||
|
|
||||||
# Check the first <= 10 lines for metadata
|
# Check the first <= 10 lines for metadata
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
inLine = inFile.readline()
|
inLine = inFile.readline()
|
||||||
@@ -108,14 +113,15 @@ class NWDoc():
|
|||||||
else:
|
else:
|
||||||
# The document file does not exist, so we assume it's a new
|
# The document file does not exist, so we assume it's a new
|
||||||
# document and initialise an empty text string.
|
# document and initialise an empty text string.
|
||||||
logger.debug("The requested document does not exist.")
|
logger.debug("The requested document does not exist")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
return theText
|
return theText
|
||||||
|
|
||||||
def writeDocument(self, docText, forceWrite=False):
|
def writeDocument(self, docText, forceWrite=False):
|
||||||
"""Write the document. The file is saved via a temp file in case
|
"""Write the document specified by the handle attribute. Handle
|
||||||
of save failure. Returns True if successful, False if not.
|
any IO errors in the process Returns True if successful, False
|
||||||
|
if not.
|
||||||
"""
|
"""
|
||||||
self._docError = ""
|
self._docError = ""
|
||||||
if self._docHandle is None:
|
if self._docHandle is None:
|
||||||
@@ -156,9 +162,7 @@ class NWDoc():
|
|||||||
|
|
||||||
# If we're here, the file was successfully saved, so we can
|
# If we're here, the file was successfully saved, so we can
|
||||||
# replace the temp file with the actual file
|
# replace the temp file with the actual file
|
||||||
if os.path.isfile(docPath):
|
os.replace(docTemp, docPath)
|
||||||
os.unlink(docPath)
|
|
||||||
os.rename(docTemp, docPath)
|
|
||||||
|
|
||||||
self._prevHash = sha256sum(docPath)
|
self._prevHash = sha256sum(docPath)
|
||||||
self._currHash = self._prevHash
|
self._currHash = self._prevHash
|
||||||
@@ -174,11 +178,10 @@ class NWDoc():
|
|||||||
logger.error("No document handle set")
|
logger.error("No document handle set")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
docFile = self._docHandle+".nwd"
|
chkList = [
|
||||||
|
os.path.join(self.theProject.projContent, f"{self._docHandle}.nwd"),
|
||||||
chkList = []
|
os.path.join(self.theProject.projContent, f"{self._docHandle}.nwd~"),
|
||||||
chkList.append(os.path.join(self.theProject.projContent, docFile))
|
]
|
||||||
chkList.append(os.path.join(self.theProject.projContent, docFile+"~"))
|
|
||||||
|
|
||||||
for chkFile in chkList:
|
for chkFile in chkList:
|
||||||
if os.path.isfile(chkFile):
|
if os.path.isfile(chkFile):
|
||||||
@@ -196,18 +199,18 @@ class NWDoc():
|
|||||||
##
|
##
|
||||||
|
|
||||||
def getFileLocation(self):
|
def getFileLocation(self):
|
||||||
"""Return the file location of the current file.
|
"""Return the file location of the current document.
|
||||||
"""
|
"""
|
||||||
return self._fileLoc
|
return self._fileLoc
|
||||||
|
|
||||||
def getCurrentItem(self):
|
def getCurrentItem(self):
|
||||||
"""Return a pointer to the currently open item.
|
"""Return a pointer to the currently open NWItem.
|
||||||
"""
|
"""
|
||||||
return self._theItem
|
return self._theItem
|
||||||
|
|
||||||
def getMeta(self):
|
def getMeta(self):
|
||||||
"""Parses the document meta tag and returns the path and name as
|
"""Parse the document meta tag and return the name, parent,
|
||||||
a list and a string.
|
class and layout meta values.
|
||||||
"""
|
"""
|
||||||
theName = self._docMeta.get("name", "")
|
theName = self._docMeta.get("name", "")
|
||||||
theParent = self._docMeta.get("parent", None)
|
theParent = self._docMeta.get("parent", None)
|
||||||
|
|||||||
+45
-74
@@ -27,7 +27,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import novelwriter
|
|
||||||
|
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
@@ -49,10 +48,10 @@ class NWIndex():
|
|||||||
|
|
||||||
def __init__(self, theProject):
|
def __init__(self, theProject):
|
||||||
|
|
||||||
|
self.theProject = theProject
|
||||||
|
|
||||||
# Internal
|
# Internal
|
||||||
self.mainConf = novelwriter.CONFIG
|
self._indexBroken = False
|
||||||
self.theProject = theProject
|
|
||||||
self.indexBroken = False
|
|
||||||
|
|
||||||
# Indices
|
# Indices
|
||||||
self._tagIndex = {}
|
self._tagIndex = {}
|
||||||
@@ -67,6 +66,10 @@ class NWIndex():
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@property
|
||||||
|
def indexBroken(self):
|
||||||
|
return self._indexBroken
|
||||||
|
|
||||||
##
|
##
|
||||||
# Public Methods
|
# Public Methods
|
||||||
##
|
##
|
||||||
@@ -88,11 +91,7 @@ class NWIndex():
|
|||||||
"""
|
"""
|
||||||
logger.debug("Removing item '%s' from the index", tHandle)
|
logger.debug("Removing item '%s' from the index", tHandle)
|
||||||
|
|
||||||
delTags = []
|
delTags = list(filter(lambda x: self._tagIndex[x][1] == tHandle, self._tagIndex))
|
||||||
for tTag in self._tagIndex:
|
|
||||||
if self._tagIndex[tTag][1] == tHandle:
|
|
||||||
delTags.append(tTag)
|
|
||||||
|
|
||||||
for tTag in delTags:
|
for tTag in delTags:
|
||||||
self._tagIndex.pop(tTag, None)
|
self._tagIndex.pop(tTag, None)
|
||||||
|
|
||||||
@@ -157,7 +156,7 @@ class NWIndex():
|
|||||||
except Exception:
|
except Exception:
|
||||||
logger.error("Failed to load index file")
|
logger.error("Failed to load index file")
|
||||||
logException()
|
logException()
|
||||||
self.indexBroken = True
|
self._indexBroken = True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self._tagIndex = theData.get("tagIndex", {})
|
self._tagIndex = theData.get("tagIndex", {})
|
||||||
@@ -214,17 +213,17 @@ class NWIndex():
|
|||||||
self._checkRefIndex()
|
self._checkRefIndex()
|
||||||
self._checkFileIndex()
|
self._checkFileIndex()
|
||||||
self._checkFileMeta()
|
self._checkFileMeta()
|
||||||
self.indexBroken = False
|
self._indexBroken = False
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error("Error while checking index")
|
logger.error("Error while checking index")
|
||||||
logException()
|
logException()
|
||||||
self.indexBroken = True
|
self._indexBroken = True
|
||||||
|
|
||||||
logger.verbose("Index check took %.3f ms", (time() - tStart)*1000)
|
logger.verbose("Index check took %.3f ms", (time() - tStart)*1000)
|
||||||
logger.debug("Index check complete")
|
logger.debug("Index check complete")
|
||||||
|
|
||||||
if self.indexBroken:
|
if self._indexBroken:
|
||||||
self.clearIndex()
|
self.clearIndex()
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -237,7 +236,8 @@ class NWIndex():
|
|||||||
"""Scan a piece of text associated with a handle. This will
|
"""Scan a piece of text associated with a handle. This will
|
||||||
update the indices accordingly. This function takes the handle
|
update the indices accordingly. This function takes the handle
|
||||||
and text as separate inputs as we want to primarily scan the
|
and text as separate inputs as we want to primarily scan the
|
||||||
files before we save them, unless we're rebuilding the index.
|
files before we save them in which case we already have the
|
||||||
|
text.
|
||||||
"""
|
"""
|
||||||
theItem = self.theProject.projTree[tHandle]
|
theItem = self.theProject.projTree[tHandle]
|
||||||
theRoot = self.theProject.projTree.getRootItem(tHandle)
|
theRoot = self.theProject.projTree.getRootItem(tHandle)
|
||||||
@@ -259,7 +259,7 @@ class NWIndex():
|
|||||||
cC, wC, pC = countWords(theText)
|
cC, wC, pC = countWords(theText)
|
||||||
self._fileMeta[tHandle] = ["H0", cC, wC, pC]
|
self._fileMeta[tHandle] = ["H0", cC, wC, pC]
|
||||||
|
|
||||||
# If the file is archived or trashed, we don't index the file itself
|
# If the file is archived or in trash, we don't index the content
|
||||||
if self.theProject.projTree.isTrashRoot(theItem.itemParent):
|
if self.theProject.projTree.isTrashRoot(theItem.itemParent):
|
||||||
logger.debug("Not indexing trash item '%s'", tHandle)
|
logger.debug("Not indexing trash item '%s'", tHandle)
|
||||||
return False
|
return False
|
||||||
@@ -276,16 +276,12 @@ class NWIndex():
|
|||||||
self._refIndex.pop(tHandle, None)
|
self._refIndex.pop(tHandle, None)
|
||||||
self._fileIndex[tHandle] = {}
|
self._fileIndex[tHandle] = {}
|
||||||
|
|
||||||
# Also clear references to file in tag index
|
# Also clear references to the file in the tags index
|
||||||
clearTags = []
|
clearTags = list(filter(lambda x: self._tagIndex[x][1] == tHandle, self._tagIndex))
|
||||||
for aTag in self._tagIndex:
|
|
||||||
if self._tagIndex[aTag][1] == tHandle:
|
|
||||||
clearTags.append(aTag)
|
|
||||||
for aTag in clearTags:
|
for aTag in clearTags:
|
||||||
self._tagIndex.pop(aTag)
|
self._tagIndex.pop(aTag)
|
||||||
|
|
||||||
# Scan the text content
|
# Scan the text content
|
||||||
nLine = 0
|
|
||||||
nTitle = 0
|
nTitle = 0
|
||||||
theLines = theText.splitlines()
|
theLines = theText.splitlines()
|
||||||
for nLine, aLine in enumerate(theLines, start=1):
|
for nLine, aLine in enumerate(theLines, start=1):
|
||||||
@@ -355,7 +351,7 @@ class NWIndex():
|
|||||||
hText = aLine[5:].strip()
|
hText = aLine[5:].strip()
|
||||||
elif aLine.startswith("#! "):
|
elif aLine.startswith("#! "):
|
||||||
hDepth = "H1"
|
hDepth = "H1"
|
||||||
hText = aLine[2:].strip()
|
hText = aLine[3:].strip()
|
||||||
elif aLine.startswith("##! "):
|
elif aLine.startswith("##! "):
|
||||||
hDepth = "H2"
|
hDepth = "H2"
|
||||||
hText = aLine[4:].strip()
|
hText = aLine[4:].strip()
|
||||||
@@ -374,6 +370,8 @@ class NWIndex():
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self._fileMeta[tHandle][0] == "H0":
|
if self._fileMeta[tHandle][0] == "H0":
|
||||||
|
# Since this initialises to H0, this ensures that only the
|
||||||
|
# first header level is recorded in the file meta index
|
||||||
self._fileMeta[tHandle][0] = hDepth
|
self._fileMeta[tHandle][0] = hDepth
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -542,8 +540,7 @@ 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._fileIndex[tHandle]:
|
for sTitle in self._fileIndex[tHandle]:
|
||||||
theData = self._fileIndex[tHandle][sTitle]
|
iLevel = H_LEVEL.get(self._fileIndex[tHandle][sTitle]["level"], 0)
|
||||||
iLevel = H_LEVEL.get(theData["level"], 0)
|
|
||||||
hCount[iLevel] += 1
|
hCount[iLevel] += 1
|
||||||
|
|
||||||
return hCount
|
return hCount
|
||||||
@@ -551,45 +548,29 @@ class NWIndex():
|
|||||||
def getHandleWordCounts(self, tHandle):
|
def getHandleWordCounts(self, tHandle):
|
||||||
"""Get all header word counts for a specific handle.
|
"""Get all header word counts for a specific handle.
|
||||||
"""
|
"""
|
||||||
theCounts = []
|
hRecord = self._fileIndex.get(tHandle, {})
|
||||||
hRecord = self._fileIndex.get(tHandle, None)
|
return [(f"{tHandle}:{sTitle}", sData["wCount"]) for sTitle, sData in hRecord.items()]
|
||||||
if hRecord is None:
|
|
||||||
return theCounts
|
|
||||||
|
|
||||||
for sTitle, sData in hRecord.items():
|
|
||||||
theCounts.append((f"{tHandle}:{sTitle}", sData["wCount"]))
|
|
||||||
|
|
||||||
return theCounts
|
|
||||||
|
|
||||||
def getHandleHeaders(self, tHandle):
|
def getHandleHeaders(self, tHandle):
|
||||||
"""Get all headers for a specific handle.
|
"""Get all headers for a specific handle.
|
||||||
"""
|
"""
|
||||||
theHeaders = []
|
hRecord = self._fileIndex.get(tHandle, {})
|
||||||
hRecord = self._fileIndex.get(tHandle, None)
|
return [(sTitle, sData["level"], sData["title"]) for sTitle, sData in hRecord.items()]
|
||||||
if hRecord is None:
|
|
||||||
return theHeaders
|
|
||||||
|
|
||||||
for sTitle, sData in hRecord.items():
|
|
||||||
theHeaders.append((sTitle, sData["level"], sData["title"]))
|
|
||||||
|
|
||||||
return theHeaders
|
|
||||||
|
|
||||||
def getHandleHeaderLevel(self, tHandle):
|
def getHandleHeaderLevel(self, tHandle):
|
||||||
"""Get the header level of the first header of a handle.
|
"""Get the header level of the first header of a handle.
|
||||||
"""
|
"""
|
||||||
if tHandle in self._fileMeta:
|
return self._fileMeta.get(tHandle, ["H0"])[0]
|
||||||
return self._fileMeta[tHandle][0]
|
|
||||||
return "H0"
|
|
||||||
|
|
||||||
def getTableOfContents(self, maxDepth, skipExcluded=True):
|
def getTableOfContents(self, maxDepth, skipExcluded=True):
|
||||||
"""Generate a table of contents up to a maxiumum depth.
|
"""Generate a table of contents up to a maximum depth.
|
||||||
"""
|
"""
|
||||||
tOrder = []
|
tOrder = []
|
||||||
tData = {}
|
tData = {}
|
||||||
pKey = None
|
pKey = None
|
||||||
for tHandle in self._listNovelHandles(skipExcluded):
|
for tHandle in self._listNovelHandles(skipExcluded):
|
||||||
for sTitle in sorted(self._fileIndex[tHandle]):
|
for sTitle in sorted(self._fileIndex[tHandle]):
|
||||||
tKey = "%s:%s" % (tHandle, sTitle)
|
tKey = f"{tHandle}:{sTitle}"
|
||||||
theData = self._fileIndex[tHandle][sTitle]
|
theData = self._fileIndex[tHandle][sTitle]
|
||||||
iLevel = H_LEVEL.get(theData["level"], 0)
|
iLevel = H_LEVEL.get(theData["level"], 0)
|
||||||
if iLevel > maxDepth:
|
if iLevel > maxDepth:
|
||||||
@@ -605,19 +586,17 @@ class NWIndex():
|
|||||||
"words": theData["wCount"],
|
"words": theData["wCount"],
|
||||||
}
|
}
|
||||||
|
|
||||||
theToC = []
|
theToC = [(
|
||||||
for tKey in tOrder:
|
tKey,
|
||||||
theToC.append((
|
tData[tKey]["level"],
|
||||||
tKey,
|
tData[tKey]["title"],
|
||||||
tData[tKey]["level"],
|
tData[tKey]["words"]
|
||||||
tData[tKey]["title"],
|
) for tKey in tOrder]
|
||||||
tData[tKey]["words"],
|
|
||||||
))
|
|
||||||
|
|
||||||
return theToC
|
return theToC
|
||||||
|
|
||||||
def getCounts(self, tHandle, sTitle=None):
|
def getCounts(self, tHandle, sTitle=None):
|
||||||
"""Returns the counts for a file, or a section of a file
|
"""Return the counts for a file, or a section of a file,
|
||||||
starting at title sTitle if it is provided.
|
starting at title sTitle if it is provided.
|
||||||
"""
|
"""
|
||||||
cC = 0
|
cC = 0
|
||||||
@@ -640,12 +619,9 @@ class NWIndex():
|
|||||||
|
|
||||||
def getReferences(self, tHandle, sTitle=None):
|
def getReferences(self, tHandle, sTitle=None):
|
||||||
"""Extract all references made in a file, and optionally title
|
"""Extract all references made in a file, and optionally title
|
||||||
section. sTitle must be a string.
|
section.
|
||||||
"""
|
"""
|
||||||
theRefs = {}
|
theRefs = {x: [] for x in nwKeyWords.KEY_CLASS}
|
||||||
for tKey in nwKeyWords.KEY_CLASS:
|
|
||||||
theRefs[tKey] = []
|
|
||||||
|
|
||||||
if tHandle not in self._refIndex:
|
if tHandle not in self._refIndex:
|
||||||
return theRefs
|
return theRefs
|
||||||
|
|
||||||
@@ -669,15 +645,11 @@ class NWIndex():
|
|||||||
"""Build a list of files referring back to our file, specified
|
"""Build a list of files referring back to our file, specified
|
||||||
by tHandle.
|
by tHandle.
|
||||||
"""
|
"""
|
||||||
theRefs = {}
|
|
||||||
if tHandle is None:
|
if tHandle is None:
|
||||||
return theRefs
|
return {}
|
||||||
|
|
||||||
theTags = set()
|
|
||||||
for tTag in self._tagIndex:
|
|
||||||
if tHandle == self._tagIndex[tTag][1]:
|
|
||||||
theTags.add(tTag)
|
|
||||||
|
|
||||||
|
theRefs = {}
|
||||||
|
theTags = set(filter(lambda x: self._tagIndex[x][1] == tHandle, self._tagIndex))
|
||||||
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]:
|
||||||
@@ -690,10 +662,9 @@ class NWIndex():
|
|||||||
def getTagSource(self, theTag):
|
def getTagSource(self, theTag):
|
||||||
"""Return the source location of a given tag.
|
"""Return the source location of a given tag.
|
||||||
"""
|
"""
|
||||||
if theTag in self._tagIndex:
|
theRef = self._tagIndex.get(theTag, [])
|
||||||
theRef = self._tagIndex[theTag]
|
if len(theRef) == 4:
|
||||||
if len(theRef) == 4:
|
return theRef[1], theRef[0], theRef[3]
|
||||||
return theRef[1], theRef[0], theRef[3]
|
|
||||||
return None, 0, "T000000"
|
return None, 0, "T000000"
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -859,9 +830,9 @@ def countWords(theText):
|
|||||||
return charCount, wordCount, paraCount
|
return charCount, wordCount, paraCount
|
||||||
|
|
||||||
# We need to treat dashes as word separators for counting words.
|
# We need to treat dashes as word separators for counting words.
|
||||||
# The check+replace apprach is much faster that direct replace for
|
# The check+replace approach is much faster than direct replace for
|
||||||
# large texts, and a bit slower for small texts, but in the latter
|
# large texts, and a bit slower for small texts, but in the latter
|
||||||
# case it doesn't matter.
|
# case it doesn't really matter.
|
||||||
if nwUnicode.U_ENDASH in theText:
|
if nwUnicode.U_ENDASH in theText:
|
||||||
theText = theText.replace(nwUnicode.U_ENDASH, " ")
|
theText = theText.replace(nwUnicode.U_ENDASH, " ")
|
||||||
if nwUnicode.U_EMDASH in theText:
|
if nwUnicode.U_EMDASH in theText:
|
||||||
|
|||||||
+17
-16
@@ -67,7 +67,7 @@ class NWItem():
|
|||||||
##
|
##
|
||||||
|
|
||||||
def packXML(self, xParent):
|
def packXML(self, xParent):
|
||||||
"""Packs all the data in the class instance into an XML object.
|
"""Pack all the data in the class instance into an XML object.
|
||||||
"""
|
"""
|
||||||
xPack = etree.SubElement(xParent, "item", attrib={
|
xPack = etree.SubElement(xParent, "item", attrib={
|
||||||
"handle": str(self.itemHandle),
|
"handle": str(self.itemHandle),
|
||||||
@@ -91,7 +91,7 @@ class NWItem():
|
|||||||
return
|
return
|
||||||
|
|
||||||
def unpackXML(self, xItem):
|
def unpackXML(self, xItem):
|
||||||
"""Sets the values from an XML entry of type 'item'.
|
"""Set the values from an XML entry of type 'item'.
|
||||||
"""
|
"""
|
||||||
if xItem.tag != "item":
|
if xItem.tag != "item":
|
||||||
logger.error("XML entry is not an NWItem")
|
logger.error("XML entry is not an NWItem")
|
||||||
@@ -133,7 +133,7 @@ class NWItem():
|
|||||||
else:
|
else:
|
||||||
# Sliently skip as we may otherwise cause orphaned
|
# Sliently skip as we may otherwise cause orphaned
|
||||||
# items if an otherwise valid file is opened by a
|
# items if an otherwise valid file is opened by a
|
||||||
# version of novelWriter that doesn't know the tag.
|
# version of novelWriter that doesn't know the tag
|
||||||
logger.error("Unknown tag '%s'", xValue.tag)
|
logger.error("Unknown tag '%s'", xValue.tag)
|
||||||
|
|
||||||
# Guarantees that <status> is parsed after <class>
|
# Guarantees that <status> is parsed after <class>
|
||||||
@@ -143,7 +143,7 @@ class NWItem():
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _subPack(xParent, name, attrib=None, text=None, none=True):
|
def _subPack(xParent, name, attrib=None, text=None, none=True):
|
||||||
"""Packs the values into an xml element.
|
"""Pack the values into an XML element.
|
||||||
"""
|
"""
|
||||||
if not none and (text is None or text == "None"):
|
if not none and (text is None or text == "None"):
|
||||||
return None
|
return None
|
||||||
@@ -204,7 +204,7 @@ class NWItem():
|
|||||||
return
|
return
|
||||||
|
|
||||||
def setParent(self, theParent):
|
def setParent(self, theParent):
|
||||||
"""Set the parent handle, and ensure that it is valid.
|
"""Set the parent handle, and ensure it is valid.
|
||||||
"""
|
"""
|
||||||
if theParent is None:
|
if theParent is None:
|
||||||
self.itemParent = None
|
self.itemParent = None
|
||||||
@@ -216,14 +216,15 @@ class NWItem():
|
|||||||
|
|
||||||
def setOrder(self, theOrder):
|
def setOrder(self, theOrder):
|
||||||
"""Set the item order, and ensure that it is valid. This value
|
"""Set the item order, and ensure that it is valid. This value
|
||||||
is purely a meta value, not actually used by novelWriter.
|
is purely a meta value, and not actually used by novelWriter at
|
||||||
|
the moment.
|
||||||
"""
|
"""
|
||||||
self.itemOrder = checkInt(theOrder, 0)
|
self.itemOrder = checkInt(theOrder, 0)
|
||||||
return
|
return
|
||||||
|
|
||||||
def setType(self, theType):
|
def setType(self, theType):
|
||||||
"""Set the item type from either a proper nwItemType, or set it
|
"""Set the item type from either a proper nwItemType, or set it
|
||||||
from a string representing a nwItemType.
|
from a string representing an nwItemType.
|
||||||
"""
|
"""
|
||||||
if isinstance(theType, nwItemType):
|
if isinstance(theType, nwItemType):
|
||||||
self.itemType = theType
|
self.itemType = theType
|
||||||
@@ -236,7 +237,7 @@ class NWItem():
|
|||||||
|
|
||||||
def setClass(self, theClass):
|
def setClass(self, theClass):
|
||||||
"""Set the item class from either a proper nwItemClass, or set
|
"""Set the item class from either a proper nwItemClass, or set
|
||||||
it from a string representing a nwItemClass.
|
it from a string representing an nwItemClass.
|
||||||
"""
|
"""
|
||||||
if isinstance(theClass, nwItemClass):
|
if isinstance(theClass, nwItemClass):
|
||||||
self.itemClass = theClass
|
self.itemClass = theClass
|
||||||
@@ -249,7 +250,7 @@ class NWItem():
|
|||||||
|
|
||||||
def setLayout(self, theLayout):
|
def setLayout(self, theLayout):
|
||||||
"""Set the item layout from either a proper nwItemLayout, or set
|
"""Set the item layout from either a proper nwItemLayout, or set
|
||||||
it from a string representing a nwItemLayout.
|
it from a string representing an nwItemLayout.
|
||||||
"""
|
"""
|
||||||
if isinstance(theLayout, nwItemLayout):
|
if isinstance(theLayout, nwItemLayout):
|
||||||
self.itemLayout = theLayout
|
self.itemLayout = theLayout
|
||||||
@@ -273,7 +274,7 @@ class NWItem():
|
|||||||
return
|
return
|
||||||
|
|
||||||
def setExpanded(self, expState):
|
def setExpanded(self, expState):
|
||||||
"""Save the expanded status of an item in the project tree.
|
"""Set the expanded status of an item in the project tree.
|
||||||
"""
|
"""
|
||||||
if isinstance(expState, str):
|
if isinstance(expState, str):
|
||||||
self.isExpanded = (expState == str(True))
|
self.isExpanded = (expState == str(True))
|
||||||
@@ -282,7 +283,7 @@ class NWItem():
|
|||||||
return
|
return
|
||||||
|
|
||||||
def setExported(self, expState):
|
def setExported(self, expState):
|
||||||
"""Save the export flag.
|
"""Set the export flag.
|
||||||
"""
|
"""
|
||||||
if isinstance(expState, str):
|
if isinstance(expState, str):
|
||||||
self.isExported = (expState == str(True))
|
self.isExported = (expState == str(True))
|
||||||
@@ -297,29 +298,29 @@ class NWItem():
|
|||||||
def setCharCount(self, theCount):
|
def setCharCount(self, theCount):
|
||||||
"""Set the character count, and ensure that it is an integer.
|
"""Set the character count, and ensure that it is an integer.
|
||||||
"""
|
"""
|
||||||
self.charCount = checkInt(theCount, 0)
|
self.charCount = max(0, checkInt(theCount, 0))
|
||||||
return
|
return
|
||||||
|
|
||||||
def setWordCount(self, theCount):
|
def setWordCount(self, theCount):
|
||||||
"""Set the word count, and ensure that it is an integer.
|
"""Set the word count, and ensure that it is an integer.
|
||||||
"""
|
"""
|
||||||
self.wordCount = checkInt(theCount, 0)
|
self.wordCount = max(0, checkInt(theCount, 0))
|
||||||
return
|
return
|
||||||
|
|
||||||
def setParaCount(self, theCount):
|
def setParaCount(self, theCount):
|
||||||
"""Set the paragraph count, and ensure that it is an integer.
|
"""Set the paragraph count, and ensure that it is an integer.
|
||||||
"""
|
"""
|
||||||
self.paraCount = checkInt(theCount, 0)
|
self.paraCount = max(0, checkInt(theCount, 0))
|
||||||
return
|
return
|
||||||
|
|
||||||
def setCursorPos(self, thePosition):
|
def setCursorPos(self, thePosition):
|
||||||
"""Set the cursor position, and ensure that it is an integer.
|
"""Set the cursor position, and ensure that it is an integer.
|
||||||
"""
|
"""
|
||||||
self.cursorPos = checkInt(thePosition, 0)
|
self.cursorPos = max(0, checkInt(thePosition, 0))
|
||||||
return
|
return
|
||||||
|
|
||||||
def saveInitialCount(self):
|
def saveInitialCount(self):
|
||||||
"""Set the initial word count.
|
"""Save the initial word count.
|
||||||
"""
|
"""
|
||||||
self.initCount = self.wordCount
|
self.initCount = self.wordCount
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ class OptionState():
|
|||||||
##
|
##
|
||||||
|
|
||||||
def setValue(self, group, name, value):
|
def setValue(self, group, name, value):
|
||||||
"""Saves a value, with a given group and name.
|
"""Save a value, with a given group and name.
|
||||||
"""
|
"""
|
||||||
if group not in VALID_MAP:
|
if group not in VALID_MAP:
|
||||||
logger.error("Unknown option group '%s'", group)
|
logger.error("Unknown option group '%s'", group)
|
||||||
|
|||||||
+25
-22
@@ -237,12 +237,13 @@ class NWProject():
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def newProject(self, projData=None):
|
def newProject(self, projData):
|
||||||
"""Create a new project by populating the project tree with a
|
"""Create a new project by populating the project tree with a
|
||||||
few starter items.
|
few starter items.
|
||||||
"""
|
"""
|
||||||
if projData is None:
|
if not isinstance(projData, dict):
|
||||||
projData = {}
|
logger.error("Invalid call to newProject function")
|
||||||
|
return False
|
||||||
|
|
||||||
popMinimal = projData.get("popMinimal", True)
|
popMinimal = projData.get("popMinimal", True)
|
||||||
popCustom = projData.get("popCustom", False)
|
popCustom = projData.get("popCustom", False)
|
||||||
@@ -473,8 +474,8 @@ class NWProject():
|
|||||||
# 1.2 : Changes the way autoReplace entries are stored. The 1.1
|
# 1.2 : Changes the way autoReplace entries are stored. The 1.1
|
||||||
# parser will lose the autoReplace settings if allowed to
|
# parser will lose the autoReplace settings if allowed to
|
||||||
# read the file. Introduced in version 0.10.
|
# read the file. Introduced in version 0.10.
|
||||||
# 1.3 : Reduces the number of layouts to onlye two. One for
|
# 1.3 : Reduces the number of layouts to only two. One for novel
|
||||||
# novel documents and one for project notes. Introduced in
|
# documents and one for project notes. Introduced in
|
||||||
# version 1.5.
|
# version 1.5.
|
||||||
|
|
||||||
if fileVersion not in ("1.0", "1.1", "1.2", "1.3"):
|
if fileVersion not in ("1.0", "1.1", "1.2", "1.3"):
|
||||||
@@ -630,8 +631,8 @@ class NWProject():
|
|||||||
|
|
||||||
def saveProject(self, autoSave=False):
|
def saveProject(self, autoSave=False):
|
||||||
"""Save the project main XML file. The saving command itself
|
"""Save the project main XML file. The saving command itself
|
||||||
uses a temporary filename, and the file is renamed afterwards to
|
uses a temporary filename, and the file is replaced afterwards
|
||||||
make sure if the save fails, we're not left with a truncated
|
to make sure if the save fails, we're not left with a truncated
|
||||||
file.
|
file.
|
||||||
"""
|
"""
|
||||||
if self.projPath is None:
|
if self.projPath is None:
|
||||||
@@ -720,11 +721,15 @@ class NWProject():
|
|||||||
|
|
||||||
# If we're here, the file was successfully saved,
|
# If we're here, the file was successfully saved,
|
||||||
# so let's sort out the temps and backups
|
# so let's sort out the temps and backups
|
||||||
if os.path.isfile(backFile):
|
try:
|
||||||
os.unlink(backFile)
|
if os.path.isfile(saveFile):
|
||||||
if os.path.isfile(saveFile):
|
os.replace(saveFile, backFile)
|
||||||
os.rename(saveFile, backFile)
|
os.replace(tempFile, saveFile)
|
||||||
os.rename(tempFile, saveFile)
|
except Exception as exc:
|
||||||
|
self.theParent.makeAlert(self.tr(
|
||||||
|
"Failed to save project."
|
||||||
|
), nwAlert.ERROR, exception=exc)
|
||||||
|
return False
|
||||||
|
|
||||||
# Save project GUI options
|
# Save project GUI options
|
||||||
self.optState.saveSettings()
|
self.optState.saveSettings()
|
||||||
@@ -857,9 +862,9 @@ class NWProject():
|
|||||||
|
|
||||||
def extractSampleProject(self, projData):
|
def extractSampleProject(self, projData):
|
||||||
"""Make a copy of the sample project.
|
"""Make a copy of the sample project.
|
||||||
First, try to copy the content of the sample folder to the new
|
First, look for the sample.zip file in the assets folder and
|
||||||
project path, or if the folder doesn't exist, look for the zip
|
unpack it. If it doesn't exist, try to copy the content of the
|
||||||
file in the assets folder.
|
sample folder to the new project path. If neither exits, error.
|
||||||
"""
|
"""
|
||||||
projPath = projData.get("projPath", None)
|
projPath = projData.get("projPath", None)
|
||||||
if projPath is None:
|
if projPath is None:
|
||||||
@@ -965,14 +970,14 @@ class NWProject():
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def setBookTitle(self, bookTitle):
|
def setBookTitle(self, bookTitle):
|
||||||
"""Set the boom title, that is, the title to include in exports.
|
"""Set the book title, that is, the title to include in exports.
|
||||||
"""
|
"""
|
||||||
self.bookTitle = bookTitle.strip()
|
self.bookTitle = bookTitle.strip()
|
||||||
self.setProjectChanged(True)
|
self.setProjectChanged(True)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def setBookAuthors(self, bookAuthors):
|
def setBookAuthors(self, bookAuthors):
|
||||||
"""A line separated list of book authors, parsed into an array.
|
"""A line-separated list of authors, parsed into an array.
|
||||||
"""
|
"""
|
||||||
if not isinstance(bookAuthors, str):
|
if not isinstance(bookAuthors, str):
|
||||||
return False
|
return False
|
||||||
@@ -1097,8 +1102,7 @@ class NWProject():
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def setAutoReplace(self, autoReplace):
|
def setAutoReplace(self, autoReplace):
|
||||||
"""Update the auto-replace dictionary. This replaces the entire
|
"""Update the auto-replace dictionary.
|
||||||
dictionary, so alterations have to be made in a copy.
|
|
||||||
"""
|
"""
|
||||||
self.autoReplace = autoReplace
|
self.autoReplace = autoReplace
|
||||||
self.setProjectChanged(True)
|
self.setProjectChanged(True)
|
||||||
@@ -1128,7 +1132,7 @@ class NWProject():
|
|||||||
##
|
##
|
||||||
|
|
||||||
def getAuthors(self):
|
def getAuthors(self):
|
||||||
"""Returns a formatted string of authors.
|
"""Return a formatted string of authors.
|
||||||
"""
|
"""
|
||||||
nAuth = len(self.bookAuthors)
|
nAuth = len(self.bookAuthors)
|
||||||
authString = ""
|
authString = ""
|
||||||
@@ -1225,8 +1229,7 @@ class NWProject():
|
|||||||
return it. The variable is cast to a string before lookup. If
|
return it. The variable is cast to a string before lookup. If
|
||||||
the word does not exist, it returns itself.
|
the word does not exist, it returns itself.
|
||||||
"""
|
"""
|
||||||
theValue = str(theWord)
|
return self.langData.get(str(theWord), str(theWord))
|
||||||
return self.langData.get(theValue, theValue)
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Internal Functions
|
# Internal Functions
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import novelwriter
|
|
||||||
|
|
||||||
from novelwriter.error import logException
|
from novelwriter.error import logException
|
||||||
|
|
||||||
@@ -36,8 +35,6 @@ class NWSpellEnchant():
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
self.mainConf = novelwriter.CONFIG
|
|
||||||
|
|
||||||
self._theDict = None
|
self._theDict = None
|
||||||
self._projDict = set()
|
self._projDict = set()
|
||||||
self._projectDict = None
|
self._projectDict = None
|
||||||
|
|||||||
+49
-41
@@ -40,9 +40,9 @@ class ToHtml(Tokenizer):
|
|||||||
def __init__(self, theProject):
|
def __init__(self, theProject):
|
||||||
Tokenizer.__init__(self, theProject)
|
Tokenizer.__init__(self, theProject)
|
||||||
|
|
||||||
self.genMode = self.M_EXPORT
|
self._genMode = self.M_EXPORT
|
||||||
self.cssStyles = True
|
self._cssStyles = True
|
||||||
self.fullHTML = []
|
self._fullHTML = []
|
||||||
|
|
||||||
# Internals
|
# Internals
|
||||||
self._trMap = {}
|
self._trMap = {}
|
||||||
@@ -50,6 +50,14 @@ class ToHtml(Tokenizer):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
##
|
||||||
|
# Properties
|
||||||
|
##
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fullHTML(self):
|
||||||
|
return self._fullHTML
|
||||||
|
|
||||||
##
|
##
|
||||||
# Setters
|
# Setters
|
||||||
##
|
##
|
||||||
@@ -59,17 +67,17 @@ class ToHtml(Tokenizer):
|
|||||||
need to make a few changes to formatting, which is managed by
|
need to make a few changes to formatting, which is managed by
|
||||||
these flags.
|
these flags.
|
||||||
"""
|
"""
|
||||||
self.genMode = self.M_PREVIEW
|
self._genMode = self.M_PREVIEW
|
||||||
self.doKeywords = True
|
self._doKeywords = True
|
||||||
self.doComments = doComments
|
self._doComments = doComments
|
||||||
self.doSynopsis = doSynopsis
|
self._doSynopsis = doSynopsis
|
||||||
return
|
return
|
||||||
|
|
||||||
def setStyles(self, cssStyles):
|
def setStyles(self, cssStyles):
|
||||||
"""Enable/disable CSS styling. Some elements may still have
|
"""Enable/disable CSS styling. Some elements may still have
|
||||||
class tags.
|
class tags.
|
||||||
"""
|
"""
|
||||||
self.cssStyles = cssStyles
|
self._cssStyles = cssStyles
|
||||||
return
|
return
|
||||||
|
|
||||||
def setReplaceUnicode(self, doReplace):
|
def setReplaceUnicode(self, doReplace):
|
||||||
@@ -93,21 +101,21 @@ class ToHtml(Tokenizer):
|
|||||||
def getFullResultSize(self):
|
def getFullResultSize(self):
|
||||||
"""Return the size of the full HTML result.
|
"""Return the size of the full HTML result.
|
||||||
"""
|
"""
|
||||||
return sum([len(x) for x in self.fullHTML])
|
return sum([len(x) for x in self._fullHTML])
|
||||||
|
|
||||||
def doPreProcessing(self):
|
def doPreProcessing(self):
|
||||||
"""Extend the auto-replace to also properly encode some unicode
|
"""Extend the auto-replace to also properly encode some unicode
|
||||||
characters into their respective HTML entities.
|
characters into their respective HTML entities.
|
||||||
"""
|
"""
|
||||||
Tokenizer.doPreProcessing(self)
|
Tokenizer.doPreProcessing(self)
|
||||||
self.theText = self.theText.translate(self._trMap)
|
self._theText = self._theText.translate(self._trMap)
|
||||||
return
|
return
|
||||||
|
|
||||||
def doConvert(self):
|
def doConvert(self):
|
||||||
"""Convert the list of text tokens into a HTML document saved
|
"""Convert the list of text tokens into a HTML document saved
|
||||||
to theResult.
|
to theResult.
|
||||||
"""
|
"""
|
||||||
if self.genMode == self.M_PREVIEW:
|
if self._genMode == self.M_PREVIEW:
|
||||||
htmlTags = { # HTML4 + CSS2 (for Qt)
|
htmlTags = { # HTML4 + CSS2 (for Qt)
|
||||||
self.FMT_B_B: "<b>",
|
self.FMT_B_B: "<b>",
|
||||||
self.FMT_B_E: "</b>",
|
self.FMT_B_E: "</b>",
|
||||||
@@ -126,7 +134,7 @@ class ToHtml(Tokenizer):
|
|||||||
self.FMT_D_E: "</del>",
|
self.FMT_D_E: "</del>",
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.isNovel and self.genMode != self.M_PREVIEW:
|
if self._isNovel and self._genMode != self.M_PREVIEW:
|
||||||
# For story files, we bump the titles one level up
|
# For story files, we bump the titles one level up
|
||||||
h1Cl = " class='title'"
|
h1Cl = " class='title'"
|
||||||
h1 = "h1"
|
h1 = "h1"
|
||||||
@@ -140,13 +148,13 @@ class ToHtml(Tokenizer):
|
|||||||
h3 = "h3"
|
h3 = "h3"
|
||||||
h4 = "h4"
|
h4 = "h4"
|
||||||
|
|
||||||
self.theResult = ""
|
self._theResult = ""
|
||||||
|
|
||||||
thisPar = []
|
thisPar = []
|
||||||
parStyle = None
|
parStyle = None
|
||||||
tmpResult = []
|
tmpResult = []
|
||||||
|
|
||||||
for tType, tLine, tDirty, tFormat, tStyle in self.theTokens:
|
for tType, tLine, tDirty, tFormat, tStyle in self._theTokens:
|
||||||
|
|
||||||
# Replace < and > and recompute formatting positions
|
# Replace < and > and recompute formatting positions
|
||||||
cText = []
|
cText = []
|
||||||
@@ -168,7 +176,7 @@ class ToHtml(Tokenizer):
|
|||||||
|
|
||||||
# Styles
|
# Styles
|
||||||
aStyle = []
|
aStyle = []
|
||||||
if tStyle is not None and self.cssStyles:
|
if tStyle is not None and self._cssStyles:
|
||||||
if tStyle & self.A_LEFT:
|
if tStyle & self.A_LEFT:
|
||||||
aStyle.append("text-align: left;")
|
aStyle.append("text-align: left;")
|
||||||
elif tStyle & self.A_RIGHT:
|
elif tStyle & self.A_RIGHT:
|
||||||
@@ -200,7 +208,7 @@ class ToHtml(Tokenizer):
|
|||||||
else:
|
else:
|
||||||
hStyle = ""
|
hStyle = ""
|
||||||
|
|
||||||
if self.linkHeaders:
|
if self._linkHeaders:
|
||||||
aNm = f"<a name='T{tLine:06d}'></a>"
|
aNm = f"<a name='T{tLine:06d}'></a>"
|
||||||
else:
|
else:
|
||||||
aNm = ""
|
aNm = ""
|
||||||
@@ -209,7 +217,7 @@ class ToHtml(Tokenizer):
|
|||||||
if tType == self.T_EMPTY:
|
if tType == self.T_EMPTY:
|
||||||
if parStyle is None:
|
if parStyle is None:
|
||||||
parStyle = ""
|
parStyle = ""
|
||||||
if len(thisPar) > 1 and self.cssStyles:
|
if len(thisPar) > 1 and self._cssStyles:
|
||||||
parClass = " class='break'"
|
parClass = " class='break'"
|
||||||
else:
|
else:
|
||||||
parClass = ""
|
parClass = ""
|
||||||
@@ -257,21 +265,21 @@ class ToHtml(Tokenizer):
|
|||||||
tTemp = tTemp[:xPos] + htmlTags[xFmt] + tTemp[xPos+xLen:]
|
tTemp = tTemp[:xPos] + htmlTags[xFmt] + tTemp[xPos+xLen:]
|
||||||
thisPar.append(tTemp.rstrip())
|
thisPar.append(tTemp.rstrip())
|
||||||
|
|
||||||
elif tType == self.T_SYNOPSIS and self.doSynopsis:
|
elif tType == self.T_SYNOPSIS and self._doSynopsis:
|
||||||
tmpResult.append(self._formatSynopsis(tText))
|
tmpResult.append(self._formatSynopsis(tText))
|
||||||
|
|
||||||
elif tType == self.T_COMMENT and self.doComments:
|
elif tType == self.T_COMMENT and self._doComments:
|
||||||
tmpResult.append(self._formatComments(tText))
|
tmpResult.append(self._formatComments(tText))
|
||||||
|
|
||||||
elif tType == self.T_KEYWORD and self.doKeywords:
|
elif tType == self.T_KEYWORD and self._doKeywords:
|
||||||
tTemp = f"<p{hStyle}>{self._formatKeywords(tText)}</p>\n"
|
tTemp = f"<p{hStyle}>{self._formatKeywords(tText)}</p>\n"
|
||||||
tmpResult.append(tTemp)
|
tmpResult.append(tTemp)
|
||||||
|
|
||||||
self.theResult = "".join(tmpResult)
|
self._theResult = "".join(tmpResult)
|
||||||
tmpResult = []
|
tmpResult = []
|
||||||
|
|
||||||
if self.genMode != self.M_PREVIEW:
|
if self._genMode != self.M_PREVIEW:
|
||||||
self.fullHTML.append(self.theResult)
|
self._fullHTML.append(self._theResult)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -281,7 +289,7 @@ class ToHtml(Tokenizer):
|
|||||||
with open(savePath, mode="w", encoding="utf-8") as outFile:
|
with open(savePath, mode="w", encoding="utf-8") as outFile:
|
||||||
theStyle = self.getStyleSheet()
|
theStyle = self.getStyleSheet()
|
||||||
theStyle.append("article {width: 800px; margin: 40px auto;}")
|
theStyle.append("article {width: 800px; margin: 40px auto;}")
|
||||||
bodyText = "".join(self.fullHTML)
|
bodyText = "".join(self._fullHTML)
|
||||||
bodyText = bodyText.replace("\t", "	").rstrip()
|
bodyText = bodyText.replace("\t", "	").rstrip()
|
||||||
|
|
||||||
theHtml = (
|
theHtml = (
|
||||||
@@ -314,24 +322,24 @@ class ToHtml(Tokenizer):
|
|||||||
"""
|
"""
|
||||||
htmlText = []
|
htmlText = []
|
||||||
tabSpace = spaceChar*nSpaces
|
tabSpace = spaceChar*nSpaces
|
||||||
for aLine in self.fullHTML:
|
for aLine in self._fullHTML:
|
||||||
htmlText.append(aLine.replace("\t", tabSpace))
|
htmlText.append(aLine.replace("\t", tabSpace))
|
||||||
|
|
||||||
self.fullHTML = htmlText
|
self._fullHTML = htmlText
|
||||||
return
|
return
|
||||||
|
|
||||||
def getStyleSheet(self):
|
def getStyleSheet(self):
|
||||||
"""Generate a stylesheet appropriate for the current settings.
|
"""Generate a stylesheet appropriate for the current settings.
|
||||||
"""
|
"""
|
||||||
theStyles = []
|
theStyles = []
|
||||||
if not self.cssStyles:
|
if not self._cssStyles:
|
||||||
return theStyles
|
return theStyles
|
||||||
|
|
||||||
mScale = self.lineHeight/1.15
|
mScale = self._lineHeight/1.15
|
||||||
textAlign = "justify" if self.doJustify else "left"
|
textAlign = "justify" if self._doJustify else "left"
|
||||||
|
|
||||||
theStyles.append("body {{font-family: '{0:s}'; font-size: {1:d}pt;}}".format(
|
theStyles.append("body {{font-family: '{0:s}'; font-size: {1:d}pt;}}".format(
|
||||||
self.textFont, self.textSize
|
self._textFont, self._textSize
|
||||||
))
|
))
|
||||||
theStyles.append((
|
theStyles.append((
|
||||||
"p {{"
|
"p {{"
|
||||||
@@ -340,9 +348,9 @@ class ToHtml(Tokenizer):
|
|||||||
"}}"
|
"}}"
|
||||||
).format(
|
).format(
|
||||||
textAlign,
|
textAlign,
|
||||||
round(100 * self.lineHeight),
|
round(100 * self._lineHeight),
|
||||||
mScale * self.marginText[0],
|
mScale * self._marginText[0],
|
||||||
mScale * self.marginText[1],
|
mScale * self._marginText[1],
|
||||||
))
|
))
|
||||||
theStyles.append((
|
theStyles.append((
|
||||||
"h1 {{"
|
"h1 {{"
|
||||||
@@ -352,7 +360,7 @@ class ToHtml(Tokenizer):
|
|||||||
"margin-bottom: {1:.2f}em;"
|
"margin-bottom: {1:.2f}em;"
|
||||||
"}}"
|
"}}"
|
||||||
).format(
|
).format(
|
||||||
mScale * self.marginHead1[0], mScale * self.marginHead1[1]
|
mScale * self._marginHead1[0], mScale * self._marginHead1[1]
|
||||||
))
|
))
|
||||||
theStyles.append((
|
theStyles.append((
|
||||||
"h2 {{"
|
"h2 {{"
|
||||||
@@ -362,7 +370,7 @@ class ToHtml(Tokenizer):
|
|||||||
"margin-bottom: {1:.2f}em;"
|
"margin-bottom: {1:.2f}em;"
|
||||||
"}}"
|
"}}"
|
||||||
).format(
|
).format(
|
||||||
mScale * self.marginHead2[0], mScale * self.marginHead2[1]
|
mScale * self._marginHead2[0], mScale * self._marginHead2[1]
|
||||||
))
|
))
|
||||||
theStyles.append((
|
theStyles.append((
|
||||||
"h3 {{"
|
"h3 {{"
|
||||||
@@ -372,7 +380,7 @@ class ToHtml(Tokenizer):
|
|||||||
"margin-bottom: {1:.2f}em;"
|
"margin-bottom: {1:.2f}em;"
|
||||||
"}}"
|
"}}"
|
||||||
).format(
|
).format(
|
||||||
mScale * self.marginHead3[0], mScale * self.marginHead3[1]
|
mScale * self._marginHead3[0], mScale * self._marginHead3[1]
|
||||||
))
|
))
|
||||||
theStyles.append((
|
theStyles.append((
|
||||||
"h4 {{"
|
"h4 {{"
|
||||||
@@ -382,7 +390,7 @@ class ToHtml(Tokenizer):
|
|||||||
"margin-bottom: {1:.2f}em;"
|
"margin-bottom: {1:.2f}em;"
|
||||||
"}}"
|
"}}"
|
||||||
).format(
|
).format(
|
||||||
mScale * self.marginHead4[0], mScale * self.marginHead4[1]
|
mScale * self._marginHead4[0], mScale * self._marginHead4[1]
|
||||||
))
|
))
|
||||||
theStyles.append((
|
theStyles.append((
|
||||||
".title {{"
|
".title {{"
|
||||||
@@ -391,7 +399,7 @@ class ToHtml(Tokenizer):
|
|||||||
"margin-bottom: {1:.2f}em;"
|
"margin-bottom: {1:.2f}em;"
|
||||||
"}}"
|
"}}"
|
||||||
).format(
|
).format(
|
||||||
mScale * self.marginTitle[0], mScale * self.marginTitle[1]
|
mScale * self._marginTitle[0], mScale * self._marginTitle[1]
|
||||||
))
|
))
|
||||||
theStyles.append((
|
theStyles.append((
|
||||||
".sep, .skip {{"
|
".sep, .skip {{"
|
||||||
@@ -418,7 +426,7 @@ class ToHtml(Tokenizer):
|
|||||||
def _formatSynopsis(self, tText):
|
def _formatSynopsis(self, tText):
|
||||||
"""Apply HTML formatting to synopsis.
|
"""Apply HTML formatting to synopsis.
|
||||||
"""
|
"""
|
||||||
if self.genMode == self.M_PREVIEW:
|
if self._genMode == self.M_PREVIEW:
|
||||||
sSynop = self._trSynopsis
|
sSynop = self._trSynopsis
|
||||||
return f"<p class='comment'><span class='synopsis'>{sSynop}:</span> {tText}</p>\n"
|
return f"<p class='comment'><span class='synopsis'>{sSynop}:</span> {tText}</p>\n"
|
||||||
else:
|
else:
|
||||||
@@ -428,7 +436,7 @@ class ToHtml(Tokenizer):
|
|||||||
def _formatComments(self, tText):
|
def _formatComments(self, tText):
|
||||||
"""Apply HTML formatting to comments.
|
"""Apply HTML formatting to comments.
|
||||||
"""
|
"""
|
||||||
if self.genMode == self.M_PREVIEW:
|
if self._genMode == self.M_PREVIEW:
|
||||||
return f"<p class='comment'>{tText}</p>\n"
|
return f"<p class='comment'>{tText}</p>\n"
|
||||||
else:
|
else:
|
||||||
sComm = self._localLookup("Comment")
|
sComm = self._localLookup("Comment")
|
||||||
@@ -449,7 +457,7 @@ class ToHtml(Tokenizer):
|
|||||||
if theBits[0] == nwKeyWords.TAG_KEY:
|
if theBits[0] == nwKeyWords.TAG_KEY:
|
||||||
retText += f"<a name='tag_{theBits[1]}'>{theBits[1]}</a>"
|
retText += f"<a name='tag_{theBits[1]}'>{theBits[1]}</a>"
|
||||||
else:
|
else:
|
||||||
if self.genMode == self.M_PREVIEW:
|
if self._genMode == self.M_PREVIEW:
|
||||||
for tTag in theBits[1:]:
|
for tTag in theBits[1:]:
|
||||||
refTags.append(f"<a href='#{theBits[0][1:]}={tTag}'>{tTag}</a>")
|
refTags.append(f"<a href='#{theBits[0][1:]}={tTag}'>{tTag}</a>")
|
||||||
retText += ", ".join(refTags)
|
retText += ", ".join(refTags)
|
||||||
|
|||||||
+194
-178
@@ -85,62 +85,62 @@ class Tokenizer():
|
|||||||
self.mainConf = novelwriter.CONFIG
|
self.mainConf = novelwriter.CONFIG
|
||||||
|
|
||||||
# Data Variables
|
# Data Variables
|
||||||
self.theText = "" # The raw text to be tokenized
|
self._theText = "" # The raw text to be tokenized
|
||||||
self.theHandle = None # The handle associated with the text
|
self._theHandle = None # The handle associated with the text
|
||||||
self.theItem = None # The NWItem associated with the handle
|
self._theItem = None # The NWItem associated with the handle
|
||||||
self.theTokens = [] # The list of the processed tokens
|
self._theTokens = [] # The list of the processed tokens
|
||||||
self.theResult = "" # The result of the last document
|
self._theResult = "" # The result of the last document
|
||||||
|
|
||||||
self.keepMarkdown = False # Whether to keep the markdown text
|
self._keepMarkdown = False # Whether to keep the markdown text
|
||||||
self.theMarkdown = [] # The result novelWriter markdown of all documents
|
self._theMarkdown = [] # The result novelWriter markdown of all documents
|
||||||
|
|
||||||
# User Settings
|
# User Settings
|
||||||
self.textFont = "Serif" # Output text font
|
self._textFont = "Serif" # Output text font
|
||||||
self.textSize = 11 # Output text size
|
self._textSize = 11 # Output text size
|
||||||
self.textFixed = False # Fixed width text
|
self._textFixed = False # Fixed width text
|
||||||
self.lineHeight = 1.15 # Line height in units of em
|
self._lineHeight = 1.15 # Line height in units of em
|
||||||
self.blockIndent = 4.00 # Block indent in units of em
|
self._blockIndent = 4.00 # Block indent in units of em
|
||||||
self.doJustify = False # Justify text
|
self._doJustify = False # Justify text
|
||||||
self.doBodyText = True # Include body text
|
self._doBodyText = True # Include body text
|
||||||
self.doSynopsis = False # Also process synopsis comments
|
self._doSynopsis = False # Also process synopsis comments
|
||||||
self.doComments = False # Also process comments
|
self._doComments = False # Also process comments
|
||||||
self.doKeywords = False # Also process keywords like tags and references
|
self._doKeywords = False # Also process keywords like tags and references
|
||||||
|
|
||||||
# Margins
|
# Margins
|
||||||
self.marginTitle = (1.000, 0.500)
|
self._marginTitle = (1.000, 0.500)
|
||||||
self.marginHead1 = (1.000, 0.500)
|
self._marginHead1 = (1.000, 0.500)
|
||||||
self.marginHead2 = (0.834, 0.500)
|
self._marginHead2 = (0.834, 0.500)
|
||||||
self.marginHead3 = (0.584, 0.500)
|
self._marginHead3 = (0.584, 0.500)
|
||||||
self.marginHead4 = (0.584, 0.500)
|
self._marginHead4 = (0.584, 0.500)
|
||||||
self.marginText = (0.000, 0.584)
|
self._marginText = (0.000, 0.584)
|
||||||
self.marginMeta = (0.000, 0.584)
|
self._marginMeta = (0.000, 0.584)
|
||||||
|
|
||||||
# Title Formats
|
# Title Formats
|
||||||
self.fmtTitle = "%title%" # Formatting for titles
|
self._fmtTitle = "%title%" # Formatting for titles
|
||||||
self.fmtChapter = "%title%" # Formatting for numbered chapters
|
self._fmtChapter = "%title%" # Formatting for numbered chapters
|
||||||
self.fmtUnNum = "%title%" # Formatting for unnumbered chapters
|
self._fmtUnNum = "%title%" # Formatting for unnumbered chapters
|
||||||
self.fmtScene = "%title%" # Formatting for scenes
|
self._fmtScene = "%title%" # Formatting for scenes
|
||||||
self.fmtSection = "%title%" # Formatting for sections
|
self._fmtSection = "%title%" # Formatting for sections
|
||||||
|
|
||||||
self.hideScene = False # Do not include scene headers
|
self._hideScene = False # Do not include scene headers
|
||||||
self.hideSection = False # Do not include section headers
|
self._hideSection = False # Do not include section headers
|
||||||
|
|
||||||
self.linkHeaders = False # Add an anchor before headers
|
self._linkHeaders = False # Add an anchor before headers
|
||||||
|
|
||||||
# Instance Variables
|
# Instance Variables
|
||||||
self.numChapter = 0 # Counter for chapter numbers
|
self._numChapter = 0 # Counter for chapter numbers
|
||||||
self.numChScene = 0 # Counter for scene number within chapter
|
self._numChScene = 0 # Counter for scene number within chapter
|
||||||
self.numAbsScene = 0 # Counter for scene number within novel
|
self._numAbsScene = 0 # Counter for scene number within novel
|
||||||
self.firstScene = False # Flag to indicate that the first scene of the chapter
|
self._firstScene = False # Flag to indicate that the first scene of the chapter
|
||||||
|
|
||||||
# This File
|
# This File
|
||||||
self.isNone = False # Document has unknown layout
|
self._isNone = False # Document has unknown layout
|
||||||
self.isNovel = False # Document is a novel document
|
self._isNovel = False # Document is a novel document
|
||||||
self.isNote = False # Document is a project note
|
self._isNote = False # Document is a project note
|
||||||
self.isFirst = True # Document is the first in a set
|
self._isFirst = True # Document is the first in a set
|
||||||
|
|
||||||
# Error Handling
|
# Error Handling
|
||||||
self.errData = []
|
self._errData = []
|
||||||
|
|
||||||
# Function Mapping
|
# Function Mapping
|
||||||
self._localLookup = self.theProject.localLookup
|
self._localLookup = self.theProject.localLookup
|
||||||
@@ -151,100 +151,116 @@ class Tokenizer():
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
##
|
||||||
|
# Properties
|
||||||
|
##
|
||||||
|
|
||||||
|
@property
|
||||||
|
def theResult(self):
|
||||||
|
return self._theResult
|
||||||
|
|
||||||
|
@property
|
||||||
|
def theMarkdown(self):
|
||||||
|
return self._theMarkdown
|
||||||
|
|
||||||
|
@property
|
||||||
|
def errData(self):
|
||||||
|
return self._errData
|
||||||
|
|
||||||
##
|
##
|
||||||
# Setters
|
# Setters
|
||||||
##
|
##
|
||||||
|
|
||||||
def setTitleFormat(self, fmtTitle):
|
def setTitleFormat(self, fmtTitle):
|
||||||
self.fmtTitle = fmtTitle.strip()
|
self._fmtTitle = fmtTitle.strip()
|
||||||
return
|
return
|
||||||
|
|
||||||
def setChapterFormat(self, fmtChapter):
|
def setChapterFormat(self, fmtChapter):
|
||||||
self.fmtChapter = fmtChapter.strip()
|
self._fmtChapter = fmtChapter.strip()
|
||||||
return
|
return
|
||||||
|
|
||||||
def setUnNumberedFormat(self, fmtUnNum):
|
def setUnNumberedFormat(self, fmtUnNum):
|
||||||
self.fmtUnNum = fmtUnNum.strip()
|
self._fmtUnNum = fmtUnNum.strip()
|
||||||
return
|
return
|
||||||
|
|
||||||
def setSceneFormat(self, fmtScene, hideScene):
|
def setSceneFormat(self, fmtScene, hideScene):
|
||||||
self.fmtScene = fmtScene.strip()
|
self._fmtScene = fmtScene.strip()
|
||||||
self.hideScene = hideScene
|
self._hideScene = hideScene
|
||||||
return
|
return
|
||||||
|
|
||||||
def setSectionFormat(self, fmtSection, hideSection):
|
def setSectionFormat(self, fmtSection, hideSection):
|
||||||
self.fmtSection = fmtSection.strip()
|
self._fmtSection = fmtSection.strip()
|
||||||
self.hideSection = hideSection
|
self._hideSection = hideSection
|
||||||
return
|
return
|
||||||
|
|
||||||
def setFont(self, textFont, textSize, textFixed=False):
|
def setFont(self, textFont, textSize, textFixed=False):
|
||||||
self.textFont = textFont
|
self._textFont = textFont
|
||||||
self.textSize = round(int(textSize))
|
self._textSize = round(int(textSize))
|
||||||
self.textFixed = textFixed
|
self._textFixed = textFixed
|
||||||
return
|
return
|
||||||
|
|
||||||
def setLineHeight(self, lineHeight):
|
def setLineHeight(self, lineHeight):
|
||||||
self.lineHeight = min(max(float(lineHeight), 0.5), 5.0)
|
self._lineHeight = min(max(float(lineHeight), 0.5), 5.0)
|
||||||
return
|
return
|
||||||
|
|
||||||
def setBlockIndent(self, blockIndent):
|
def setBlockIndent(self, blockIndent):
|
||||||
self.blockIndent = min(max(float(blockIndent), 0.0), 10.0)
|
self._blockIndent = min(max(float(blockIndent), 0.0), 10.0)
|
||||||
return
|
return
|
||||||
|
|
||||||
def setJustify(self, doJustify):
|
def setJustify(self, doJustify):
|
||||||
self.doJustify = doJustify
|
self._doJustify = doJustify
|
||||||
return
|
return
|
||||||
|
|
||||||
def setTitleMargins(self, mUpper, mLower):
|
def setTitleMargins(self, mUpper, mLower):
|
||||||
self.marginTitle = (float(mUpper), float(mLower))
|
self._marginTitle = (float(mUpper), float(mLower))
|
||||||
return
|
return
|
||||||
|
|
||||||
def setHead1Margins(self, mUpper, mLower):
|
def setHead1Margins(self, mUpper, mLower):
|
||||||
self.marginHead1 = (float(mUpper), float(mLower))
|
self._marginHead1 = (float(mUpper), float(mLower))
|
||||||
return
|
return
|
||||||
|
|
||||||
def setHead2Margins(self, mUpper, mLower):
|
def setHead2Margins(self, mUpper, mLower):
|
||||||
self.marginHead2 = (float(mUpper), float(mLower))
|
self._marginHead2 = (float(mUpper), float(mLower))
|
||||||
return
|
return
|
||||||
|
|
||||||
def setHead3Margins(self, mUpper, mLower):
|
def setHead3Margins(self, mUpper, mLower):
|
||||||
self.marginHead3 = (float(mUpper), float(mLower))
|
self._marginHead3 = (float(mUpper), float(mLower))
|
||||||
return
|
return
|
||||||
|
|
||||||
def setHead4Margins(self, mUpper, mLower):
|
def setHead4Margins(self, mUpper, mLower):
|
||||||
self.marginHead4 = (float(mUpper), float(mLower))
|
self._marginHead4 = (float(mUpper), float(mLower))
|
||||||
return
|
return
|
||||||
|
|
||||||
def setTextMargins(self, mUpper, mLower):
|
def setTextMargins(self, mUpper, mLower):
|
||||||
self.marginText = (float(mUpper), float(mLower))
|
self._marginText = (float(mUpper), float(mLower))
|
||||||
return
|
return
|
||||||
|
|
||||||
def setMetaMargins(self, mUpper, mLower):
|
def setMetaMargins(self, mUpper, mLower):
|
||||||
self.marginMeta = (float(mUpper), float(mLower))
|
self._marginMeta = (float(mUpper), float(mLower))
|
||||||
return
|
return
|
||||||
|
|
||||||
def setLinkHeaders(self, linkHeaders):
|
def setLinkHeaders(self, linkHeaders):
|
||||||
self.linkHeaders = linkHeaders
|
self._linkHeaders = linkHeaders
|
||||||
return
|
return
|
||||||
|
|
||||||
def setBodyText(self, doBodyText):
|
def setBodyText(self, doBodyText):
|
||||||
self.doBodyText = doBodyText
|
self._doBodyText = doBodyText
|
||||||
return
|
return
|
||||||
|
|
||||||
def setSynopsis(self, doSynopsis):
|
def setSynopsis(self, doSynopsis):
|
||||||
self.doSynopsis = doSynopsis
|
self._doSynopsis = doSynopsis
|
||||||
return
|
return
|
||||||
|
|
||||||
def setComments(self, doComments):
|
def setComments(self, doComments):
|
||||||
self.doComments = doComments
|
self._doComments = doComments
|
||||||
return
|
return
|
||||||
|
|
||||||
def setKeywords(self, doKeywords):
|
def setKeywords(self, doKeywords):
|
||||||
self.doKeywords = doKeywords
|
self._doKeywords = doKeywords
|
||||||
return
|
return
|
||||||
|
|
||||||
def setKeepMarkdown(self, keepMarkdown):
|
def setKeepMarkdown(self, keepMarkdown):
|
||||||
self.keepMarkdown = keepMarkdown
|
self._keepMarkdown = keepMarkdown
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -261,20 +277,20 @@ class Tokenizer():
|
|||||||
if theItem.itemType != nwItemType.ROOT:
|
if theItem.itemType != nwItemType.ROOT:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if self.isFirst:
|
if self._isFirst:
|
||||||
textAlign = self.A_CENTRE
|
textAlign = self.A_CENTRE
|
||||||
self.isFirst = False
|
self._isFirst = False
|
||||||
else:
|
else:
|
||||||
textAlign = self.A_PBB | self.A_CENTRE
|
textAlign = self.A_PBB | self.A_CENTRE
|
||||||
|
|
||||||
locNotes = self._localLookup("Notes")
|
locNotes = self._localLookup("Notes")
|
||||||
theTitle = f"{locNotes}: {theItem.itemName}"
|
theTitle = f"{locNotes}: {theItem.itemName}"
|
||||||
self.theTokens = []
|
self._theTokens = []
|
||||||
self.theTokens.append((
|
self._theTokens.append((
|
||||||
self.T_TITLE, 0, theTitle, None, textAlign
|
self.T_TITLE, 0, theTitle, None, textAlign
|
||||||
))
|
))
|
||||||
if self.keepMarkdown:
|
if self._keepMarkdown:
|
||||||
self.theMarkdown.append(f"# {theTitle}\n\n")
|
self._theMarkdown.append(f"# {theTitle}\n\n")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -282,33 +298,33 @@ class Tokenizer():
|
|||||||
"""Set the text for the tokenizer from a handle. If theText is
|
"""Set the text for the tokenizer from a handle. If theText is
|
||||||
not set, load it from the file.
|
not set, load it from the file.
|
||||||
"""
|
"""
|
||||||
self.theHandle = theHandle
|
self._theHandle = theHandle
|
||||||
self.theItem = self.theProject.projTree[theHandle]
|
self._theItem = self.theProject.projTree[theHandle]
|
||||||
if self.theItem is None:
|
if self._theItem is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.theText = ""
|
self._theText = ""
|
||||||
if theText is not None:
|
if theText is not None:
|
||||||
# If the text is set, just use that
|
# If the text is set, just use that
|
||||||
self.theText = theText
|
self._theText = theText
|
||||||
else:
|
else:
|
||||||
# Otherwise, load it from file
|
# Otherwise, load it from file
|
||||||
theDoc = NWDoc(self.theProject, theHandle)
|
theDoc = NWDoc(self.theProject, theHandle)
|
||||||
theText = theDoc.readDocument()
|
theText = theDoc.readDocument()
|
||||||
if theText:
|
if theText:
|
||||||
self.theText = theText
|
self._theText = theText
|
||||||
|
|
||||||
docSize = len(self.theText)
|
docSize = len(self._theText)
|
||||||
if docSize > nwConst.MAX_DOCSIZE:
|
if docSize > nwConst.MAX_DOCSIZE:
|
||||||
errVal = self.tr("Document '{0}' is too big ({1} MB). Skipping.").format(
|
errVal = self.tr("Document '{0}' is too big ({1} MB). Skipping.").format(
|
||||||
self.theItem.itemName, f"{docSize/1.0e6:.2f}"
|
self._theItem.itemName, f"{docSize/1.0e6:.2f}"
|
||||||
)
|
)
|
||||||
self.theText = "# {0}\n\n{1}\n\n".format(self.tr("ERROR"), errVal)
|
self._theText = "# {0}\n\n{1}\n\n".format(self.tr("ERROR"), errVal)
|
||||||
self.errData.append(errVal)
|
self._errData.append(errVal)
|
||||||
|
|
||||||
self.isNone = self.theItem.itemLayout == nwItemLayout.NO_LAYOUT
|
self._isNone = self._theItem.itemLayout == nwItemLayout.NO_LAYOUT
|
||||||
self.isNovel = self.theItem.itemLayout == nwItemLayout.DOCUMENT
|
self._isNovel = self._theItem.itemLayout == nwItemLayout.DOCUMENT
|
||||||
self.isNote = self.theItem.itemLayout == nwItemLayout.NOTE
|
self._isNote = self._theItem.itemLayout == nwItemLayout.NOTE
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -321,11 +337,11 @@ class Tokenizer():
|
|||||||
for aKey, aVal in self.theProject.autoReplace.items():
|
for aKey, aVal in self.theProject.autoReplace.items():
|
||||||
repDict[f"<{aKey}>"] = aVal
|
repDict[f"<{aKey}>"] = aVal
|
||||||
xRep = re.compile("|".join([re.escape(k) for k in repDict.keys()]), flags=re.DOTALL)
|
xRep = re.compile("|".join([re.escape(k) for k in repDict.keys()]), flags=re.DOTALL)
|
||||||
self.theText = xRep.sub(lambda x: repDict[x.group(0)], self.theText)
|
self._theText = xRep.sub(lambda x: repDict[x.group(0)], self._theText)
|
||||||
|
|
||||||
# Process the character translation map
|
# Process the character translation map
|
||||||
trDict = {nwUnicode.U_MAPOSS: nwUnicode.U_RSQUO}
|
trDict = {nwUnicode.U_MAPOSS: nwUnicode.U_RSQUO}
|
||||||
self.theText = self.theText.translate(str.maketrans(trDict))
|
self._theText = self._theText.translate(str.maketrans(trDict))
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -341,8 +357,8 @@ class Tokenizer():
|
|||||||
escReplace = re.compile(
|
escReplace = re.compile(
|
||||||
"|".join([re.escape(k) for k in escapeDict.keys()]), flags=re.DOTALL
|
"|".join([re.escape(k) for k in escapeDict.keys()]), flags=re.DOTALL
|
||||||
)
|
)
|
||||||
self.theResult = escReplace.sub(
|
self._theResult = escReplace.sub(
|
||||||
lambda x: escapeDict[x.group(0)], self.theResult
|
lambda x: escapeDict[x.group(0)], self._theResult
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -356,7 +372,7 @@ class Tokenizer():
|
|||||||
The format of the token list is an entry with a five-tuple for
|
The format of the token list is an entry with a five-tuple for
|
||||||
each line in the file. The tuple is as follows:
|
each line in the file. The tuple is as follows:
|
||||||
1: The type of the block, self.T_*
|
1: The type of the block, self.T_*
|
||||||
2: The line in file where this block occurred
|
2: The line in the file where this block occurred
|
||||||
3: The text content of the block, without leading tags
|
3: The text content of the block, without leading tags
|
||||||
4: The internal formatting map of the text, self.FMT_*
|
4: The internal formatting map of the text, self.FMT_*
|
||||||
5: The style of the block, self.A_*
|
5: The style of the block, self.A_*
|
||||||
@@ -368,20 +384,20 @@ class Tokenizer():
|
|||||||
(QRegularExpression(nwRegEx.FMT_ST), [None, self.FMT_D_B, None, self.FMT_D_E]),
|
(QRegularExpression(nwRegEx.FMT_ST), [None, self.FMT_D_B, None, self.FMT_D_E]),
|
||||||
]
|
]
|
||||||
|
|
||||||
self.theTokens = []
|
self._theTokens = []
|
||||||
tmpMarkdown = []
|
tmpMarkdown = []
|
||||||
nLine = 0
|
nLine = 0
|
||||||
breakNext = False
|
breakNext = False
|
||||||
for aLine in self.theText.splitlines():
|
for aLine in self._theText.splitlines():
|
||||||
nLine += 1
|
nLine += 1
|
||||||
sLine = aLine.strip()
|
sLine = aLine.strip()
|
||||||
|
|
||||||
# Check for blank lines
|
# Check for blank lines
|
||||||
if len(sLine) == 0:
|
if len(sLine) == 0:
|
||||||
self.theTokens.append((
|
self._theTokens.append((
|
||||||
self.T_EMPTY, nLine, "", None, self.A_NONE
|
self.T_EMPTY, nLine, "", None, self.A_NONE
|
||||||
))
|
))
|
||||||
if self.keepMarkdown:
|
if self._keepMarkdown:
|
||||||
tmpMarkdown.append("\n")
|
tmpMarkdown.append("\n")
|
||||||
|
|
||||||
continue
|
continue
|
||||||
@@ -403,7 +419,7 @@ class Tokenizer():
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
elif sLine == "[VSPACE]":
|
elif sLine == "[VSPACE]":
|
||||||
self.theTokens.append(
|
self._theTokens.append(
|
||||||
(self.T_SKIP, nLine, "", None, sAlign)
|
(self.T_SKIP, nLine, "", None, sAlign)
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
@@ -411,11 +427,11 @@ class Tokenizer():
|
|||||||
elif sLine.startswith("[VSPACE:") and sLine.endswith("]"):
|
elif sLine.startswith("[VSPACE:") and sLine.endswith("]"):
|
||||||
nSkip = checkInt(sLine[8:-1], 0)
|
nSkip = checkInt(sLine[8:-1], 0)
|
||||||
if nSkip >= 1:
|
if nSkip >= 1:
|
||||||
self.theTokens.append(
|
self._theTokens.append(
|
||||||
(self.T_SKIP, nLine, "", None, sAlign)
|
(self.T_SKIP, nLine, "", None, sAlign)
|
||||||
)
|
)
|
||||||
if nSkip > 1:
|
if nSkip > 1:
|
||||||
self.theTokens += (nSkip - 1) * [
|
self._theTokens += (nSkip - 1) * [
|
||||||
(self.T_SKIP, nLine, "", None, self.A_NONE)
|
(self.T_SKIP, nLine, "", None, self.A_NONE)
|
||||||
]
|
]
|
||||||
continue
|
continue
|
||||||
@@ -424,87 +440,87 @@ class Tokenizer():
|
|||||||
cLine = aLine[1:].lstrip()
|
cLine = aLine[1:].lstrip()
|
||||||
synTag = cLine[:9].lower()
|
synTag = cLine[:9].lower()
|
||||||
if synTag == "synopsis:":
|
if synTag == "synopsis:":
|
||||||
self.theTokens.append((
|
self._theTokens.append((
|
||||||
self.T_SYNOPSIS, nLine, cLine[9:].strip(), None, sAlign
|
self.T_SYNOPSIS, nLine, cLine[9:].strip(), None, sAlign
|
||||||
))
|
))
|
||||||
if self.doSynopsis and self.keepMarkdown:
|
if self._doSynopsis and self._keepMarkdown:
|
||||||
tmpMarkdown.append("%s\n" % aLine)
|
tmpMarkdown.append("%s\n" % aLine)
|
||||||
else:
|
else:
|
||||||
self.theTokens.append((
|
self._theTokens.append((
|
||||||
self.T_COMMENT, nLine, aLine[1:].strip(), None, sAlign
|
self.T_COMMENT, nLine, aLine[1:].strip(), None, sAlign
|
||||||
))
|
))
|
||||||
if self.doComments and self.keepMarkdown:
|
if self._doComments and self._keepMarkdown:
|
||||||
tmpMarkdown.append("%s\n" % aLine)
|
tmpMarkdown.append("%s\n" % aLine)
|
||||||
|
|
||||||
elif aLine[0] == "@":
|
elif aLine[0] == "@":
|
||||||
self.theTokens.append((
|
self._theTokens.append((
|
||||||
self.T_KEYWORD, nLine, aLine[1:].strip(), None, sAlign
|
self.T_KEYWORD, nLine, aLine[1:].strip(), None, sAlign
|
||||||
))
|
))
|
||||||
if self.doKeywords and self.keepMarkdown:
|
if self._doKeywords and self._keepMarkdown:
|
||||||
tmpMarkdown.append("%s\n" % aLine)
|
tmpMarkdown.append("%s\n" % aLine)
|
||||||
|
|
||||||
elif aLine[:2] == "# ":
|
elif aLine[:2] == "# ":
|
||||||
if self.isNovel:
|
if self._isNovel:
|
||||||
sAlign |= self.A_CENTRE
|
sAlign |= self.A_CENTRE
|
||||||
sAlign |= self.A_PBB
|
sAlign |= self.A_PBB
|
||||||
|
|
||||||
self.theTokens.append((
|
self._theTokens.append((
|
||||||
self.T_HEAD1, nLine, aLine[2:].strip(), None, sAlign
|
self.T_HEAD1, nLine, aLine[2:].strip(), None, sAlign
|
||||||
))
|
))
|
||||||
if self.keepMarkdown:
|
if self._keepMarkdown:
|
||||||
tmpMarkdown.append("%s\n" % aLine)
|
tmpMarkdown.append("%s\n" % aLine)
|
||||||
|
|
||||||
elif aLine[:3] == "## ":
|
elif aLine[:3] == "## ":
|
||||||
if self.isNovel:
|
if self._isNovel:
|
||||||
sAlign |= self.A_PBB
|
sAlign |= self.A_PBB
|
||||||
|
|
||||||
self.theTokens.append((
|
self._theTokens.append((
|
||||||
self.T_HEAD2, nLine, aLine[3:].strip(), None, sAlign
|
self.T_HEAD2, nLine, aLine[3:].strip(), None, sAlign
|
||||||
))
|
))
|
||||||
if self.keepMarkdown:
|
if self._keepMarkdown:
|
||||||
tmpMarkdown.append("%s\n" % aLine)
|
tmpMarkdown.append("%s\n" % aLine)
|
||||||
|
|
||||||
elif aLine[:4] == "### ":
|
elif aLine[:4] == "### ":
|
||||||
self.theTokens.append((
|
self._theTokens.append((
|
||||||
self.T_HEAD3, nLine, aLine[4:].strip(), None, sAlign
|
self.T_HEAD3, nLine, aLine[4:].strip(), None, sAlign
|
||||||
))
|
))
|
||||||
if self.keepMarkdown:
|
if self._keepMarkdown:
|
||||||
tmpMarkdown.append("%s\n" % aLine)
|
tmpMarkdown.append("%s\n" % aLine)
|
||||||
|
|
||||||
elif aLine[:5] == "#### ":
|
elif aLine[:5] == "#### ":
|
||||||
self.theTokens.append((
|
self._theTokens.append((
|
||||||
self.T_HEAD4, nLine, aLine[5:].strip(), None, sAlign
|
self.T_HEAD4, nLine, aLine[5:].strip(), None, sAlign
|
||||||
))
|
))
|
||||||
if self.keepMarkdown:
|
if self._keepMarkdown:
|
||||||
tmpMarkdown.append("%s\n" % aLine)
|
tmpMarkdown.append("%s\n" % aLine)
|
||||||
|
|
||||||
elif aLine[:3] == "#! ":
|
elif aLine[:3] == "#! ":
|
||||||
if self.isNovel:
|
if self._isNovel:
|
||||||
tStyle = self.T_TITLE
|
tStyle = self.T_TITLE
|
||||||
else:
|
else:
|
||||||
tStyle = self.T_HEAD1
|
tStyle = self.T_HEAD1
|
||||||
|
|
||||||
self.theTokens.append((
|
self._theTokens.append((
|
||||||
tStyle, nLine, aLine[3:].strip(), None, sAlign | self.A_CENTRE
|
tStyle, nLine, aLine[3:].strip(), None, sAlign | self.A_CENTRE
|
||||||
))
|
))
|
||||||
if self.keepMarkdown:
|
if self._keepMarkdown:
|
||||||
tmpMarkdown.append("%s\n" % aLine)
|
tmpMarkdown.append("%s\n" % aLine)
|
||||||
|
|
||||||
elif aLine[:4] == "##! ":
|
elif aLine[:4] == "##! ":
|
||||||
if self.isNovel:
|
if self._isNovel:
|
||||||
tStyle = self.T_UNNUM
|
tStyle = self.T_UNNUM
|
||||||
sAlign |= self.A_PBB
|
sAlign |= self.A_PBB
|
||||||
else:
|
else:
|
||||||
tStyle = self.T_HEAD2
|
tStyle = self.T_HEAD2
|
||||||
|
|
||||||
self.theTokens.append((
|
self._theTokens.append((
|
||||||
tStyle, nLine, aLine[4:].strip(), None, sAlign
|
tStyle, nLine, aLine[4:].strip(), None, sAlign
|
||||||
))
|
))
|
||||||
if self.keepMarkdown:
|
if self._keepMarkdown:
|
||||||
tmpMarkdown.append("%s\n" % aLine)
|
tmpMarkdown.append("%s\n" % aLine)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if not self.doBodyText:
|
if not self._doBodyText:
|
||||||
# Skip all body text
|
# Skip all body text
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -554,33 +570,33 @@ class Tokenizer():
|
|||||||
# Save the line as is, but append the array of formatting locations
|
# Save the line as is, but append the array of formatting locations
|
||||||
# sorted by position
|
# sorted by position
|
||||||
fmtPos = sorted(fmtPos, key=itemgetter(0))
|
fmtPos = sorted(fmtPos, key=itemgetter(0))
|
||||||
self.theTokens.append((
|
self._theTokens.append((
|
||||||
self.T_TEXT, nLine, aLine, fmtPos, sAlign
|
self.T_TEXT, nLine, aLine, fmtPos, sAlign
|
||||||
))
|
))
|
||||||
if self.keepMarkdown:
|
if self._keepMarkdown:
|
||||||
tmpMarkdown.append("%s\n" % aLine)
|
tmpMarkdown.append("%s\n" % aLine)
|
||||||
|
|
||||||
# If we have content, turn off the first page flag
|
# If we have content, turn off the first page flag
|
||||||
if self.isFirst and self.theTokens:
|
if self._isFirst and self._theTokens:
|
||||||
self.isFirst = False
|
self._isFirst = False
|
||||||
|
|
||||||
# Make sure the token array doesn't start with a page break
|
# Make sure the token array doesn't start with a page break
|
||||||
# on the very first page, adding a blank first page.
|
# on the very first page, adding a blank first page.
|
||||||
if self.theTokens[0][4] & self.A_PBB:
|
if self._theTokens[0][4] & self.A_PBB:
|
||||||
tToken = self.theTokens[0]
|
tToken = self._theTokens[0]
|
||||||
self.theTokens[0] = (
|
self._theTokens[0] = (
|
||||||
tToken[0], tToken[1], tToken[2], tToken[3], tToken[4] & ~self.A_PBB
|
tToken[0], tToken[1], tToken[2], tToken[3], tToken[4] & ~self.A_PBB
|
||||||
)
|
)
|
||||||
|
|
||||||
# Always add an empty line at the end of the file
|
# Always add an empty line at the end of the file
|
||||||
self.theTokens.append((
|
self._theTokens.append((
|
||||||
self.T_EMPTY, nLine, "", None, self.A_NONE
|
self.T_EMPTY, nLine, "", None, self.A_NONE
|
||||||
))
|
))
|
||||||
if self.keepMarkdown:
|
if self._keepMarkdown:
|
||||||
tmpMarkdown.append("\n")
|
tmpMarkdown.append("\n")
|
||||||
|
|
||||||
if self.keepMarkdown:
|
if self._keepMarkdown:
|
||||||
self.theMarkdown.append("".join(tmpMarkdown))
|
self._theMarkdown.append("".join(tmpMarkdown))
|
||||||
|
|
||||||
# Second Pass
|
# Second Pass
|
||||||
# ===========
|
# ===========
|
||||||
@@ -588,13 +604,13 @@ class Tokenizer():
|
|||||||
|
|
||||||
pToken = (self.T_EMPTY, 0, "", None, self.A_NONE)
|
pToken = (self.T_EMPTY, 0, "", None, self.A_NONE)
|
||||||
nToken = (self.T_EMPTY, 0, "", None, self.A_NONE)
|
nToken = (self.T_EMPTY, 0, "", None, self.A_NONE)
|
||||||
tCount = len(self.theTokens)
|
tCount = len(self._theTokens)
|
||||||
for n, tToken in enumerate(self.theTokens):
|
for n, tToken in enumerate(self._theTokens):
|
||||||
|
|
||||||
if n > 0:
|
if n > 0:
|
||||||
pToken = self.theTokens[n-1]
|
pToken = self._theTokens[n-1]
|
||||||
if n < tCount - 1:
|
if n < tCount - 1:
|
||||||
nToken = self.theTokens[n+1]
|
nToken = self._theTokens[n+1]
|
||||||
|
|
||||||
if tToken[0] == self.T_KEYWORD:
|
if tToken[0] == self.T_KEYWORD:
|
||||||
aStyle = tToken[4]
|
aStyle = tToken[4]
|
||||||
@@ -602,7 +618,7 @@ class Tokenizer():
|
|||||||
aStyle |= self.A_Z_TOPMRG
|
aStyle |= self.A_Z_TOPMRG
|
||||||
if nToken[0] == self.T_KEYWORD:
|
if nToken[0] == self.T_KEYWORD:
|
||||||
aStyle |= self.A_Z_BTMMRG
|
aStyle |= self.A_Z_BTMMRG
|
||||||
self.theTokens[n] = (
|
self._theTokens[n] = (
|
||||||
tToken[0], tToken[1], tToken[2], tToken[3], aStyle
|
tToken[0], tToken[1], tToken[2], tToken[3], aStyle
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -612,20 +628,20 @@ class Tokenizer():
|
|||||||
"""Apply formatting to the text headers for novel files. This
|
"""Apply formatting to the text headers for novel files. This
|
||||||
also applies chapter and scene numbering.
|
also applies chapter and scene numbering.
|
||||||
"""
|
"""
|
||||||
if not self.isNovel:
|
if not self._isNovel:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for n, tToken in enumerate(self.theTokens):
|
for n, tToken in enumerate(self._theTokens):
|
||||||
|
|
||||||
# In case we see text before a scene, we reset the flag
|
# In case we see text before a scene, we reset the flag
|
||||||
if tToken[0] == self.T_TEXT:
|
if tToken[0] == self.T_TEXT:
|
||||||
self.firstScene = False
|
self._firstScene = False
|
||||||
|
|
||||||
elif tToken[0] == self.T_HEAD1:
|
elif tToken[0] == self.T_HEAD1:
|
||||||
# Partition
|
# Partition
|
||||||
|
|
||||||
tTemp = self._formatHeading(self.fmtTitle, tToken[2])
|
tTemp = self._formatHeading(self._fmtTitle, tToken[2])
|
||||||
self.theTokens[n] = (
|
self._theTokens[n] = (
|
||||||
tToken[0], tToken[1], tTemp, None, tToken[4]
|
tToken[0], tToken[1], tTemp, None, tToken[4]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -634,75 +650,75 @@ class Tokenizer():
|
|||||||
|
|
||||||
# Numbered or Unnumbered
|
# Numbered or Unnumbered
|
||||||
if tToken[0] == self.T_UNNUM:
|
if tToken[0] == self.T_UNNUM:
|
||||||
tTemp = self._formatHeading(self.fmtUnNum, tToken[2])
|
tTemp = self._formatHeading(self._fmtUnNum, tToken[2])
|
||||||
else:
|
else:
|
||||||
self.numChapter += 1
|
self._numChapter += 1
|
||||||
tTemp = self._formatHeading(self.fmtChapter, tToken[2])
|
tTemp = self._formatHeading(self._fmtChapter, tToken[2])
|
||||||
|
|
||||||
# Format the chapter header
|
# Format the chapter header
|
||||||
self.theTokens[n] = (
|
self._theTokens[n] = (
|
||||||
tToken[0], tToken[1], tTemp, None, tToken[4]
|
tToken[0], tToken[1], tTemp, None, tToken[4]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set scene variables
|
# Set scene variables
|
||||||
self.firstScene = True
|
self._firstScene = True
|
||||||
self.numChScene = 0
|
self._numChScene = 0
|
||||||
|
|
||||||
elif tToken[0] == self.T_HEAD3:
|
elif tToken[0] == self.T_HEAD3:
|
||||||
# Scene
|
# Scene
|
||||||
|
|
||||||
self.numChScene += 1
|
self._numChScene += 1
|
||||||
self.numAbsScene += 1
|
self._numAbsScene += 1
|
||||||
|
|
||||||
tTemp = self._formatHeading(self.fmtScene, tToken[2])
|
tTemp = self._formatHeading(self._fmtScene, tToken[2])
|
||||||
if tTemp == "" and self.hideScene:
|
if tTemp == "" and self._hideScene:
|
||||||
self.theTokens[n] = (
|
self._theTokens[n] = (
|
||||||
self.T_EMPTY, tToken[1], "", None, self.A_NONE
|
self.T_EMPTY, tToken[1], "", None, self.A_NONE
|
||||||
)
|
)
|
||||||
elif tTemp == "" and not self.hideScene:
|
elif tTemp == "" and not self._hideScene:
|
||||||
if self.firstScene:
|
if self._firstScene:
|
||||||
self.theTokens[n] = (
|
self._theTokens[n] = (
|
||||||
self.T_EMPTY, tToken[1], "", None, self.A_NONE
|
self.T_EMPTY, tToken[1], "", None, self.A_NONE
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.theTokens[n] = (
|
self._theTokens[n] = (
|
||||||
self.T_SKIP, tToken[1], "", None, tToken[4]
|
self.T_SKIP, tToken[1], "", None, tToken[4]
|
||||||
)
|
)
|
||||||
elif tTemp == self.fmtScene:
|
elif tTemp == self._fmtScene:
|
||||||
if self.firstScene:
|
if self._firstScene:
|
||||||
self.theTokens[n] = (
|
self._theTokens[n] = (
|
||||||
self.T_EMPTY, tToken[1], "", None, self.A_NONE
|
self.T_EMPTY, tToken[1], "", None, self.A_NONE
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.theTokens[n] = (
|
self._theTokens[n] = (
|
||||||
self.T_SEP, tToken[1], tTemp, None, tToken[4] | self.A_CENTRE
|
self.T_SEP, tToken[1], tTemp, None, tToken[4] | self.A_CENTRE
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.theTokens[n] = (
|
self._theTokens[n] = (
|
||||||
tToken[0], tToken[1], tTemp, None, tToken[4]
|
tToken[0], tToken[1], tTemp, None, tToken[4]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Definitely no longer the first scene
|
# Definitely no longer the first scene
|
||||||
self.firstScene = False
|
self._firstScene = False
|
||||||
|
|
||||||
elif tToken[0] == self.T_HEAD4:
|
elif tToken[0] == self.T_HEAD4:
|
||||||
# Section
|
# Section
|
||||||
|
|
||||||
tTemp = self._formatHeading(self.fmtSection, tToken[2])
|
tTemp = self._formatHeading(self._fmtSection, tToken[2])
|
||||||
if tTemp == "" and self.hideSection:
|
if tTemp == "" and self._hideSection:
|
||||||
self.theTokens[n] = (
|
self._theTokens[n] = (
|
||||||
self.T_EMPTY, tToken[1], "", None, self.A_NONE
|
self.T_EMPTY, tToken[1], "", None, self.A_NONE
|
||||||
)
|
)
|
||||||
elif tTemp == "" and not self.hideSection:
|
elif tTemp == "" and not self._hideSection:
|
||||||
self.theTokens[n] = (
|
self._theTokens[n] = (
|
||||||
self.T_SKIP, tToken[1], "", None, tToken[4]
|
self.T_SKIP, tToken[1], "", None, tToken[4]
|
||||||
)
|
)
|
||||||
elif tTemp == self.fmtSection:
|
elif tTemp == self._fmtSection:
|
||||||
self.theTokens[n] = (
|
self._theTokens[n] = (
|
||||||
self.T_SEP, tToken[1], tTemp, None, tToken[4] | self.A_CENTRE
|
self.T_SEP, tToken[1], tTemp, None, tToken[4] | self.A_CENTRE
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.theTokens[n] = (
|
self._theTokens[n] = (
|
||||||
tToken[0], tToken[1], tTemp, None, tToken[4]
|
tToken[0], tToken[1], tTemp, None, tToken[4]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -712,7 +728,7 @@ class Tokenizer():
|
|||||||
"""Save the data to a plain text file.
|
"""Save the data to a plain text file.
|
||||||
"""
|
"""
|
||||||
with open(savePath, mode="w", encoding="utf-8") as outFile:
|
with open(savePath, mode="w", encoding="utf-8") as outFile:
|
||||||
for nwdPage in self.theMarkdown:
|
for nwdPage in self._theMarkdown:
|
||||||
outFile.write(nwdPage)
|
outFile.write(nwdPage)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -724,15 +740,15 @@ class Tokenizer():
|
|||||||
"""Replaces the %keyword% strings.
|
"""Replaces the %keyword% strings.
|
||||||
"""
|
"""
|
||||||
theTitle = theTitle.replace(r"%title%", theText)
|
theTitle = theTitle.replace(r"%title%", theText)
|
||||||
theTitle = theTitle.replace(r"%ch%", str(self.numChapter))
|
theTitle = theTitle.replace(r"%ch%", str(self._numChapter))
|
||||||
theTitle = theTitle.replace(r"%sc%", str(self.numChScene))
|
theTitle = theTitle.replace(r"%sc%", str(self._numChScene))
|
||||||
theTitle = theTitle.replace(r"%sca%", str(self.numAbsScene))
|
theTitle = theTitle.replace(r"%sca%", str(self._numAbsScene))
|
||||||
if r"%chw%" in theTitle:
|
if r"%chw%" in theTitle:
|
||||||
theTitle = theTitle.replace(r"%chw%", self._localLookup(self.numChapter))
|
theTitle = theTitle.replace(r"%chw%", self._localLookup(self._numChapter))
|
||||||
if r"%chi%" in theTitle:
|
if r"%chi%" in theTitle:
|
||||||
theTitle = theTitle.replace(r"%chi%", numberToRoman(self.numChapter, True))
|
theTitle = theTitle.replace(r"%chi%", numberToRoman(self._numChapter, True))
|
||||||
if r"%chI%" in theTitle:
|
if r"%chI%" in theTitle:
|
||||||
theTitle = theTitle.replace(r"%chI%", numberToRoman(self.numChapter, False))
|
theTitle = theTitle.replace(r"%chI%", numberToRoman(self._numChapter, False))
|
||||||
|
|
||||||
return theTitle[:1].upper() + theTitle[1:]
|
return theTitle[:1].upper() + theTitle[1:]
|
||||||
|
|
||||||
|
|||||||
+24
-16
@@ -39,21 +39,29 @@ class ToMarkdown(Tokenizer):
|
|||||||
def __init__(self, theProject):
|
def __init__(self, theProject):
|
||||||
Tokenizer.__init__(self, theProject)
|
Tokenizer.__init__(self, theProject)
|
||||||
|
|
||||||
self.genMode = self.M_STD
|
self._genMode = self.M_STD
|
||||||
self.fullMD = []
|
self._fullMD = []
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
##
|
||||||
|
# Properties
|
||||||
|
##
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fullMD(self):
|
||||||
|
return self._fullMD
|
||||||
|
|
||||||
##
|
##
|
||||||
# Setters
|
# Setters
|
||||||
##
|
##
|
||||||
|
|
||||||
def setStandardMarkdown(self):
|
def setStandardMarkdown(self):
|
||||||
self.genMode = self.M_STD
|
self._genMode = self.M_STD
|
||||||
return
|
return
|
||||||
|
|
||||||
def setGitHubMarkdown(self):
|
def setGitHubMarkdown(self):
|
||||||
self.genMode = self.M_GH
|
self._genMode = self.M_GH
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -63,13 +71,13 @@ class ToMarkdown(Tokenizer):
|
|||||||
def getFullResultSize(self):
|
def getFullResultSize(self):
|
||||||
"""Return the size of the full Markdown result.
|
"""Return the size of the full Markdown result.
|
||||||
"""
|
"""
|
||||||
return sum([len(x) for x in self.fullMD])
|
return sum([len(x) for x in self._fullMD])
|
||||||
|
|
||||||
def doConvert(self):
|
def doConvert(self):
|
||||||
"""Convert the list of text tokens into a HTML document saved
|
"""Convert the list of text tokens into a HTML document saved
|
||||||
to theResult.
|
to theResult.
|
||||||
"""
|
"""
|
||||||
if self.genMode == self.M_STD:
|
if self._genMode == self.M_STD:
|
||||||
# Standard
|
# Standard
|
||||||
mdTags = {
|
mdTags = {
|
||||||
self.FMT_B_B: "**",
|
self.FMT_B_B: "**",
|
||||||
@@ -90,12 +98,12 @@ class ToMarkdown(Tokenizer):
|
|||||||
self.FMT_D_E: "~~",
|
self.FMT_D_E: "~~",
|
||||||
}
|
}
|
||||||
|
|
||||||
self.theResult = ""
|
self._theResult = ""
|
||||||
|
|
||||||
thisPar = []
|
thisPar = []
|
||||||
tmpResult = []
|
tmpResult = []
|
||||||
|
|
||||||
for tType, _, tText, tFormat, tStyle in self.theTokens:
|
for tType, _, tText, tFormat, tStyle in self._theTokens:
|
||||||
|
|
||||||
# Process Text Type
|
# Process Text Type
|
||||||
if tType == self.T_EMPTY:
|
if tType == self.T_EMPTY:
|
||||||
@@ -140,21 +148,21 @@ class ToMarkdown(Tokenizer):
|
|||||||
tTemp = tTemp[:xPos] + mdTags[xFmt] + tTemp[xPos+xLen:]
|
tTemp = tTemp[:xPos] + mdTags[xFmt] + tTemp[xPos+xLen:]
|
||||||
thisPar.append(tTemp.rstrip())
|
thisPar.append(tTemp.rstrip())
|
||||||
|
|
||||||
elif tType == self.T_SYNOPSIS and self.doSynopsis:
|
elif tType == self.T_SYNOPSIS and self._doSynopsis:
|
||||||
locName = self._localLookup("Synopsis")
|
locName = self._localLookup("Synopsis")
|
||||||
tmpResult.append(f"**{locName}:** {tText}\n\n")
|
tmpResult.append(f"**{locName}:** {tText}\n\n")
|
||||||
|
|
||||||
elif tType == self.T_COMMENT and self.doComments:
|
elif tType == self.T_COMMENT and self._doComments:
|
||||||
locName = self._localLookup("Comment")
|
locName = self._localLookup("Comment")
|
||||||
tmpResult.append(f"**{locName}:** {tText}\n\n")
|
tmpResult.append(f"**{locName}:** {tText}\n\n")
|
||||||
|
|
||||||
elif tType == self.T_KEYWORD and self.doKeywords:
|
elif tType == self.T_KEYWORD and self._doKeywords:
|
||||||
tmpResult.append(self._formatKeywords(tText, tStyle))
|
tmpResult.append(self._formatKeywords(tText, tStyle))
|
||||||
|
|
||||||
self.theResult = "".join(tmpResult)
|
self._theResult = "".join(tmpResult)
|
||||||
tmpResult = []
|
tmpResult = []
|
||||||
|
|
||||||
self.fullMD.append(self.theResult)
|
self._fullMD.append(self._theResult)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -162,7 +170,7 @@ class ToMarkdown(Tokenizer):
|
|||||||
"""Save the data to a plain text file.
|
"""Save the data to a plain text file.
|
||||||
"""
|
"""
|
||||||
with open(savePath, mode="w", encoding="utf-8") as outFile:
|
with open(savePath, mode="w", encoding="utf-8") as outFile:
|
||||||
theText = "".join(self.fullMD)
|
theText = "".join(self._fullMD)
|
||||||
outFile.write(theText)
|
outFile.write(theText)
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -172,10 +180,10 @@ class ToMarkdown(Tokenizer):
|
|||||||
"""
|
"""
|
||||||
fullMD = []
|
fullMD = []
|
||||||
eightSpace = spaceChar*nSpaces
|
eightSpace = spaceChar*nSpaces
|
||||||
for aPage in self.fullMD:
|
for aPage in self._fullMD:
|
||||||
fullMD.append(aPage.replace("\t", eightSpace))
|
fullMD.append(aPage.replace("\t", eightSpace))
|
||||||
|
|
||||||
self.fullMD = fullMD
|
self._fullMD = fullMD
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|||||||
+77
-77
@@ -115,27 +115,27 @@ class ToOdt(Tokenizer):
|
|||||||
self._errData = [] # List of errors encountered
|
self._errData = [] # List of errors encountered
|
||||||
|
|
||||||
# Properties
|
# Properties
|
||||||
self.textFont = "Liberation Serif"
|
self._textFont = "Liberation Serif"
|
||||||
self.textSize = 12
|
self._textSize = 12
|
||||||
self.textFixed = False
|
self._textFixed = False
|
||||||
self.colourHead = False
|
self._colourHead = False
|
||||||
self.headerText = ""
|
self._headerText = ""
|
||||||
|
|
||||||
# Internal
|
# Internal
|
||||||
self._fontFamily = "'Liberation Serif'"
|
self._fontFamily = "'Liberation Serif'"
|
||||||
self._fontPitch = "variable"
|
self._fontPitch = "variable"
|
||||||
self._fSizeTitle = "30pt"
|
self._fSizeTitle = "30pt"
|
||||||
self._fSizeHead1 = "24pt"
|
self._fSizeHead1 = "24pt"
|
||||||
self._fSizeHead2 = "20pt"
|
self._fSizeHead2 = "20pt"
|
||||||
self._fSizeHead3 = "16pt"
|
self._fSizeHead3 = "16pt"
|
||||||
self._fSizeHead4 = "14pt"
|
self._fSizeHead4 = "14pt"
|
||||||
self._fSizeHead = "14pt"
|
self._fSizeHead = "14pt"
|
||||||
self._fSizeText = "12pt"
|
self._fSizeText = "12pt"
|
||||||
self._lineHeight = "115%"
|
self._fLineHeight = "115%"
|
||||||
self._blockIndent = "1.693cm"
|
self._fBlockIndent = "1.693cm"
|
||||||
self._textAlign = "left"
|
self._textAlign = "left"
|
||||||
self._dLanguage = "en"
|
self._dLanguage = "en"
|
||||||
self._dCountry = "GB"
|
self._dCountry = "GB"
|
||||||
|
|
||||||
# Text Margings in Units of em
|
# Text Margings in Units of em
|
||||||
self._mTopTitle = "0.423cm"
|
self._mTopTitle = "0.423cm"
|
||||||
@@ -192,7 +192,7 @@ class ToOdt(Tokenizer):
|
|||||||
def setColourHeaders(self, doColour):
|
def setColourHeaders(self, doColour):
|
||||||
"""Enable/disable coloured headings and comments.
|
"""Enable/disable coloured headings and comments.
|
||||||
"""
|
"""
|
||||||
self.colourHead = doColour
|
self._colourHead = doColour
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -209,40 +209,40 @@ class ToOdt(Tokenizer):
|
|||||||
# Initialise Variables
|
# Initialise Variables
|
||||||
# ====================
|
# ====================
|
||||||
|
|
||||||
self._fontFamily = self.textFont
|
self._fontFamily = self._textFont
|
||||||
if len(self.textFont.split()) > 1:
|
if len(self._textFont.split()) > 1:
|
||||||
self._fontFamily = f"'{self.textFont}'"
|
self._fontFamily = f"'{self._textFont}'"
|
||||||
self._fontPitch = "fixed" if self.textFixed else "variable"
|
self._fontPitch = "fixed" if self._textFixed else "variable"
|
||||||
|
|
||||||
self._fSizeTitle = f"{round(2.50 * self.textSize):d}pt"
|
self._fSizeTitle = f"{round(2.50 * self._textSize):d}pt"
|
||||||
self._fSizeHead1 = f"{round(2.00 * self.textSize):d}pt"
|
self._fSizeHead1 = f"{round(2.00 * self._textSize):d}pt"
|
||||||
self._fSizeHead2 = f"{round(1.60 * self.textSize):d}pt"
|
self._fSizeHead2 = f"{round(1.60 * self._textSize):d}pt"
|
||||||
self._fSizeHead3 = f"{round(1.30 * self.textSize):d}pt"
|
self._fSizeHead3 = f"{round(1.30 * self._textSize):d}pt"
|
||||||
self._fSizeHead4 = f"{round(1.15 * self.textSize):d}pt"
|
self._fSizeHead4 = f"{round(1.15 * self._textSize):d}pt"
|
||||||
self._fSizeHead = f"{round(1.15 * self.textSize):d}pt"
|
self._fSizeHead = f"{round(1.15 * self._textSize):d}pt"
|
||||||
self._fSizeText = f"{self.textSize:d}pt"
|
self._fSizeText = f"{self._textSize:d}pt"
|
||||||
|
|
||||||
mScale = self.lineHeight/1.15
|
mScale = self._lineHeight/1.15
|
||||||
|
|
||||||
self._mTopTitle = self._emToCm(mScale * self.marginTitle[0])
|
self._mTopTitle = self._emToCm(mScale * self._marginTitle[0])
|
||||||
self._mTopHead1 = self._emToCm(mScale * self.marginHead1[0])
|
self._mTopHead1 = self._emToCm(mScale * self._marginHead1[0])
|
||||||
self._mTopHead2 = self._emToCm(mScale * self.marginHead2[0])
|
self._mTopHead2 = self._emToCm(mScale * self._marginHead2[0])
|
||||||
self._mTopHead3 = self._emToCm(mScale * self.marginHead3[0])
|
self._mTopHead3 = self._emToCm(mScale * self._marginHead3[0])
|
||||||
self._mTopHead4 = self._emToCm(mScale * self.marginHead4[0])
|
self._mTopHead4 = self._emToCm(mScale * self._marginHead4[0])
|
||||||
self._mTopHead = self._emToCm(mScale * self.marginHead4[0])
|
self._mTopHead = self._emToCm(mScale * self._marginHead4[0])
|
||||||
self._mTopText = self._emToCm(mScale * self.marginText[0])
|
self._mTopText = self._emToCm(mScale * self._marginText[0])
|
||||||
self._mTopMeta = self._emToCm(mScale * self.marginMeta[0])
|
self._mTopMeta = self._emToCm(mScale * self._marginMeta[0])
|
||||||
|
|
||||||
self._mBotTitle = self._emToCm(mScale * self.marginTitle[1])
|
self._mBotTitle = self._emToCm(mScale * self._marginTitle[1])
|
||||||
self._mBotHead1 = self._emToCm(mScale * self.marginHead1[1])
|
self._mBotHead1 = self._emToCm(mScale * self._marginHead1[1])
|
||||||
self._mBotHead2 = self._emToCm(mScale * self.marginHead2[1])
|
self._mBotHead2 = self._emToCm(mScale * self._marginHead2[1])
|
||||||
self._mBotHead3 = self._emToCm(mScale * self.marginHead3[1])
|
self._mBotHead3 = self._emToCm(mScale * self._marginHead3[1])
|
||||||
self._mBotHead4 = self._emToCm(mScale * self.marginHead4[1])
|
self._mBotHead4 = self._emToCm(mScale * self._marginHead4[1])
|
||||||
self._mBotHead = self._emToCm(mScale * self.marginHead4[1])
|
self._mBotHead = self._emToCm(mScale * self._marginHead4[1])
|
||||||
self._mBotText = self._emToCm(mScale * self.marginText[1])
|
self._mBotText = self._emToCm(mScale * self._marginText[1])
|
||||||
self._mBotMeta = self._emToCm(mScale * self.marginMeta[1])
|
self._mBotMeta = self._emToCm(mScale * self._marginMeta[1])
|
||||||
|
|
||||||
if self.colourHead:
|
if self._colourHead:
|
||||||
self._colHead12 = "#2a6099"
|
self._colHead12 = "#2a6099"
|
||||||
self._opaHead12 = "100%"
|
self._opaHead12 = "100%"
|
||||||
self._colHead34 = "#444444"
|
self._colHead34 = "#444444"
|
||||||
@@ -250,9 +250,9 @@ class ToOdt(Tokenizer):
|
|||||||
self._colMetaTx = "#813709"
|
self._colMetaTx = "#813709"
|
||||||
self._opaMetaTx = "100%"
|
self._opaMetaTx = "100%"
|
||||||
|
|
||||||
self._lineHeight = f"{round(100 * self.lineHeight):d}%"
|
self._fLineHeight = f"{round(100 * self._lineHeight):d}%"
|
||||||
self._blockIndent = self._emToCm(self.blockIndent)
|
self._fBlockIndent = self._emToCm(self._blockIndent)
|
||||||
self._textAlign = "justify" if self.doJustify else "left"
|
self._textAlign = "justify" if self._doJustify else "left"
|
||||||
|
|
||||||
# Clear Errors
|
# Clear Errors
|
||||||
self._errData = []
|
self._errData = []
|
||||||
@@ -260,10 +260,10 @@ class ToOdt(Tokenizer):
|
|||||||
# Document Header
|
# Document Header
|
||||||
# ===============
|
# ===============
|
||||||
|
|
||||||
if self.headerText == "":
|
if self._headerText == "":
|
||||||
theTitle = self.theProject.bookTitle
|
theTitle = self.theProject.bookTitle
|
||||||
theAuth = self.theProject.getAuthors()
|
theAuth = self.theProject.getAuthors()
|
||||||
self.headerText = f"{theTitle} / {theAuth} /"
|
self._headerText = f"{theTitle} / {theAuth} /"
|
||||||
|
|
||||||
# Create Roots
|
# Create Roots
|
||||||
# ============
|
# ============
|
||||||
@@ -272,7 +272,7 @@ class ToOdt(Tokenizer):
|
|||||||
tAttr[_mkTag("office", "version")] = X_VERS
|
tAttr[_mkTag("office", "version")] = X_VERS
|
||||||
|
|
||||||
fAttr = {}
|
fAttr = {}
|
||||||
fAttr[_mkTag("style", "name")] = self.textFont
|
fAttr[_mkTag("style", "name")] = self._textFont
|
||||||
fAttr[_mkTag("style", "font-pitch")] = self._fontPitch
|
fAttr[_mkTag("style", "font-pitch")] = self._fontPitch
|
||||||
|
|
||||||
if self._isFlat:
|
if self._isFlat:
|
||||||
@@ -345,7 +345,7 @@ class ToOdt(Tokenizer):
|
|||||||
def doConvert(self):
|
def doConvert(self):
|
||||||
"""Convert the list of text tokens into XML elements.
|
"""Convert the list of text tokens into XML elements.
|
||||||
"""
|
"""
|
||||||
self.theResult = "" # Not used, but cleared just in case
|
self._theResult = "" # Not used, but cleared just in case
|
||||||
|
|
||||||
odtTags = {
|
odtTags = {
|
||||||
self.FMT_B_B: "_B", # Bold open format
|
self.FMT_B_B: "_B", # Bold open format
|
||||||
@@ -359,7 +359,7 @@ class ToOdt(Tokenizer):
|
|||||||
thisPar = []
|
thisPar = []
|
||||||
thisFmt = []
|
thisFmt = []
|
||||||
parStyle = None
|
parStyle = None
|
||||||
for tType, _, tText, tFormat, tStyle in self.theTokens:
|
for tType, _, tText, tFormat, tStyle in self._theTokens:
|
||||||
|
|
||||||
# Styles
|
# Styles
|
||||||
oStyle = ODTParagraphStyle()
|
oStyle = ODTParagraphStyle()
|
||||||
@@ -385,14 +385,14 @@ class ToOdt(Tokenizer):
|
|||||||
oStyle.setMarginTop("0.000cm")
|
oStyle.setMarginTop("0.000cm")
|
||||||
|
|
||||||
if tStyle & self.A_IND_L:
|
if tStyle & self.A_IND_L:
|
||||||
oStyle.setMarginLeft(self._blockIndent)
|
oStyle.setMarginLeft(self._fBlockIndent)
|
||||||
if tStyle & self.A_IND_R:
|
if tStyle & self.A_IND_R:
|
||||||
oStyle.setMarginRight(self._blockIndent)
|
oStyle.setMarginRight(self._fBlockIndent)
|
||||||
|
|
||||||
# Process Text Types
|
# Process Text Types
|
||||||
if tType == self.T_EMPTY:
|
if tType == self.T_EMPTY:
|
||||||
if len(thisPar) > 1 and parStyle is not None:
|
if len(thisPar) > 1 and parStyle is not None:
|
||||||
if self.doJustify:
|
if self._doJustify:
|
||||||
parStyle.setTextAlign("left")
|
parStyle.setTextAlign("left")
|
||||||
|
|
||||||
if len(thisPar) > 0:
|
if len(thisPar) > 0:
|
||||||
@@ -449,15 +449,15 @@ class ToOdt(Tokenizer):
|
|||||||
thisPar.append(tTxt)
|
thisPar.append(tTxt)
|
||||||
thisFmt.append(tFmt)
|
thisFmt.append(tFmt)
|
||||||
|
|
||||||
elif tType == self.T_SYNOPSIS and self.doSynopsis:
|
elif tType == self.T_SYNOPSIS and self._doSynopsis:
|
||||||
tTemp, fTemp = self._formatSynopsis(tText)
|
tTemp, fTemp = self._formatSynopsis(tText)
|
||||||
self._addTextPar("Text_Meta", oStyle, tTemp, theFmt=fTemp)
|
self._addTextPar("Text_Meta", oStyle, tTemp, theFmt=fTemp)
|
||||||
|
|
||||||
elif tType == self.T_COMMENT and self.doComments:
|
elif tType == self.T_COMMENT and self._doComments:
|
||||||
tTemp, fTemp = self._formatComments(tText)
|
tTemp, fTemp = self._formatComments(tText)
|
||||||
self._addTextPar("Text_Meta", oStyle, tTemp, theFmt=fTemp)
|
self._addTextPar("Text_Meta", oStyle, tTemp, theFmt=fTemp)
|
||||||
|
|
||||||
elif tType == self.T_KEYWORD and self.doKeywords:
|
elif tType == self.T_KEYWORD and self._doKeywords:
|
||||||
tTemp, fTemp = self._formatKeywords(tText)
|
tTemp, fTemp = self._formatKeywords(tText)
|
||||||
self._addTextPar("Text_Meta", oStyle, tTemp, theFmt=fTemp)
|
self._addTextPar("Text_Meta", oStyle, tTemp, theFmt=fTemp)
|
||||||
|
|
||||||
@@ -696,7 +696,7 @@ class ToOdt(Tokenizer):
|
|||||||
def _emToCm(self, emVal):
|
def _emToCm(self, emVal):
|
||||||
"""Converts an em value to centimetres.
|
"""Converts an em value to centimetres.
|
||||||
"""
|
"""
|
||||||
return f"{emVal*2.54/72*self.textSize:.3f}cm"
|
return f"{emVal*2.54/72*self._textSize:.3f}cm"
|
||||||
|
|
||||||
##
|
##
|
||||||
# Style Elements
|
# Style Elements
|
||||||
@@ -747,7 +747,7 @@ class ToOdt(Tokenizer):
|
|||||||
etree.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
|
etree.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
|
||||||
|
|
||||||
theAttr = {}
|
theAttr = {}
|
||||||
theAttr[_mkTag("style", "font-name")] = self.textFont
|
theAttr[_mkTag("style", "font-name")] = self._textFont
|
||||||
theAttr[_mkTag("fo", "font-family")] = self._fontFamily
|
theAttr[_mkTag("fo", "font-family")] = self._fontFamily
|
||||||
theAttr[_mkTag("fo", "font-size")] = self._fSizeText
|
theAttr[_mkTag("fo", "font-size")] = self._fSizeText
|
||||||
theAttr[_mkTag("fo", "language")] = self._dLanguage
|
theAttr[_mkTag("fo", "language")] = self._dLanguage
|
||||||
@@ -764,7 +764,7 @@ class ToOdt(Tokenizer):
|
|||||||
xStyl = etree.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr)
|
xStyl = etree.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr)
|
||||||
|
|
||||||
theAttr = {}
|
theAttr = {}
|
||||||
theAttr[_mkTag("style", "font-name")] = self.textFont
|
theAttr[_mkTag("style", "font-name")] = self._textFont
|
||||||
theAttr[_mkTag("fo", "font-family")] = self._fontFamily
|
theAttr[_mkTag("fo", "font-family")] = self._fontFamily
|
||||||
theAttr[_mkTag("fo", "font-size")] = self._fSizeText
|
theAttr[_mkTag("fo", "font-size")] = self._fSizeText
|
||||||
etree.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
|
etree.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
|
||||||
@@ -787,7 +787,7 @@ class ToOdt(Tokenizer):
|
|||||||
etree.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
|
etree.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
|
||||||
|
|
||||||
theAttr = {}
|
theAttr = {}
|
||||||
theAttr[_mkTag("style", "font-name")] = self.textFont
|
theAttr[_mkTag("style", "font-name")] = self._textFont
|
||||||
theAttr[_mkTag("fo", "font-family")] = self._fontFamily
|
theAttr[_mkTag("fo", "font-family")] = self._fontFamily
|
||||||
theAttr[_mkTag("fo", "font-size")] = self._fSizeHead
|
theAttr[_mkTag("fo", "font-size")] = self._fSizeHead
|
||||||
etree.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
|
etree.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
|
||||||
@@ -816,8 +816,8 @@ class ToOdt(Tokenizer):
|
|||||||
oStyle.setClass("text")
|
oStyle.setClass("text")
|
||||||
oStyle.setMarginTop(self._mTopText)
|
oStyle.setMarginTop(self._mTopText)
|
||||||
oStyle.setMarginBottom(self._mBotText)
|
oStyle.setMarginBottom(self._mBotText)
|
||||||
oStyle.setLineHeight(self._lineHeight)
|
oStyle.setLineHeight(self._fLineHeight)
|
||||||
oStyle.setFontName(self.textFont)
|
oStyle.setFontName(self._textFont)
|
||||||
oStyle.setFontFamily(self._fontFamily)
|
oStyle.setFontFamily(self._fontFamily)
|
||||||
oStyle.setFontSize(self._fSizeText)
|
oStyle.setFontSize(self._fSizeText)
|
||||||
oStyle.setTextAlign(self._textAlign)
|
oStyle.setTextAlign(self._textAlign)
|
||||||
@@ -834,8 +834,8 @@ class ToOdt(Tokenizer):
|
|||||||
oStyle.setClass("text")
|
oStyle.setClass("text")
|
||||||
oStyle.setMarginTop(self._mTopMeta)
|
oStyle.setMarginTop(self._mTopMeta)
|
||||||
oStyle.setMarginBottom(self._mBotMeta)
|
oStyle.setMarginBottom(self._mBotMeta)
|
||||||
oStyle.setLineHeight(self._lineHeight)
|
oStyle.setLineHeight(self._fLineHeight)
|
||||||
oStyle.setFontName(self.textFont)
|
oStyle.setFontName(self._textFont)
|
||||||
oStyle.setFontFamily(self._fontFamily)
|
oStyle.setFontFamily(self._fontFamily)
|
||||||
oStyle.setFontSize(self._fSizeText)
|
oStyle.setFontSize(self._fSizeText)
|
||||||
oStyle.setColor(self._colMetaTx)
|
oStyle.setColor(self._colMetaTx)
|
||||||
@@ -855,7 +855,7 @@ class ToOdt(Tokenizer):
|
|||||||
oStyle.setTextAlign("center")
|
oStyle.setTextAlign("center")
|
||||||
oStyle.setMarginTop(self._mTopTitle)
|
oStyle.setMarginTop(self._mTopTitle)
|
||||||
oStyle.setMarginBottom(self._mBotTitle)
|
oStyle.setMarginBottom(self._mBotTitle)
|
||||||
oStyle.setFontName(self.textFont)
|
oStyle.setFontName(self._textFont)
|
||||||
oStyle.setFontFamily(self._fontFamily)
|
oStyle.setFontFamily(self._fontFamily)
|
||||||
oStyle.setFontSize(self._fSizeTitle)
|
oStyle.setFontSize(self._fSizeTitle)
|
||||||
oStyle.setFontWeight("bold")
|
oStyle.setFontWeight("bold")
|
||||||
@@ -874,7 +874,7 @@ class ToOdt(Tokenizer):
|
|||||||
oStyle.setClass("text")
|
oStyle.setClass("text")
|
||||||
oStyle.setMarginTop(self._mTopHead1)
|
oStyle.setMarginTop(self._mTopHead1)
|
||||||
oStyle.setMarginBottom(self._mBotHead1)
|
oStyle.setMarginBottom(self._mBotHead1)
|
||||||
oStyle.setFontName(self.textFont)
|
oStyle.setFontName(self._textFont)
|
||||||
oStyle.setFontFamily(self._fontFamily)
|
oStyle.setFontFamily(self._fontFamily)
|
||||||
oStyle.setFontSize(self._fSizeHead1)
|
oStyle.setFontSize(self._fSizeHead1)
|
||||||
oStyle.setColor(self._colHead12)
|
oStyle.setColor(self._colHead12)
|
||||||
@@ -895,7 +895,7 @@ class ToOdt(Tokenizer):
|
|||||||
oStyle.setClass("text")
|
oStyle.setClass("text")
|
||||||
oStyle.setMarginTop(self._mTopHead2)
|
oStyle.setMarginTop(self._mTopHead2)
|
||||||
oStyle.setMarginBottom(self._mBotHead2)
|
oStyle.setMarginBottom(self._mBotHead2)
|
||||||
oStyle.setFontName(self.textFont)
|
oStyle.setFontName(self._textFont)
|
||||||
oStyle.setFontFamily(self._fontFamily)
|
oStyle.setFontFamily(self._fontFamily)
|
||||||
oStyle.setFontSize(self._fSizeHead2)
|
oStyle.setFontSize(self._fSizeHead2)
|
||||||
oStyle.setColor(self._colHead12)
|
oStyle.setColor(self._colHead12)
|
||||||
@@ -916,7 +916,7 @@ class ToOdt(Tokenizer):
|
|||||||
oStyle.setClass("text")
|
oStyle.setClass("text")
|
||||||
oStyle.setMarginTop(self._mTopHead3)
|
oStyle.setMarginTop(self._mTopHead3)
|
||||||
oStyle.setMarginBottom(self._mBotHead3)
|
oStyle.setMarginBottom(self._mBotHead3)
|
||||||
oStyle.setFontName(self.textFont)
|
oStyle.setFontName(self._textFont)
|
||||||
oStyle.setFontFamily(self._fontFamily)
|
oStyle.setFontFamily(self._fontFamily)
|
||||||
oStyle.setFontSize(self._fSizeHead3)
|
oStyle.setFontSize(self._fSizeHead3)
|
||||||
oStyle.setColor(self._colHead34)
|
oStyle.setColor(self._colHead34)
|
||||||
@@ -937,7 +937,7 @@ class ToOdt(Tokenizer):
|
|||||||
oStyle.setClass("text")
|
oStyle.setClass("text")
|
||||||
oStyle.setMarginTop(self._mTopHead4)
|
oStyle.setMarginTop(self._mTopHead4)
|
||||||
oStyle.setMarginBottom(self._mBotHead4)
|
oStyle.setMarginBottom(self._mBotHead4)
|
||||||
oStyle.setFontName(self.textFont)
|
oStyle.setFontName(self._textFont)
|
||||||
oStyle.setFontFamily(self._fontFamily)
|
oStyle.setFontFamily(self._fontFamily)
|
||||||
oStyle.setFontSize(self._fSizeHead4)
|
oStyle.setFontSize(self._fSizeHead4)
|
||||||
oStyle.setColor(self._colHead34)
|
oStyle.setColor(self._colHead34)
|
||||||
@@ -972,7 +972,7 @@ class ToOdt(Tokenizer):
|
|||||||
xPar = etree.SubElement(xHead, _mkTag("text", "p"), attrib={
|
xPar = etree.SubElement(xHead, _mkTag("text", "p"), attrib={
|
||||||
_mkTag("text", "style-name"): "Header"
|
_mkTag("text", "style-name"): "Header"
|
||||||
})
|
})
|
||||||
xPar.text = self.headerText.strip() + " "
|
xPar.text = self._headerText.strip() + " "
|
||||||
|
|
||||||
xTail = etree.SubElement(xPar, _mkTag("text", "page-number"), attrib={
|
xTail = etree.SubElement(xPar, _mkTag("text", "page-number"), attrib={
|
||||||
_mkTag("text", "select-page"): "current"
|
_mkTag("text", "select-page"): "current"
|
||||||
|
|||||||
+21
-19
@@ -120,27 +120,29 @@ class NWErrorMessage(QDialog):
|
|||||||
kernelVersion = "Unknown"
|
kernelVersion = "Unknown"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
import lxml
|
||||||
|
lxmlVersion = lxml.__version__
|
||||||
|
except Exception:
|
||||||
|
lxmlVersion = "Unknown"
|
||||||
|
|
||||||
|
try:
|
||||||
|
import enchant
|
||||||
|
enchantVersion = enchant.__version__
|
||||||
|
except Exception:
|
||||||
|
enchantVersion = "Unknown"
|
||||||
|
|
||||||
|
try:
|
||||||
|
exTrace = "\n".join(format_tb(exTrace))
|
||||||
self.msgBody.setPlainText((
|
self.msgBody.setPlainText((
|
||||||
"Environment:\n"
|
"Environment:\n"
|
||||||
"novelWriter Version: {nwVersion}\n"
|
f"novelWriter Version: {__version__}\n"
|
||||||
"Host OS: {osType} ({osKernel})\n"
|
f"Host OS: {sys.platform} ({kernelVersion})\n"
|
||||||
"Python: {pyVersion} ({pyHexVer:#x})\n"
|
f"Python: {sys.version.split()[0]} ({sys.hexversion:#x})\n"
|
||||||
"Qt: {qtVers}, PyQt: {pyqtVers}\n"
|
f"Qt: {QT_VERSION_STR}, PyQt: {PYQT_VERSION_STR}\n"
|
||||||
"\n"
|
f"lxml: {lxmlVersion}\n"
|
||||||
"{exType}:\n{exMessage}\n"
|
f"enchant: {enchantVersion}\n\n"
|
||||||
"\n"
|
f"{exType.__name__}:\n{str(exValue)}\n\n"
|
||||||
"Traceback:\n{exTrace}\n"
|
f"Traceback:\n{exTrace}\n"
|
||||||
).format(
|
|
||||||
nwVersion=__version__,
|
|
||||||
osType=sys.platform,
|
|
||||||
osKernel=kernelVersion,
|
|
||||||
pyVersion=sys.version.split()[0],
|
|
||||||
pyHexVer=sys.hexversion,
|
|
||||||
qtVers=QT_VERSION_STR,
|
|
||||||
pyqtVers=PYQT_VERSION_STR,
|
|
||||||
exType=exType.__name__,
|
|
||||||
exMessage=str(exValue),
|
|
||||||
exTrace="\n".join(format_tb(exTrace)),
|
|
||||||
))
|
))
|
||||||
except Exception:
|
except Exception:
|
||||||
self.msgBody.setPlainText("Failed to generate error report ...")
|
self.msgBody.setPlainText("Failed to generate error report ...")
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ def testCoreDocument_LoadSave(monkeypatch, mockGUI, nwMinimal):
|
|||||||
|
|
||||||
# Not a valid handle
|
# Not a valid handle
|
||||||
theDoc = NWDoc(theProject, "stuff")
|
theDoc = NWDoc(theProject, "stuff")
|
||||||
|
assert bool(theDoc) is False
|
||||||
assert theDoc.readDocument() is None
|
assert theDoc.readDocument() is None
|
||||||
|
|
||||||
# Non-existent handle
|
# Non-existent handle
|
||||||
@@ -67,6 +68,8 @@ def testCoreDocument_LoadSave(monkeypatch, mockGUI, nwMinimal):
|
|||||||
assert nHandle is not None
|
assert nHandle is not None
|
||||||
xHandle = theProject.newFile("New File", nwItemClass.NOVEL, nHandle)
|
xHandle = theProject.newFile("New File", nwItemClass.NOVEL, nHandle)
|
||||||
theDoc = NWDoc(theProject, xHandle)
|
theDoc = NWDoc(theProject, xHandle)
|
||||||
|
assert bool(theDoc) is True
|
||||||
|
assert repr(theDoc) == f"<NWDoc handle={xHandle}>"
|
||||||
assert theDoc.readDocument() == ""
|
assert theDoc.readDocument() == ""
|
||||||
|
|
||||||
# Write Document
|
# Write Document
|
||||||
|
|||||||
@@ -219,6 +219,9 @@ def testCoreIndex_CheckThese(nwMinimal, mockGUI):
|
|||||||
assert theIndex.notesChangedSince(0) is True
|
assert theIndex.notesChangedSince(0) is True
|
||||||
assert theIndex.indexChangedSince(0) is True
|
assert theIndex.indexChangedSince(0) is True
|
||||||
|
|
||||||
|
assert theIndex.getHandleHeaderLevel(cHandle) == "H1"
|
||||||
|
assert theIndex.getHandleHeaderLevel(nHandle) == "H1"
|
||||||
|
|
||||||
# Zero Items
|
# Zero Items
|
||||||
assert theIndex.checkThese([], cItem) == []
|
assert theIndex.checkThese([], cItem) == []
|
||||||
|
|
||||||
|
|||||||
@@ -48,36 +48,39 @@ def testCoreProject_NewMinimal(fncDir, outDir, refDir, mockGUI):
|
|||||||
theProject.projTree.setSeed(42)
|
theProject.projTree.setSeed(42)
|
||||||
|
|
||||||
# Setting no data should fail
|
# Setting no data should fail
|
||||||
assert not theProject.newProject({})
|
assert theProject.newProject({}) is False
|
||||||
|
|
||||||
|
# Wrong type should also fail
|
||||||
|
assert theProject.newProject("stuff") is False
|
||||||
|
|
||||||
# Try again with a proper path
|
# Try again with a proper path
|
||||||
assert theProject.newProject({"projPath": fncDir})
|
assert theProject.newProject({"projPath": fncDir}) is True
|
||||||
assert theProject.saveProject()
|
assert theProject.saveProject() is True
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
|
|
||||||
# Creating the project once more should fail
|
# Creating the project once more should fail
|
||||||
assert not theProject.newProject({"projPath": fncDir})
|
assert theProject.newProject({"projPath": fncDir}) is False
|
||||||
|
|
||||||
# Check the new project
|
# Check the new project
|
||||||
copyfile(projFile, testFile)
|
copyfile(projFile, testFile)
|
||||||
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
||||||
|
|
||||||
# Open again
|
# Open again
|
||||||
assert theProject.openProject(projFile)
|
assert theProject.openProject(projFile) is True
|
||||||
|
|
||||||
# Save and close
|
# Save and close
|
||||||
assert theProject.saveProject()
|
assert theProject.saveProject() is True
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
copyfile(projFile, testFile)
|
copyfile(projFile, testFile)
|
||||||
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
||||||
assert not theProject.projChanged
|
assert theProject.projChanged is False
|
||||||
|
|
||||||
# Open a second time
|
# Open a second time
|
||||||
assert theProject.openProject(projFile)
|
assert theProject.openProject(projFile) is True
|
||||||
assert not theProject.openProject(projFile)
|
assert theProject.openProject(projFile) is False
|
||||||
assert theProject.openProject(projFile, overrideLock=True)
|
assert theProject.openProject(projFile, overrideLock=True) is True
|
||||||
assert theProject.saveProject()
|
assert theProject.saveProject() is True
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
copyfile(projFile, testFile)
|
copyfile(projFile, testFile)
|
||||||
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
||||||
|
|
||||||
@@ -116,9 +119,9 @@ def testCoreProject_NewCustomA(fncDir, outDir, refDir, mockGUI):
|
|||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
theProject.projTree.setSeed(42)
|
theProject.projTree.setSeed(42)
|
||||||
|
|
||||||
assert theProject.newProject(projData)
|
assert theProject.newProject(projData) is True
|
||||||
assert theProject.saveProject()
|
assert theProject.saveProject() is True
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
|
|
||||||
copyfile(projFile, testFile)
|
copyfile(projFile, testFile)
|
||||||
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
||||||
@@ -158,9 +161,9 @@ def testCoreProject_NewCustomB(fncDir, outDir, refDir, mockGUI):
|
|||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
theProject.projTree.setSeed(42)
|
theProject.projTree.setSeed(42)
|
||||||
|
|
||||||
assert theProject.newProject(projData)
|
assert theProject.newProject(projData) is True
|
||||||
assert theProject.saveProject()
|
assert theProject.saveProject() is True
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
|
|
||||||
copyfile(projFile, testFile)
|
copyfile(projFile, testFile)
|
||||||
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
||||||
@@ -207,11 +210,11 @@ def testCoreProject_NewSampleA(fncDir, tmpConf, mockGUI, tmpDir):
|
|||||||
srcDoc = os.path.join(srcSample, "content", docFile)
|
srcDoc = os.path.join(srcSample, "content", docFile)
|
||||||
zipObj.write(srcDoc, "content/"+docFile)
|
zipObj.write(srcDoc, "content/"+docFile)
|
||||||
|
|
||||||
assert theProject.newProject(projData)
|
assert theProject.newProject(projData) is True
|
||||||
assert theProject.openProject(fncDir)
|
assert theProject.openProject(fncDir) is True
|
||||||
assert theProject.projName == "Sample Project"
|
assert theProject.projName == "Sample Project"
|
||||||
assert theProject.saveProject()
|
assert theProject.saveProject() is True
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
os.unlink(dstSample)
|
os.unlink(dstSample)
|
||||||
|
|
||||||
# END Test testCoreProject_NewSampleA
|
# END Test testCoreProject_NewSampleA
|
||||||
@@ -242,11 +245,11 @@ def testCoreProject_NewSampleB(monkeypatch, fncDir, tmpConf, mockGUI, tmpDir):
|
|||||||
assert not theProject.newProject(projData)
|
assert not theProject.newProject(projData)
|
||||||
|
|
||||||
monkeypatch.setattr(nwFiles, "PROJ_FILE", "nwProject.nwx")
|
monkeypatch.setattr(nwFiles, "PROJ_FILE", "nwProject.nwx")
|
||||||
assert theProject.newProject(projData)
|
assert theProject.newProject(projData) is True
|
||||||
assert theProject.openProject(fncDir)
|
assert theProject.openProject(fncDir) is True
|
||||||
assert theProject.projName == "Sample Project"
|
assert theProject.projName == "Sample Project"
|
||||||
assert theProject.saveProject()
|
assert theProject.saveProject() is True
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
|
|
||||||
# Misdirect the appRoot path so neither is possible
|
# Misdirect the appRoot path so neither is possible
|
||||||
tmpConf.appRoot = tmpDir
|
tmpConf.appRoot = tmpDir
|
||||||
@@ -266,11 +269,11 @@ def testCoreProject_NewRoot(fncDir, outDir, refDir, mockGUI):
|
|||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
theProject.projTree.setSeed(42)
|
theProject.projTree.setSeed(42)
|
||||||
|
|
||||||
assert theProject.newProject({"projPath": fncDir})
|
assert theProject.newProject({"projPath": fncDir}) is True
|
||||||
assert theProject.setProjectPath(fncDir)
|
assert theProject.setProjectPath(fncDir) is True
|
||||||
assert theProject.saveProject()
|
assert theProject.saveProject() is True
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
assert theProject.openProject(projFile)
|
assert theProject.openProject(projFile) is True
|
||||||
|
|
||||||
assert isinstance(theProject.newRoot("Novel", nwItemClass.NOVEL), type(None))
|
assert isinstance(theProject.newRoot("Novel", nwItemClass.NOVEL), type(None))
|
||||||
assert isinstance(theProject.newRoot("Plot", nwItemClass.PLOT), type(None))
|
assert isinstance(theProject.newRoot("Plot", nwItemClass.PLOT), type(None))
|
||||||
@@ -281,13 +284,13 @@ def testCoreProject_NewRoot(fncDir, outDir, refDir, mockGUI):
|
|||||||
assert isinstance(theProject.newRoot("Custom1", nwItemClass.CUSTOM), str)
|
assert isinstance(theProject.newRoot("Custom1", nwItemClass.CUSTOM), str)
|
||||||
assert isinstance(theProject.newRoot("Custom2", nwItemClass.CUSTOM), str)
|
assert isinstance(theProject.newRoot("Custom2", nwItemClass.CUSTOM), str)
|
||||||
|
|
||||||
assert theProject.projChanged
|
assert theProject.projChanged is True
|
||||||
assert theProject.saveProject()
|
assert theProject.saveProject() is True
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
|
|
||||||
copyfile(projFile, testFile)
|
copyfile(projFile, testFile)
|
||||||
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
||||||
assert not theProject.projChanged
|
assert theProject.projChanged is False
|
||||||
|
|
||||||
# END Test testCoreProject_NewRoot
|
# END Test testCoreProject_NewRoot
|
||||||
|
|
||||||
@@ -303,21 +306,21 @@ def testCoreProject_NewFile(fncDir, outDir, refDir, mockGUI):
|
|||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
theProject.projTree.setSeed(42)
|
theProject.projTree.setSeed(42)
|
||||||
|
|
||||||
assert theProject.newProject({"projPath": fncDir})
|
assert theProject.newProject({"projPath": fncDir}) is True
|
||||||
assert theProject.setProjectPath(fncDir)
|
assert theProject.setProjectPath(fncDir) is True
|
||||||
assert theProject.saveProject()
|
assert theProject.saveProject() is True
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
assert theProject.openProject(projFile)
|
assert theProject.openProject(projFile) is True
|
||||||
|
|
||||||
assert isinstance(theProject.newFile("Hello", nwItemClass.NOVEL, "31489056e0916"), str)
|
assert isinstance(theProject.newFile("Hello", nwItemClass.NOVEL, "31489056e0916"), str)
|
||||||
assert isinstance(theProject.newFile("Jane", nwItemClass.CHARACTER, "71ee45a3c0db9"), str)
|
assert isinstance(theProject.newFile("Jane", nwItemClass.CHARACTER, "71ee45a3c0db9"), str)
|
||||||
assert theProject.projChanged
|
assert theProject.projChanged
|
||||||
assert theProject.saveProject()
|
assert theProject.saveProject() is True
|
||||||
assert theProject.closeProject()
|
assert theProject.closeProject() is True
|
||||||
|
|
||||||
copyfile(projFile, testFile)
|
copyfile(projFile, testFile)
|
||||||
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
|
||||||
assert not theProject.projChanged
|
assert theProject.projChanged is False
|
||||||
|
|
||||||
# END Test testCoreProject_NewFile
|
# END Test testCoreProject_NewFile
|
||||||
|
|
||||||
@@ -466,6 +469,7 @@ def testCoreProject_Save(monkeypatch, nwMinimal, mockGUI, refDir):
|
|||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
testFile = os.path.join(nwMinimal, "nwProject.nwx")
|
testFile = os.path.join(nwMinimal, "nwProject.nwx")
|
||||||
|
backFile = os.path.join(nwMinimal, "nwProject.bak")
|
||||||
compFile = os.path.join(refDir, os.path.pardir, "minimal", "nwProject.nwx")
|
compFile = os.path.join(refDir, os.path.pardir, "minimal", "nwProject.nwx")
|
||||||
|
|
||||||
# Nothing to save
|
# Nothing to save
|
||||||
@@ -476,7 +480,7 @@ def testCoreProject_Save(monkeypatch, nwMinimal, mockGUI, refDir):
|
|||||||
|
|
||||||
# Fail on folder structure check
|
# Fail on folder structure check
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr("os.path.isdir", lambda *args: False)
|
mp.setattr("os.path.isdir", lambda *a: False)
|
||||||
assert theProject.saveProject() is False
|
assert theProject.saveProject() is False
|
||||||
|
|
||||||
# Fail on open file
|
# Fail on open file
|
||||||
@@ -484,6 +488,12 @@ def testCoreProject_Save(monkeypatch, nwMinimal, mockGUI, refDir):
|
|||||||
mp.setattr("builtins.open", causeOSError)
|
mp.setattr("builtins.open", causeOSError)
|
||||||
assert theProject.saveProject() is False
|
assert theProject.saveProject() is False
|
||||||
|
|
||||||
|
# Fail on creating .bak file
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr("os.replace", causeOSError)
|
||||||
|
assert theProject.saveProject() is False
|
||||||
|
assert os.path.isfile(backFile) is False
|
||||||
|
|
||||||
# Successful save
|
# Successful save
|
||||||
saveCount = theProject.saveCount
|
saveCount = theProject.saveCount
|
||||||
autoCount = theProject.autoCount
|
autoCount = theProject.autoCount
|
||||||
@@ -492,6 +502,9 @@ def testCoreProject_Save(monkeypatch, nwMinimal, mockGUI, refDir):
|
|||||||
assert theProject.autoCount == autoCount
|
assert theProject.autoCount == autoCount
|
||||||
assert cmpFiles(testFile, compFile, [2, 6, 7, 8, 9])
|
assert cmpFiles(testFile, compFile, [2, 6, 7, 8, 9])
|
||||||
|
|
||||||
|
# Check that a second save creates a .bak file
|
||||||
|
assert os.path.isfile(backFile) is True
|
||||||
|
|
||||||
# Successful autosave
|
# Successful autosave
|
||||||
saveCount = theProject.saveCount
|
saveCount = theProject.saveCount
|
||||||
autoCount = theProject.autoCount
|
autoCount = theProject.autoCount
|
||||||
|
|||||||
@@ -38,12 +38,12 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
# Novel Files Headers
|
# Novel Files Headers
|
||||||
# ===================
|
# ===================
|
||||||
|
|
||||||
theHtml.isNovel = True
|
theHtml._isNovel = True
|
||||||
theHtml.isNote = False
|
theHtml._isNote = False
|
||||||
theHtml.isFirst = True
|
theHtml._isFirst = True
|
||||||
|
|
||||||
# Header 1
|
# Header 1
|
||||||
theHtml.theText = "# Partition\n"
|
theHtml._theText = "# Partition\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
@@ -51,7 +51,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Header 2
|
# Header 2
|
||||||
theHtml.theText = "## Chapter Title\n"
|
theHtml._theText = "## Chapter Title\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
@@ -59,19 +59,19 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Header 3
|
# Header 3
|
||||||
theHtml.theText = "### Scene Title\n"
|
theHtml._theText = "### Scene Title\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == "<h2>Scene Title</h2>\n"
|
assert theHtml.theResult == "<h2>Scene Title</h2>\n"
|
||||||
|
|
||||||
# Header 4
|
# Header 4
|
||||||
theHtml.theText = "#### Section Title\n"
|
theHtml._theText = "#### Section Title\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == "<h3>Section Title</h3>\n"
|
assert theHtml.theResult == "<h3>Section Title</h3>\n"
|
||||||
|
|
||||||
# Title
|
# Title
|
||||||
theHtml.theText = "#! Title\n"
|
theHtml._theText = "#! Title\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
@@ -79,7 +79,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Unnumbered
|
# Unnumbered
|
||||||
theHtml.theText = "##! Prologue\n"
|
theHtml._theText = "##! Prologue\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == "<h1 style='page-break-before: always;'>Prologue</h1>\n"
|
assert theHtml.theResult == "<h1 style='page-break-before: always;'>Prologue</h1>\n"
|
||||||
@@ -87,37 +87,37 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
# Note Files Headers
|
# Note Files Headers
|
||||||
# ==================
|
# ==================
|
||||||
|
|
||||||
theHtml.isNovel = False
|
theHtml._isNovel = False
|
||||||
theHtml.isNote = True
|
theHtml._isNote = True
|
||||||
theHtml.isFirst = True
|
theHtml._isFirst = True
|
||||||
theHtml.setLinkHeaders(True)
|
theHtml.setLinkHeaders(True)
|
||||||
|
|
||||||
# Header 1
|
# Header 1
|
||||||
theHtml.theText = "# Heading One\n"
|
theHtml._theText = "# Heading One\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == "<h1><a name='T000001'></a>Heading One</h1>\n"
|
assert theHtml.theResult == "<h1><a name='T000001'></a>Heading One</h1>\n"
|
||||||
|
|
||||||
# Header 2
|
# Header 2
|
||||||
theHtml.theText = "## Heading Two\n"
|
theHtml._theText = "## Heading Two\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == "<h2><a name='T000001'></a>Heading Two</h2>\n"
|
assert theHtml.theResult == "<h2><a name='T000001'></a>Heading Two</h2>\n"
|
||||||
|
|
||||||
# Header 3
|
# Header 3
|
||||||
theHtml.theText = "### Heading Three\n"
|
theHtml._theText = "### Heading Three\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == "<h3><a name='T000001'></a>Heading Three</h3>\n"
|
assert theHtml.theResult == "<h3><a name='T000001'></a>Heading Three</h3>\n"
|
||||||
|
|
||||||
# Header 4
|
# Header 4
|
||||||
theHtml.theText = "#### Heading Four\n"
|
theHtml._theText = "#### Heading Four\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == "<h4><a name='T000001'></a>Heading Four</h4>\n"
|
assert theHtml.theResult == "<h4><a name='T000001'></a>Heading Four</h4>\n"
|
||||||
|
|
||||||
# Title
|
# Title
|
||||||
theHtml.theText = "#! Heading One\n"
|
theHtml._theText = "#! Heading One\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
@@ -125,7 +125,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Unnumbered
|
# Unnumbered
|
||||||
theHtml.theText = "##! Heading Two\n"
|
theHtml._theText = "##! Heading Two\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == "<h2><a name='T000001'></a>Heading Two</h2>\n"
|
assert theHtml.theResult == "<h2><a name='T000001'></a>Heading Two</h2>\n"
|
||||||
@@ -134,7 +134,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
# ==========
|
# ==========
|
||||||
|
|
||||||
# Text
|
# Text
|
||||||
theHtml.theText = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
|
theHtml._theText = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
@@ -143,7 +143,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Text w/Hard Break
|
# Text w/Hard Break
|
||||||
theHtml.theText = "Line one \nLine two \nLine three\n"
|
theHtml._theText = "Line one \nLine two \nLine three\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
@@ -151,13 +151,13 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Synopsis
|
# Synopsis
|
||||||
theHtml.theText = "%synopsis: The synopsis ...\n"
|
theHtml._theText = "%synopsis: The synopsis ...\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == ""
|
assert theHtml.theResult == ""
|
||||||
|
|
||||||
theHtml.setSynopsis(True)
|
theHtml.setSynopsis(True)
|
||||||
theHtml.theText = "%synopsis: The synopsis ...\n"
|
theHtml._theText = "%synopsis: The synopsis ...\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
@@ -165,13 +165,13 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Comment
|
# Comment
|
||||||
theHtml.theText = "% A comment ...\n"
|
theHtml._theText = "% A comment ...\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == ""
|
assert theHtml.theResult == ""
|
||||||
|
|
||||||
theHtml.setComments(True)
|
theHtml.setComments(True)
|
||||||
theHtml.theText = "% A comment ...\n"
|
theHtml._theText = "% A comment ...\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
@@ -179,13 +179,13 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Keywords
|
# Keywords
|
||||||
theHtml.theText = "@char: Bod, Jane\n"
|
theHtml._theText = "@char: Bod, Jane\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == ""
|
assert theHtml.theResult == ""
|
||||||
|
|
||||||
theHtml.setKeywords(True)
|
theHtml.setKeywords(True)
|
||||||
theHtml.theText = "@char: Bod, Jane\n"
|
theHtml._theText = "@char: Bod, Jane\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
@@ -195,7 +195,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
|
|
||||||
# Multiple Keywords
|
# Multiple Keywords
|
||||||
theHtml.setKeywords(True)
|
theHtml.setKeywords(True)
|
||||||
theHtml.theText = "## Chapter\n\n@pov: Bod\n@plot: Main\n@location: Europe\n\n"
|
theHtml._theText = "## Chapter\n\n@pov: Bod\n@plot: Main\n@location: Europe\n\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
@@ -218,7 +218,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
theHtml.setPreview(True, True)
|
theHtml.setPreview(True, True)
|
||||||
|
|
||||||
# Text (HTML4)
|
# Text (HTML4)
|
||||||
theHtml.theText = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
|
theHtml._theText = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
@@ -238,15 +238,15 @@ def testCoreToHtml_ConvertDirect(mockGUI):
|
|||||||
mockGUI.theIndex = NWIndex(theProject)
|
mockGUI.theIndex = NWIndex(theProject)
|
||||||
theHtml = ToHtml(theProject)
|
theHtml = ToHtml(theProject)
|
||||||
|
|
||||||
theHtml.isNovel = True
|
theHtml._isNovel = True
|
||||||
theHtml.isNote = False
|
theHtml._isNote = False
|
||||||
theHtml.setLinkHeaders(True)
|
theHtml.setLinkHeaders(True)
|
||||||
|
|
||||||
# Special Titles
|
# Special Titles
|
||||||
# ==============
|
# ==============
|
||||||
|
|
||||||
# Title
|
# Title
|
||||||
theHtml.theTokens = [
|
theHtml._theTokens = [
|
||||||
(theHtml.T_TITLE, 1, "A Title", None, theHtml.A_PBB | theHtml.A_CENTRE),
|
(theHtml.T_TITLE, 1, "A Title", None, theHtml.A_PBB | theHtml.A_CENTRE),
|
||||||
(theHtml.T_EMPTY, 1, "", None, theHtml.A_NONE),
|
(theHtml.T_EMPTY, 1, "", None, theHtml.A_NONE),
|
||||||
]
|
]
|
||||||
@@ -257,7 +257,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Unnumbered
|
# Unnumbered
|
||||||
theHtml.theTokens = [
|
theHtml._theTokens = [
|
||||||
(theHtml.T_UNNUM, 1, "Prologue", None, theHtml.A_PBB),
|
(theHtml.T_UNNUM, 1, "Prologue", None, theHtml.A_PBB),
|
||||||
(theHtml.T_EMPTY, 1, "", None, theHtml.A_NONE),
|
(theHtml.T_EMPTY, 1, "", None, theHtml.A_NONE),
|
||||||
]
|
]
|
||||||
@@ -271,7 +271,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
|
|||||||
# ==========
|
# ==========
|
||||||
|
|
||||||
# Separator
|
# Separator
|
||||||
theHtml.theTokens = [
|
theHtml._theTokens = [
|
||||||
(theHtml.T_SEP, 1, "* * *", None, theHtml.A_CENTRE),
|
(theHtml.T_SEP, 1, "* * *", None, theHtml.A_CENTRE),
|
||||||
(theHtml.T_EMPTY, 1, "", None, theHtml.A_NONE),
|
(theHtml.T_EMPTY, 1, "", None, theHtml.A_NONE),
|
||||||
]
|
]
|
||||||
@@ -279,7 +279,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
|
|||||||
assert theHtml.theResult == "<p class='sep' style='text-align: center;'>* * *</p>\n"
|
assert theHtml.theResult == "<p class='sep' style='text-align: center;'>* * *</p>\n"
|
||||||
|
|
||||||
# Skip
|
# Skip
|
||||||
theHtml.theTokens = [
|
theHtml._theTokens = [
|
||||||
(theHtml.T_SKIP, 1, "", None, theHtml.A_NONE),
|
(theHtml.T_SKIP, 1, "", None, theHtml.A_NONE),
|
||||||
(theHtml.T_EMPTY, 1, "", None, theHtml.A_NONE),
|
(theHtml.T_EMPTY, 1, "", None, theHtml.A_NONE),
|
||||||
]
|
]
|
||||||
@@ -293,7 +293,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
|
|||||||
|
|
||||||
# Align Left
|
# Align Left
|
||||||
theHtml.setStyles(False)
|
theHtml.setStyles(False)
|
||||||
theHtml.theTokens = [
|
theHtml._theTokens = [
|
||||||
(theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_LEFT),
|
(theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_LEFT),
|
||||||
]
|
]
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
@@ -304,7 +304,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
|
|||||||
theHtml.setStyles(True)
|
theHtml.setStyles(True)
|
||||||
|
|
||||||
# Align Left
|
# Align Left
|
||||||
theHtml.theTokens = [
|
theHtml._theTokens = [
|
||||||
(theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_LEFT),
|
(theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_LEFT),
|
||||||
]
|
]
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
@@ -313,7 +313,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Align Right
|
# Align Right
|
||||||
theHtml.theTokens = [
|
theHtml._theTokens = [
|
||||||
(theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_RIGHT),
|
(theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_RIGHT),
|
||||||
]
|
]
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
@@ -322,7 +322,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Align Centre
|
# Align Centre
|
||||||
theHtml.theTokens = [
|
theHtml._theTokens = [
|
||||||
(theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_CENTRE),
|
(theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_CENTRE),
|
||||||
]
|
]
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
@@ -331,7 +331,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Align Justify
|
# Align Justify
|
||||||
theHtml.theTokens = [
|
theHtml._theTokens = [
|
||||||
(theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_JUSTIFY),
|
(theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_JUSTIFY),
|
||||||
]
|
]
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
@@ -343,7 +343,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
|
|||||||
# ==========
|
# ==========
|
||||||
|
|
||||||
# Page Break Always
|
# Page Break Always
|
||||||
theHtml.theTokens = [
|
theHtml._theTokens = [
|
||||||
(theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_PBB | theHtml.A_PBA),
|
(theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_PBB | theHtml.A_PBA),
|
||||||
]
|
]
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
@@ -356,7 +356,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
|
|||||||
# ======
|
# ======
|
||||||
|
|
||||||
# Indent Left
|
# Indent Left
|
||||||
theHtml.theTokens = [
|
theHtml._theTokens = [
|
||||||
(theHtml.T_TEXT, 1, "Some text ...", [], theHtml.A_IND_L),
|
(theHtml.T_TEXT, 1, "Some text ...", [], theHtml.A_IND_L),
|
||||||
(theHtml.T_EMPTY, 2, "", None, theHtml.A_NONE),
|
(theHtml.T_EMPTY, 2, "", None, theHtml.A_NONE),
|
||||||
]
|
]
|
||||||
@@ -366,7 +366,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Indent Right
|
# Indent Right
|
||||||
theHtml.theTokens = [
|
theHtml._theTokens = [
|
||||||
(theHtml.T_TEXT, 1, "Some text ...", [], theHtml.A_IND_R),
|
(theHtml.T_TEXT, 1, "Some text ...", [], theHtml.A_IND_R),
|
||||||
(theHtml.T_EMPTY, 2, "", None, theHtml.A_NONE),
|
(theHtml.T_EMPTY, 2, "", None, theHtml.A_NONE),
|
||||||
]
|
]
|
||||||
@@ -384,33 +384,33 @@ def testCoreToHtml_SpecialCases(mockGUI):
|
|||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
theHtml = ToHtml(theProject)
|
theHtml = ToHtml(theProject)
|
||||||
theHtml.isNovel = True
|
theHtml._isNovel = True
|
||||||
|
|
||||||
# Greater/Lesser than symbols
|
# Greater/Lesser than symbols
|
||||||
# ===========================
|
# ===========================
|
||||||
|
|
||||||
theHtml.theText = "Text with > and < with some **bold text** in it.\n"
|
theHtml._theText = "Text with > and < with some **bold text** in it.\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
"<p>Text with > and < with some <strong>bold text</strong> in it.</p>\n"
|
"<p>Text with > and < with some <strong>bold text</strong> in it.</p>\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
theHtml.theText = "Text with some <**bold text**> in it.\n"
|
theHtml._theText = "Text with some <**bold text**> in it.\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
"<p>Text with some <<strong>bold text</strong>> in it.</p>\n"
|
"<p>Text with some <<strong>bold text</strong>> in it.</p>\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
theHtml.theText = "Let's > be > _difficult **shall** > we_?\n"
|
theHtml._theText = "Let's > be > _difficult **shall** > we_?\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
"<p>Let's > be > <em>difficult <strong>shall</strong> > we</em>?</p>\n"
|
"<p>Let's > be > <em>difficult <strong>shall</strong> > we</em>?</p>\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
theHtml.theText = "Test > text _<**bold**>_ and more.\n"
|
theHtml._theText = "Test > text _<**bold**>_ and more.\n"
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
assert theHtml.theResult == (
|
assert theHtml.theResult == (
|
||||||
@@ -426,7 +426,7 @@ def testCoreToHtml_Complex(mockGUI, fncDir):
|
|||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
theHtml = ToHtml(theProject)
|
theHtml = ToHtml(theProject)
|
||||||
theHtml.isNovel = True
|
theHtml._isNovel = True
|
||||||
|
|
||||||
# Build Project
|
# Build Project
|
||||||
# =============
|
# =============
|
||||||
@@ -472,7 +472,7 @@ def testCoreToHtml_Complex(mockGUI, fncDir):
|
|||||||
]
|
]
|
||||||
|
|
||||||
for i in range(len(docText)):
|
for i in range(len(docText)):
|
||||||
theHtml.theText = docText[i]
|
theHtml._theText = docText[i]
|
||||||
theHtml.doPreProcessing()
|
theHtml.doPreProcessing()
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
@@ -526,7 +526,7 @@ def testCoreToHtml_Methods(mockGUI):
|
|||||||
|
|
||||||
# Auto-Replace, keep Unicode
|
# Auto-Replace, keep Unicode
|
||||||
docText = "Text with <brackets> & short–dash, long—dash …\n"
|
docText = "Text with <brackets> & short–dash, long—dash …\n"
|
||||||
theHtml.theText = docText
|
theHtml._theText = docText
|
||||||
theHtml.setReplaceUnicode(False)
|
theHtml.setReplaceUnicode(False)
|
||||||
theHtml.doPreProcessing()
|
theHtml.doPreProcessing()
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
@@ -537,7 +537,7 @@ def testCoreToHtml_Methods(mockGUI):
|
|||||||
|
|
||||||
# Auto-Replace, replace Unicode
|
# Auto-Replace, replace Unicode
|
||||||
docText = "Text with <brackets> & short–dash, long—dash …\n"
|
docText = "Text with <brackets> & short–dash, long—dash …\n"
|
||||||
theHtml.theText = docText
|
theHtml._theText = docText
|
||||||
theHtml.setReplaceUnicode(True)
|
theHtml.setReplaceUnicode(True)
|
||||||
theHtml.doPreProcessing()
|
theHtml.doPreProcessing()
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
@@ -548,7 +548,7 @@ def testCoreToHtml_Methods(mockGUI):
|
|||||||
|
|
||||||
# With Preview
|
# With Preview
|
||||||
theHtml.setPreview(True, True)
|
theHtml.setPreview(True, True)
|
||||||
theHtml.theText = docText
|
theHtml._theText = docText
|
||||||
theHtml.doPreProcessing()
|
theHtml.doPreProcessing()
|
||||||
theHtml.tokenizeText()
|
theHtml.tokenizeText()
|
||||||
theHtml.doConvert()
|
theHtml.doConvert()
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -38,42 +38,42 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
|
|||||||
# Headers
|
# Headers
|
||||||
# =======
|
# =======
|
||||||
|
|
||||||
theMD.isNovel = True
|
theMD._isNovel = True
|
||||||
theMD.isNote = False
|
theMD._isNote = False
|
||||||
theMD.isFirst = True
|
theMD._isFirst = True
|
||||||
|
|
||||||
# Header 1
|
# Header 1
|
||||||
theMD.theText = "# Partition\n"
|
theMD._theText = "# Partition\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == "# Partition\n\n"
|
assert theMD.theResult == "# Partition\n\n"
|
||||||
|
|
||||||
# Header 2
|
# Header 2
|
||||||
theMD.theText = "## Chapter Title\n"
|
theMD._theText = "## Chapter Title\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == "## Chapter Title\n\n"
|
assert theMD.theResult == "## Chapter Title\n\n"
|
||||||
|
|
||||||
# Header 3
|
# Header 3
|
||||||
theMD.theText = "### Scene Title\n"
|
theMD._theText = "### Scene Title\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == "### Scene Title\n\n"
|
assert theMD.theResult == "### Scene Title\n\n"
|
||||||
|
|
||||||
# Header 4
|
# Header 4
|
||||||
theMD.theText = "#### Section Title\n"
|
theMD._theText = "#### Section Title\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == "#### Section Title\n\n"
|
assert theMD.theResult == "#### Section Title\n\n"
|
||||||
|
|
||||||
# Title
|
# Title
|
||||||
theMD.theText = "#! Title\n"
|
theMD._theText = "#! Title\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == "# Title\n\n"
|
assert theMD.theResult == "# Title\n\n"
|
||||||
|
|
||||||
# Unnumbered
|
# Unnumbered
|
||||||
theMD.theText = "##! Prologue\n"
|
theMD._theText = "##! Prologue\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == "## Prologue\n\n"
|
assert theMD.theResult == "## Prologue\n\n"
|
||||||
@@ -83,7 +83,7 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
|
|||||||
|
|
||||||
# Text for GitHub Markdown
|
# Text for GitHub Markdown
|
||||||
theMD.setGitHubMarkdown()
|
theMD.setGitHubMarkdown()
|
||||||
theMD.theText = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
|
theMD._theText = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == (
|
assert theMD.theResult == (
|
||||||
@@ -92,7 +92,7 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
|
|||||||
|
|
||||||
# Text for Standard Markdown
|
# Text for Standard Markdown
|
||||||
theMD.setStandardMarkdown()
|
theMD.setStandardMarkdown()
|
||||||
theMD.theText = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
|
theMD._theText = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == (
|
assert theMD.theResult == (
|
||||||
@@ -100,50 +100,50 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Text w/Hard Break
|
# Text w/Hard Break
|
||||||
theMD.theText = "Line one \nLine two \nLine three\n"
|
theMD._theText = "Line one \nLine two \nLine three\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == "Line one \nLine two \nLine three\n\n"
|
assert theMD.theResult == "Line one \nLine two \nLine three\n\n"
|
||||||
|
|
||||||
# Synopsis
|
# Synopsis
|
||||||
theMD.theText = "%synopsis: The synopsis ...\n"
|
theMD._theText = "%synopsis: The synopsis ...\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == ""
|
assert theMD.theResult == ""
|
||||||
|
|
||||||
theMD.setSynopsis(True)
|
theMD.setSynopsis(True)
|
||||||
theMD.theText = "%synopsis: The synopsis ...\n"
|
theMD._theText = "%synopsis: The synopsis ...\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == "**Synopsis:** The synopsis ...\n\n"
|
assert theMD.theResult == "**Synopsis:** The synopsis ...\n\n"
|
||||||
|
|
||||||
# Comment
|
# Comment
|
||||||
theMD.theText = "% A comment ...\n"
|
theMD._theText = "% A comment ...\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == ""
|
assert theMD.theResult == ""
|
||||||
|
|
||||||
theMD.setComments(True)
|
theMD.setComments(True)
|
||||||
theMD.theText = "% A comment ...\n"
|
theMD._theText = "% A comment ...\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == "**Comment:** A comment ...\n\n"
|
assert theMD.theResult == "**Comment:** A comment ...\n\n"
|
||||||
|
|
||||||
# Keywords
|
# Keywords
|
||||||
theMD.theText = "@char: Bod, Jane\n"
|
theMD._theText = "@char: Bod, Jane\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == ""
|
assert theMD.theResult == ""
|
||||||
|
|
||||||
theMD.setKeywords(True)
|
theMD.setKeywords(True)
|
||||||
theMD.theText = "@char: Bod, Jane\n"
|
theMD._theText = "@char: Bod, Jane\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == "**Characters:** Bod, Jane\n\n"
|
assert theMD.theResult == "**Characters:** Bod, Jane\n\n"
|
||||||
|
|
||||||
# Multiple Keywords
|
# Multiple Keywords
|
||||||
theMD.setKeywords(True)
|
theMD.setKeywords(True)
|
||||||
theMD.theText = "## Chapter\n\n@pov: Bod\n@plot: Main\n@location: Europe\n\n"
|
theMD._theText = "## Chapter\n\n@pov: Bod\n@plot: Main\n@location: Europe\n\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
assert theMD.theResult == (
|
assert theMD.theResult == (
|
||||||
@@ -164,14 +164,14 @@ def testCoreToMarkdown_ConvertDirect(mockGUI):
|
|||||||
mockGUI.theIndex = NWIndex(theProject)
|
mockGUI.theIndex = NWIndex(theProject)
|
||||||
theMD = ToMarkdown(theProject)
|
theMD = ToMarkdown(theProject)
|
||||||
|
|
||||||
theMD.isNovel = True
|
theMD._isNovel = True
|
||||||
theMD.isNote = False
|
theMD._isNote = False
|
||||||
|
|
||||||
# Special Titles
|
# Special Titles
|
||||||
# ==============
|
# ==============
|
||||||
|
|
||||||
# Title
|
# Title
|
||||||
theMD.theTokens = [
|
theMD._theTokens = [
|
||||||
(theMD.T_TITLE, 1, "A Title", None, theMD.A_PBB | theMD.A_CENTRE),
|
(theMD.T_TITLE, 1, "A Title", None, theMD.A_PBB | theMD.A_CENTRE),
|
||||||
(theMD.T_EMPTY, 1, "", None, theMD.A_NONE),
|
(theMD.T_EMPTY, 1, "", None, theMD.A_NONE),
|
||||||
]
|
]
|
||||||
@@ -179,7 +179,7 @@ def testCoreToMarkdown_ConvertDirect(mockGUI):
|
|||||||
assert theMD.theResult == "# A Title\n\n"
|
assert theMD.theResult == "# A Title\n\n"
|
||||||
|
|
||||||
# Unnumbered
|
# Unnumbered
|
||||||
theMD.theTokens = [
|
theMD._theTokens = [
|
||||||
(theMD.T_UNNUM, 1, "Prologue", None, theMD.A_PBB),
|
(theMD.T_UNNUM, 1, "Prologue", None, theMD.A_PBB),
|
||||||
(theMD.T_EMPTY, 1, "", None, theMD.A_NONE),
|
(theMD.T_EMPTY, 1, "", None, theMD.A_NONE),
|
||||||
]
|
]
|
||||||
@@ -190,7 +190,7 @@ def testCoreToMarkdown_ConvertDirect(mockGUI):
|
|||||||
# ==========
|
# ==========
|
||||||
|
|
||||||
# Separator
|
# Separator
|
||||||
theMD.theTokens = [
|
theMD._theTokens = [
|
||||||
(theMD.T_SEP, 1, "* * *", None, theMD.A_CENTRE),
|
(theMD.T_SEP, 1, "* * *", None, theMD.A_CENTRE),
|
||||||
(theMD.T_EMPTY, 1, "", None, theMD.A_NONE),
|
(theMD.T_EMPTY, 1, "", None, theMD.A_NONE),
|
||||||
]
|
]
|
||||||
@@ -198,7 +198,7 @@ def testCoreToMarkdown_ConvertDirect(mockGUI):
|
|||||||
assert theMD.theResult == "* * *\n\n"
|
assert theMD.theResult == "* * *\n\n"
|
||||||
|
|
||||||
# Skip
|
# Skip
|
||||||
theMD.theTokens = [
|
theMD._theTokens = [
|
||||||
(theMD.T_SKIP, 1, "", None, theMD.A_NONE),
|
(theMD.T_SKIP, 1, "", None, theMD.A_NONE),
|
||||||
(theMD.T_EMPTY, 1, "", None, theMD.A_NONE),
|
(theMD.T_EMPTY, 1, "", None, theMD.A_NONE),
|
||||||
]
|
]
|
||||||
@@ -214,7 +214,7 @@ def testCoreToMarkdown_Complex(mockGUI, fncDir):
|
|||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject(mockGUI)
|
||||||
theMD = ToMarkdown(theProject)
|
theMD = ToMarkdown(theProject)
|
||||||
theMD.isNovel = True
|
theMD._isNovel = True
|
||||||
|
|
||||||
# Build Project
|
# Build Project
|
||||||
# =============
|
# =============
|
||||||
@@ -239,7 +239,7 @@ def testCoreToMarkdown_Complex(mockGUI, fncDir):
|
|||||||
]
|
]
|
||||||
|
|
||||||
for i in range(len(docText)):
|
for i in range(len(docText)):
|
||||||
theMD.theText = docText[i]
|
theMD._theText = docText[i]
|
||||||
theMD.doPreProcessing()
|
theMD.doPreProcessing()
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
mockGUI.theIndex = NWIndex(theProject)
|
mockGUI.theIndex = NWIndex(theProject)
|
||||||
theDoc = ToOdt(theProject, isFlat=True)
|
theDoc = ToOdt(theProject, isFlat=True)
|
||||||
|
|
||||||
theDoc.isNovel = True
|
theDoc._isNovel = True
|
||||||
|
|
||||||
def getStyle(styleName):
|
def getStyle(styleName):
|
||||||
for aSet in theDoc._autoPara.values():
|
for aSet in theDoc._autoPara.values():
|
||||||
@@ -248,7 +248,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
# =======
|
# =======
|
||||||
|
|
||||||
# Header 1
|
# Header 1
|
||||||
theDoc.theText = "# Title\n"
|
theDoc._theText = "# Title\n"
|
||||||
theDoc.tokenizeText()
|
theDoc.tokenizeText()
|
||||||
theDoc.initDocument()
|
theDoc.initDocument()
|
||||||
theDoc.doConvert()
|
theDoc.doConvert()
|
||||||
@@ -261,7 +261,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Header 2
|
# Header 2
|
||||||
theDoc.theText = "## Chapter\n"
|
theDoc._theText = "## Chapter\n"
|
||||||
theDoc.tokenizeText()
|
theDoc.tokenizeText()
|
||||||
theDoc.initDocument()
|
theDoc.initDocument()
|
||||||
theDoc.doConvert()
|
theDoc.doConvert()
|
||||||
@@ -274,7 +274,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Header 3
|
# Header 3
|
||||||
theDoc.theText = "### Scene\n"
|
theDoc._theText = "### Scene\n"
|
||||||
theDoc.tokenizeText()
|
theDoc.tokenizeText()
|
||||||
theDoc.initDocument()
|
theDoc.initDocument()
|
||||||
theDoc.doConvert()
|
theDoc.doConvert()
|
||||||
@@ -287,7 +287,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Header 4
|
# Header 4
|
||||||
theDoc.theText = "#### Section\n"
|
theDoc._theText = "#### Section\n"
|
||||||
theDoc.tokenizeText()
|
theDoc.tokenizeText()
|
||||||
theDoc.initDocument()
|
theDoc.initDocument()
|
||||||
theDoc.doConvert()
|
theDoc.doConvert()
|
||||||
@@ -300,7 +300,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Title
|
# Title
|
||||||
theDoc.theText = "#! Title\n"
|
theDoc._theText = "#! Title\n"
|
||||||
theDoc.tokenizeText()
|
theDoc.tokenizeText()
|
||||||
theDoc.initDocument()
|
theDoc.initDocument()
|
||||||
theDoc.doConvert()
|
theDoc.doConvert()
|
||||||
@@ -313,7 +313,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Unnumbered chapter
|
# Unnumbered chapter
|
||||||
theDoc.theText = "##! Prologue\n"
|
theDoc._theText = "##! Prologue\n"
|
||||||
theDoc.tokenizeText()
|
theDoc.tokenizeText()
|
||||||
theDoc.initDocument()
|
theDoc.initDocument()
|
||||||
theDoc.doConvert()
|
theDoc.doConvert()
|
||||||
@@ -329,7 +329,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
# ==========
|
# ==========
|
||||||
|
|
||||||
# Nested Text
|
# Nested Text
|
||||||
theDoc.theText = "Some ~~nested **bold** and _italics_ text~~ text."
|
theDoc._theText = "Some ~~nested **bold** and _italics_ text~~ text."
|
||||||
theDoc.tokenizeText()
|
theDoc.tokenizeText()
|
||||||
theDoc.initDocument()
|
theDoc.initDocument()
|
||||||
theDoc.doConvert()
|
theDoc.doConvert()
|
||||||
@@ -347,7 +347,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Hard Break
|
# Hard Break
|
||||||
theDoc.theText = "Some text.\nNext line\n"
|
theDoc._theText = "Some text.\nNext line\n"
|
||||||
theDoc.tokenizeText()
|
theDoc.tokenizeText()
|
||||||
theDoc.initDocument()
|
theDoc.initDocument()
|
||||||
theDoc.doConvert()
|
theDoc.doConvert()
|
||||||
@@ -360,7 +360,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Tab
|
# Tab
|
||||||
theDoc.theText = "\tItem 1\tItem 2\n"
|
theDoc._theText = "\tItem 1\tItem 2\n"
|
||||||
theDoc.tokenizeText()
|
theDoc.tokenizeText()
|
||||||
theDoc.initDocument()
|
theDoc.initDocument()
|
||||||
theDoc.doConvert()
|
theDoc.doConvert()
|
||||||
@@ -373,7 +373,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Tab in Format
|
# Tab in Format
|
||||||
theDoc.theText = "Some **bold\ttext**"
|
theDoc._theText = "Some **bold\ttext**"
|
||||||
theDoc.tokenizeText()
|
theDoc.tokenizeText()
|
||||||
theDoc.initDocument()
|
theDoc.initDocument()
|
||||||
theDoc.doConvert()
|
theDoc.doConvert()
|
||||||
@@ -387,7 +387,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Multiple Spaces
|
# Multiple Spaces
|
||||||
theDoc.theText = (
|
theDoc._theText = (
|
||||||
"### Scene\n\n"
|
"### Scene\n\n"
|
||||||
"Hello World\n\n"
|
"Hello World\n\n"
|
||||||
"Hello World\n\n"
|
"Hello World\n\n"
|
||||||
@@ -408,7 +408,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Synopsis, Comment, Keywords
|
# Synopsis, Comment, Keywords
|
||||||
theDoc.theText = (
|
theDoc._theText = (
|
||||||
"### Scene\n\n"
|
"### Scene\n\n"
|
||||||
"@pov: Jane\n\n"
|
"@pov: Jane\n\n"
|
||||||
"% synopsis: So it begins\n\n"
|
"% synopsis: So it begins\n\n"
|
||||||
@@ -435,7 +435,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Scene Separator
|
# Scene Separator
|
||||||
theDoc.theText = "### Scene One\n\nText\n\n### Scene Two\n\nText"
|
theDoc._theText = "### Scene One\n\nText\n\n### Scene Two\n\nText"
|
||||||
theDoc.setSceneFormat("* * *", False)
|
theDoc.setSceneFormat("* * *", False)
|
||||||
theDoc.tokenizeText()
|
theDoc.tokenizeText()
|
||||||
theDoc.doHeaders()
|
theDoc.doHeaders()
|
||||||
@@ -453,7 +453,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Scene Break
|
# Scene Break
|
||||||
theDoc.theText = "### Scene One\n\nText\n\n### Scene Two\n\nText"
|
theDoc._theText = "### Scene One\n\nText\n\n### Scene Two\n\nText"
|
||||||
theDoc.setSceneFormat("", False)
|
theDoc.setSceneFormat("", False)
|
||||||
theDoc.tokenizeText()
|
theDoc.tokenizeText()
|
||||||
theDoc.doHeaders()
|
theDoc.doHeaders()
|
||||||
@@ -471,7 +471,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Paragraph Styles
|
# Paragraph Styles
|
||||||
theDoc.theText = (
|
theDoc._theText = (
|
||||||
"### Scene\n\n"
|
"### Scene\n\n"
|
||||||
"@pov: Jane\n"
|
"@pov: Jane\n"
|
||||||
"@char: John\n"
|
"@char: John\n"
|
||||||
@@ -513,7 +513,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
assert getStyle("P8")._pAttr["margin-right"] == ["fo", "1.693cm"]
|
assert getStyle("P8")._pAttr["margin-right"] == ["fo", "1.693cm"]
|
||||||
|
|
||||||
# Justified
|
# Justified
|
||||||
theDoc.theText = (
|
theDoc._theText = (
|
||||||
"### Scene\n\n"
|
"### Scene\n\n"
|
||||||
"Regular paragraph\n\n"
|
"Regular paragraph\n\n"
|
||||||
"with\nbreak\n\n"
|
"with\nbreak\n\n"
|
||||||
@@ -536,7 +536,7 @@ def testCoreToOdt_Convert(mockGUI):
|
|||||||
assert getStyle("P9")._pAttr["text-align"] == ["fo", "left"]
|
assert getStyle("P9")._pAttr["text-align"] == ["fo", "left"]
|
||||||
|
|
||||||
# Page Breaks
|
# Page Breaks
|
||||||
theDoc.theText = (
|
theDoc._theText = (
|
||||||
"## Chapter One\n\n"
|
"## Chapter One\n\n"
|
||||||
"Text\n\n"
|
"Text\n\n"
|
||||||
"## Chapter Two\n\n"
|
"## Chapter Two\n\n"
|
||||||
@@ -568,11 +568,11 @@ def testCoreToOdt_ConvertDirect(mockGUI):
|
|||||||
mockGUI.theIndex = NWIndex(theProject)
|
mockGUI.theIndex = NWIndex(theProject)
|
||||||
theDoc = ToOdt(theProject, isFlat=True)
|
theDoc = ToOdt(theProject, isFlat=True)
|
||||||
|
|
||||||
theDoc.isNovel = True
|
theDoc._isNovel = True
|
||||||
|
|
||||||
# Justified
|
# Justified
|
||||||
theDoc = ToOdt(theProject, isFlat=True)
|
theDoc = ToOdt(theProject, isFlat=True)
|
||||||
theDoc.theTokens = [
|
theDoc._theTokens = [
|
||||||
(theDoc.T_TEXT, 1, "This is a paragraph", [], theDoc.A_JUSTIFY),
|
(theDoc.T_TEXT, 1, "This is a paragraph", [], theDoc.A_JUSTIFY),
|
||||||
(theDoc.T_EMPTY, 1, "", None, theDoc.A_NONE),
|
(theDoc.T_EMPTY, 1, "", None, theDoc.A_NONE),
|
||||||
]
|
]
|
||||||
@@ -593,7 +593,7 @@ def testCoreToOdt_ConvertDirect(mockGUI):
|
|||||||
|
|
||||||
# Page Break After
|
# Page Break After
|
||||||
theDoc = ToOdt(theProject, isFlat=True)
|
theDoc = ToOdt(theProject, isFlat=True)
|
||||||
theDoc.theTokens = [
|
theDoc._theTokens = [
|
||||||
(theDoc.T_TEXT, 1, "This is a paragraph", [], theDoc.A_PBA),
|
(theDoc.T_TEXT, 1, "This is a paragraph", [], theDoc.A_PBA),
|
||||||
(theDoc.T_EMPTY, 1, "", None, theDoc.A_NONE),
|
(theDoc.T_EMPTY, 1, "", None, theDoc.A_NONE),
|
||||||
]
|
]
|
||||||
@@ -623,12 +623,12 @@ def testCoreToOdt_SaveFlat(mockGUI, fncDir, outDir, refDir):
|
|||||||
mockGUI.theIndex = NWIndex(theProject)
|
mockGUI.theIndex = NWIndex(theProject)
|
||||||
|
|
||||||
theDoc = ToOdt(theProject, isFlat=True)
|
theDoc = ToOdt(theProject, isFlat=True)
|
||||||
theDoc.isNovel = True
|
theDoc._isNovel = True
|
||||||
assert theDoc.setLanguage(None) is False
|
assert theDoc.setLanguage(None) is False
|
||||||
assert theDoc.setLanguage("nb_NO") is True
|
assert theDoc.setLanguage("nb_NO") is True
|
||||||
theDoc.setColourHeaders(True)
|
theDoc.setColourHeaders(True)
|
||||||
|
|
||||||
theDoc.theText = (
|
theDoc._theText = (
|
||||||
"## Chapter One\n\n"
|
"## Chapter One\n\n"
|
||||||
"Text\n\n"
|
"Text\n\n"
|
||||||
"## Chapter Two\n\n"
|
"## Chapter Two\n\n"
|
||||||
@@ -660,9 +660,9 @@ def testCoreToOdt_SaveFull(mockGUI, fncDir, outDir, refDir):
|
|||||||
mockGUI.theIndex = NWIndex(theProject)
|
mockGUI.theIndex = NWIndex(theProject)
|
||||||
|
|
||||||
theDoc = ToOdt(theProject, isFlat=False)
|
theDoc = ToOdt(theProject, isFlat=False)
|
||||||
theDoc.isNovel = True
|
theDoc._isNovel = True
|
||||||
|
|
||||||
theDoc.theText = (
|
theDoc._theText = (
|
||||||
"## Chapter One\n\n"
|
"## Chapter One\n\n"
|
||||||
"Text\n\n"
|
"Text\n\n"
|
||||||
"## Chapter Two\n\n"
|
"## Chapter Two\n\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user