Fix and optimise code (#904)
* Fix bug in early error reporting in main init * Update docstrings and optimise code in GuiMain * Update docstrings and optimise code in Config * Update docstrings and optimise code in common module * Update docstrings and optimise code in main project classes * Update the OptionState class * Update the spell checker class * Update the file converter classes and extend tests * Update the about, merge, split and item editor classes and extend tests * Update item editor test * Update about dialog tests * Some minor test cleanup * Fix typo and add clarification in contributing guide
This commit is contained in:
committed by
GitHub
parent
2a06db0a2b
commit
1c45331b0a
+70
-130
@@ -30,88 +30,40 @@ import logging
|
||||
import novelwriter
|
||||
|
||||
from novelwriter.constants import nwFiles
|
||||
from novelwriter.common import checkBool, checkFloat, checkInt, checkString
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
VALID_MAP = {
|
||||
"GuiWritingStats": {
|
||||
"winWidth", "winHeight", "widthCol0", "widthCol1", "widthCol2",
|
||||
"widthCol3", "sortCol", "sortOrder", "incNovel", "incNotes",
|
||||
"hideZeros", "hideNegative", "groupByDay", "showIdleTime", "histMax"
|
||||
},
|
||||
"GuiDocSplit": {"spLevel"},
|
||||
"GuiBuildNovel": {
|
||||
"winWidth", "winHeight", "boxWidth", "docWidth", "addNovel",
|
||||
"addNotes", "ignoreFlag", "justifyText", "excludeBody", "textFont",
|
||||
"textSize", "lineHeight", "noStyling", "incSynopsis", "incComments",
|
||||
"incKeywords", "incBodyText", "replaceTabs", "replaceUCode"
|
||||
},
|
||||
"GuiOutline": {"headerOrder", "columnWidth", "columnHidden"},
|
||||
"GuiProjectSettings": {
|
||||
"winWidth", "winHeight", "replaceColW", "statusColW", "importColW"
|
||||
},
|
||||
"GuiProjectDetails": {
|
||||
"winWidth", "winHeight", "widthCol0", "widthCol1", "widthCol2",
|
||||
"widthCol3", "widthCol4", "wordsPerPage", "countFrom", "clearDouble"
|
||||
},
|
||||
"GuiWordList": {"winWidth", "winHeight"}
|
||||
}
|
||||
|
||||
|
||||
class OptionState():
|
||||
|
||||
def __init__(self, theProject):
|
||||
|
||||
self.theProject = theProject
|
||||
self.theState = {}
|
||||
self.validMap = {
|
||||
"GuiWritingStats": {
|
||||
"winWidth",
|
||||
"winHeight",
|
||||
"widthCol0",
|
||||
"widthCol1",
|
||||
"widthCol2",
|
||||
"widthCol3",
|
||||
"sortCol",
|
||||
"sortOrder",
|
||||
"incNovel",
|
||||
"incNotes",
|
||||
"hideZeros",
|
||||
"hideNegative",
|
||||
"groupByDay",
|
||||
"showIdleTime",
|
||||
"histMax",
|
||||
},
|
||||
"GuiDocSplit": {
|
||||
"spLevel",
|
||||
},
|
||||
"GuiBuildNovel": {
|
||||
"winWidth",
|
||||
"winHeight",
|
||||
"boxWidth",
|
||||
"docWidth",
|
||||
"addNovel",
|
||||
"addNotes",
|
||||
"ignoreFlag",
|
||||
"justifyText",
|
||||
"excludeBody",
|
||||
"textFont",
|
||||
"textSize",
|
||||
"lineHeight",
|
||||
"noStyling",
|
||||
"incSynopsis",
|
||||
"incComments",
|
||||
"incKeywords",
|
||||
"incBodyText",
|
||||
"replaceTabs",
|
||||
"replaceUCode",
|
||||
},
|
||||
"GuiOutline": {
|
||||
"headerOrder",
|
||||
"columnWidth",
|
||||
"columnHidden",
|
||||
},
|
||||
"GuiProjectSettings": {
|
||||
"winWidth",
|
||||
"winHeight",
|
||||
"replaceColW",
|
||||
"statusColW",
|
||||
"importColW",
|
||||
},
|
||||
"GuiProjectDetails": {
|
||||
"winWidth",
|
||||
"winHeight",
|
||||
"widthCol0",
|
||||
"widthCol1",
|
||||
"widthCol2",
|
||||
"widthCol3",
|
||||
"widthCol4",
|
||||
"wordsPerPage",
|
||||
"countFrom",
|
||||
"clearDouble",
|
||||
},
|
||||
"GuiWordList": {
|
||||
"winWidth",
|
||||
"winHeight",
|
||||
}
|
||||
}
|
||||
|
||||
self._theState = {}
|
||||
return
|
||||
|
||||
##
|
||||
@@ -139,11 +91,11 @@ class OptionState():
|
||||
|
||||
# Filter out unused variables
|
||||
for aGroup in theState:
|
||||
if aGroup in self.validMap:
|
||||
self.theState[aGroup] = {}
|
||||
if aGroup in VALID_MAP:
|
||||
self._theState[aGroup] = {}
|
||||
for anOpt in theState[aGroup]:
|
||||
if anOpt in self.validMap[aGroup]:
|
||||
self.theState[aGroup][anOpt] = theState[aGroup][anOpt]
|
||||
if anOpt in VALID_MAP[aGroup]:
|
||||
self._theState[aGroup][anOpt] = theState[aGroup][anOpt]
|
||||
|
||||
return True
|
||||
|
||||
@@ -158,7 +110,7 @@ class OptionState():
|
||||
|
||||
try:
|
||||
with open(stateFile, mode="w+", encoding="utf-8") as outFile:
|
||||
json.dump(self.theState, outFile, indent=2)
|
||||
json.dump(self._theState, outFile, indent=2)
|
||||
except Exception:
|
||||
logger.error("Failed to save GUI options file")
|
||||
novelwriter.logException()
|
||||
@@ -170,21 +122,21 @@ class OptionState():
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setValue(self, setGroup, setName, setValue):
|
||||
def setValue(self, group, name, value):
|
||||
"""Saves a value, with a given group and name.
|
||||
"""
|
||||
if setGroup not in self.validMap:
|
||||
logger.error("Unknown option group '%s'", setGroup)
|
||||
if group not in VALID_MAP:
|
||||
logger.error("Unknown option group '%s'", group)
|
||||
return False
|
||||
|
||||
if setName not in self.validMap[setGroup]:
|
||||
logger.error("Unknown option name '%s'", setName)
|
||||
if name not in VALID_MAP[group]:
|
||||
logger.error("Unknown option name '%s'", name)
|
||||
return False
|
||||
|
||||
if setGroup not in self.theState:
|
||||
self.theState[setGroup] = {}
|
||||
if group not in self._theState:
|
||||
self._theState[group] = {}
|
||||
|
||||
self.theState[setGroup][setName] = setValue
|
||||
self._theState[group][name] = value
|
||||
|
||||
return True
|
||||
|
||||
@@ -192,79 +144,67 @@ class OptionState():
|
||||
# Getters
|
||||
##
|
||||
|
||||
def getValue(self, getGroup, getName, defaultValue):
|
||||
def getValue(self, group, name, default):
|
||||
"""Return an arbitrary type value, if it exists. Otherwise,
|
||||
return the default value.
|
||||
"""
|
||||
if getGroup in self.theState:
|
||||
if getName in self.theState[getGroup]:
|
||||
return self.theState[getGroup][getName]
|
||||
return defaultValue
|
||||
if group in self._theState:
|
||||
return self._theState[group].get(name, default)
|
||||
return default
|
||||
|
||||
def getString(self, getGroup, getName, defaultValue):
|
||||
def getString(self, group, name, default):
|
||||
"""Return the value as a string, if it exists. Otherwise, return
|
||||
the default value.
|
||||
"""
|
||||
if getGroup in self.theState:
|
||||
if getName in self.theState[getGroup]:
|
||||
return str(self.theState[getGroup][getName])
|
||||
return defaultValue
|
||||
if group in self._theState:
|
||||
return checkString(self._theState[group].get(name, default), default)
|
||||
return default
|
||||
|
||||
def getInt(self, getGroup, getName, defaultValue):
|
||||
def getInt(self, group, name, default):
|
||||
"""Return the value as an int, if it exists. Otherwise, return
|
||||
the default value.
|
||||
"""
|
||||
if getGroup in self.theState:
|
||||
if getName in self.theState[getGroup]:
|
||||
try:
|
||||
return int(self.theState[getGroup][getName])
|
||||
except Exception as e:
|
||||
logger.warning(str(e))
|
||||
return defaultValue
|
||||
return defaultValue
|
||||
if group in self._theState:
|
||||
return checkInt(self._theState[group].get(name, default), default)
|
||||
return default
|
||||
|
||||
def getFloat(self, getGroup, getName, defaultValue):
|
||||
def getFloat(self, group, name, default):
|
||||
"""Return the value as a float, if it exists. Otherwise, return
|
||||
the default value.
|
||||
"""
|
||||
if getGroup in self.theState:
|
||||
if getName in self.theState[getGroup]:
|
||||
try:
|
||||
return float(self.theState[getGroup][getName])
|
||||
except Exception as e:
|
||||
logger.warning(str(e))
|
||||
return defaultValue
|
||||
return defaultValue
|
||||
if group in self._theState:
|
||||
return checkFloat(self._theState[group].get(name, default), default)
|
||||
return default
|
||||
|
||||
def getBool(self, getGroup, getName, defaultValue):
|
||||
def getBool(self, group, name, default):
|
||||
"""Return the value as a bool, if it exists. Otherwise, return
|
||||
the default value.
|
||||
"""
|
||||
if getGroup in self.theState:
|
||||
if getName in self.theState[getGroup]:
|
||||
return bool(self.theState[getGroup][getName])
|
||||
return defaultValue
|
||||
if group in self._theState:
|
||||
if name in self._theState[group]:
|
||||
return checkBool(self._theState[group].get(name, default), default)
|
||||
return default
|
||||
|
||||
##
|
||||
# Validators
|
||||
##
|
||||
|
||||
def validIntRange(self, theValue, intA, intB, intDefault):
|
||||
def validIntRange(self, value, first, last, default):
|
||||
"""Check that an int is in a given range. If it isn't, return
|
||||
the default value.
|
||||
"""
|
||||
if isinstance(theValue, int):
|
||||
if theValue >= intA and theValue <= intB:
|
||||
return theValue
|
||||
return intDefault
|
||||
if isinstance(value, int):
|
||||
if value >= first and value <= last:
|
||||
return value
|
||||
return default
|
||||
|
||||
def validIntTuple(self, theValue, theTuple, intDefault):
|
||||
def validIntTuple(self, value, valid, default):
|
||||
"""Check that an int is an element of a tuple. If it isn't,
|
||||
return the default value.
|
||||
"""
|
||||
if isinstance(theValue, int):
|
||||
if theValue in theTuple:
|
||||
return theValue
|
||||
return intDefault
|
||||
if isinstance(value, int):
|
||||
if value in valid:
|
||||
return value
|
||||
return default
|
||||
|
||||
# END Class OptionState
|
||||
|
||||
Reference in New Issue
Block a user