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