Config class improvements (#826)
* Subclass ConfigParser * Remove redundant variables and update tests * Update file description * Move NWConfigParser class to common.py * Improve coverage of config class * Use NWConfigParser also in themes.py * Update config class file header * Fix comment * Update the usage of ConfigParser to recommended practice and extend tests * Improve logging for info level a bit
This commit is contained in:
committed by
GitHub
parent
e92506dc07
commit
e5c715695e
+174
-63
@@ -26,24 +26,27 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
|
||||
from datetime import datetime
|
||||
from configparser import ConfigParser
|
||||
|
||||
from PyQt5.QtWidgets import qApp
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from nw.enum import nwItemClass, nwItemType, nwItemLayout
|
||||
from nw.error import logException
|
||||
from nw.constants import nwConst, nwUnicode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# =============================================================================================== #
|
||||
# Checker Functions
|
||||
# =============================================================================================== #
|
||||
|
||||
def checkString(value, default, allowNone=False):
|
||||
"""Check if a variable is a string or a none.
|
||||
"""
|
||||
if allowNone:
|
||||
if value is None:
|
||||
return None
|
||||
if value == "None":
|
||||
return None
|
||||
if allowNone and (value is None or value == "None"):
|
||||
return None
|
||||
if isinstance(value, str):
|
||||
return str(value)
|
||||
return default
|
||||
@@ -52,11 +55,8 @@ def checkString(value, default, allowNone=False):
|
||||
def checkInt(value, default, allowNone=False):
|
||||
"""Check if a variable is an integer or a none.
|
||||
"""
|
||||
if allowNone:
|
||||
if value is None:
|
||||
return None
|
||||
if value == "None":
|
||||
return None
|
||||
if allowNone and (value is None or value == "None"):
|
||||
return None
|
||||
try:
|
||||
return int(value)
|
||||
except Exception:
|
||||
@@ -66,11 +66,9 @@ def checkInt(value, default, allowNone=False):
|
||||
def checkBool(value, default, allowNone=False):
|
||||
"""Check if a variable is a boolean or a none.
|
||||
"""
|
||||
if allowNone:
|
||||
if value is None:
|
||||
return None
|
||||
if value == "None":
|
||||
return None
|
||||
if allowNone and (value is None or value == "None"):
|
||||
return None
|
||||
|
||||
if isinstance(value, str):
|
||||
if value == "True":
|
||||
return True
|
||||
@@ -78,6 +76,7 @@ def checkBool(value, default, allowNone=False):
|
||||
return False
|
||||
else:
|
||||
return default
|
||||
|
||||
elif isinstance(value, int):
|
||||
if value == 1:
|
||||
return True
|
||||
@@ -85,67 +84,69 @@ def checkBool(value, default, allowNone=False):
|
||||
return False
|
||||
else:
|
||||
return default
|
||||
|
||||
return default
|
||||
|
||||
|
||||
def checkHandle(value, default, allowNone=False):
|
||||
"""Check if a value is a handle.
|
||||
"""
|
||||
if allowNone:
|
||||
if value is None:
|
||||
return None
|
||||
if value == "None":
|
||||
return None
|
||||
if allowNone and (value is None or value == "None"):
|
||||
return None
|
||||
if isHandle(value):
|
||||
return str(value)
|
||||
return default
|
||||
|
||||
|
||||
def isHandle(theString):
|
||||
# =============================================================================================== #
|
||||
# Validator Functions
|
||||
# =============================================================================================== #
|
||||
|
||||
def isHandle(value):
|
||||
"""Check if a string is a valid novelWriter handle.
|
||||
Note: This is case sensitive. Must be lower case!
|
||||
"""
|
||||
if not isinstance(theString, str):
|
||||
if not isinstance(value, str):
|
||||
return False
|
||||
if len(theString) != 13:
|
||||
if len(value) != 13:
|
||||
return False
|
||||
for c in theString:
|
||||
for c in value:
|
||||
if c not in "0123456789abcdef":
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def isTitleTag(theString):
|
||||
def isTitleTag(value):
|
||||
"""Check if a string is a valid title string.
|
||||
"""
|
||||
if not isinstance(theString, str):
|
||||
if not isinstance(value, str):
|
||||
return False
|
||||
if len(theString) != 7:
|
||||
if len(value) != 7:
|
||||
return False
|
||||
if not theString.startswith("T"):
|
||||
if not value.startswith("T"):
|
||||
return False
|
||||
for c in theString[1:]:
|
||||
for c in value[1:]:
|
||||
if c not in "0123456789":
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def isItemClass(theString):
|
||||
"""Check if an item is a calid nwItemClass identifier.
|
||||
def isItemClass(value):
|
||||
"""Check if a string is a valid nwItemClass identifier.
|
||||
"""
|
||||
return theString in nwItemClass.__members__
|
||||
return value in nwItemClass.__members__
|
||||
|
||||
|
||||
def isItemType(theString):
|
||||
"""Check if an item is a calid nwItemType identifier.
|
||||
def isItemType(value):
|
||||
"""Check if a string is a valid nwItemType identifier.
|
||||
"""
|
||||
return theString in nwItemType.__members__
|
||||
return value in nwItemType.__members__
|
||||
|
||||
|
||||
def isItemLayout(theString):
|
||||
"""Check if an item is a calid nwItemLayout identifier.
|
||||
def isItemLayout(value):
|
||||
"""Check if a string is a valid nwItemLayout identifier.
|
||||
"""
|
||||
return theString in nwItemLayout.__members__
|
||||
return value in nwItemLayout.__members__
|
||||
|
||||
|
||||
def hexToInt(value, default=0):
|
||||
@@ -159,14 +160,19 @@ def hexToInt(value, default=0):
|
||||
return default
|
||||
|
||||
|
||||
def formatInt(theInt):
|
||||
# =============================================================================================== #
|
||||
# Formatting Functions
|
||||
# =============================================================================================== #
|
||||
|
||||
def formatInt(value):
|
||||
"""Formats an integer with k, M, G etc.
|
||||
"""
|
||||
postFix = ["k", "M", "G", "T", "P", "E"]
|
||||
theVal = float(theInt)
|
||||
if not isinstance(value, int):
|
||||
return "ERR"
|
||||
|
||||
theVal = float(value)
|
||||
if theVal > 1000.0:
|
||||
for pF in postFix:
|
||||
for pF in ["k", "M", "G", "T", "P", "E"]:
|
||||
theVal /= 1000.0
|
||||
if theVal < 1000.0:
|
||||
if theVal < 10.0:
|
||||
@@ -176,7 +182,7 @@ def formatInt(theInt):
|
||||
else:
|
||||
return f"{theVal:3.0f}{nwUnicode.U_THSP}{pF}"
|
||||
|
||||
return str(theInt)
|
||||
return str(value)
|
||||
|
||||
|
||||
def formatTimeStamp(theTime, fileSafe=False):
|
||||
@@ -201,6 +207,23 @@ def formatTime(tS):
|
||||
return "ERROR"
|
||||
|
||||
|
||||
def parseTimeStamp(theStamp, default, allowNone=False):
|
||||
"""Parses a text representation of a time stamp and converts it into
|
||||
a float. Note that negative timestamps cause an OSError on Windows.
|
||||
See https://bugs.python.org/issue29097
|
||||
"""
|
||||
if str(theStamp).lower() == "none" and allowNone:
|
||||
return None
|
||||
try:
|
||||
return datetime.strptime(theStamp, nwConst.FMT_TSTAMP).timestamp()
|
||||
except Exception:
|
||||
return default
|
||||
|
||||
|
||||
# =============================================================================================== #
|
||||
# String Functions
|
||||
# =============================================================================================== #
|
||||
|
||||
def splitVersionNumber(vString):
|
||||
""" Splits a version string on the form aa.bb.cc into major, minor
|
||||
and patch, and computes an integer value aabbcc.
|
||||
@@ -308,27 +331,8 @@ def fuzzyTime(secDiff):
|
||||
).format(int(round(secDiff/31557600)))
|
||||
|
||||
|
||||
def makeFileNameSafe(theText):
|
||||
"""Returns a filename safe version of the text.
|
||||
"""
|
||||
cleanName = ""
|
||||
for c in theText.strip():
|
||||
if c.isalpha() or c.isdigit() or c == " ":
|
||||
cleanName += c
|
||||
return cleanName
|
||||
|
||||
|
||||
def getGuiItem(theName):
|
||||
"""Returns a QtWidget based on its objectName.
|
||||
"""
|
||||
for qWidget in qApp.topLevelWidgets():
|
||||
if qWidget.objectName() == theName:
|
||||
return qWidget
|
||||
return None
|
||||
|
||||
|
||||
def numberToRoman(numVal, isLower=False):
|
||||
"""Convert an integer to a roman number.
|
||||
"""Convert an integer to a Roman number.
|
||||
"""
|
||||
if not isinstance(numVal, int):
|
||||
return "NAN"
|
||||
@@ -349,3 +353,110 @@ def numberToRoman(numVal, isLower=False):
|
||||
break
|
||||
|
||||
return romNum.lower() if isLower else romNum
|
||||
|
||||
|
||||
# =============================================================================================== #
|
||||
# Other Functions
|
||||
# =============================================================================================== #
|
||||
|
||||
def makeFileNameSafe(theText):
|
||||
"""Returns a filename safe version of the text.
|
||||
"""
|
||||
cleanName = ""
|
||||
for c in theText.strip():
|
||||
if c.isalpha() or c.isdigit() or c == " ":
|
||||
cleanName += c
|
||||
return cleanName
|
||||
|
||||
|
||||
def getGuiItem(theName):
|
||||
"""Returns a QtWidget based on its objectName.
|
||||
"""
|
||||
for qWidget in qApp.topLevelWidgets():
|
||||
if qWidget.objectName() == theName:
|
||||
return qWidget
|
||||
return None
|
||||
|
||||
|
||||
# =============================================================================================== #
|
||||
# Classes
|
||||
# =============================================================================================== #
|
||||
|
||||
class NWConfigParser(ConfigParser):
|
||||
|
||||
CNF_STR = 0
|
||||
CNF_INT = 1
|
||||
CNF_BOOL = 2
|
||||
CNF_S_LST = 3
|
||||
CNF_I_LST = 4
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def rdStr(self, section, option, default):
|
||||
"""Read string value.
|
||||
"""
|
||||
return self._parseLine(section, option, default, self.CNF_STR)
|
||||
|
||||
def rdInt(self, section, option, default):
|
||||
"""Read integer value.
|
||||
"""
|
||||
return self._parseLine(section, option, default, self.CNF_INT)
|
||||
|
||||
def rdBool(self, section, option, default):
|
||||
"""Read boolean value.
|
||||
"""
|
||||
return self._parseLine(section, option, default, self.CNF_BOOL)
|
||||
|
||||
def rdStrList(self, section, option, default):
|
||||
"""Read string list.
|
||||
"""
|
||||
return self._parseLine(section, option, default, self.CNF_S_LST)
|
||||
|
||||
def rdIntList(self, section, option, default):
|
||||
"""Read integer list.
|
||||
"""
|
||||
return self._parseLine(section, option, default, self.CNF_I_LST)
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _unpackList(self, value, default, type):
|
||||
"""Unpack a comma-separated string of items into a list.
|
||||
"""
|
||||
inList = value.split(",")
|
||||
outList = []
|
||||
if isinstance(default, list):
|
||||
outList = default.copy()
|
||||
for i in range(min(len(inList), len(outList))):
|
||||
try:
|
||||
if type == self.CNF_S_LST:
|
||||
outList[i] = inList[i].strip()
|
||||
elif type == self.CNF_I_LST:
|
||||
outList[i] = int(inList[i].strip())
|
||||
except Exception:
|
||||
continue
|
||||
return outList
|
||||
|
||||
def _parseLine(self, section, option, default, type):
|
||||
"""Parse a line and return the correct datatype.
|
||||
"""
|
||||
if self.has_option(section, option):
|
||||
try:
|
||||
if type == self.CNF_STR:
|
||||
return self.get(section, option)
|
||||
elif type == self.CNF_INT:
|
||||
return self.getint(section, option)
|
||||
elif type == self.CNF_BOOL:
|
||||
return self.getboolean(section, option)
|
||||
elif type in (self.CNF_I_LST, self.CNF_S_LST):
|
||||
return self._unpackList(self.get(section, option), default, type)
|
||||
except ValueError:
|
||||
logger.error("Could not read '%s':'%s' from config", str(section), str(option))
|
||||
logException()
|
||||
return default
|
||||
|
||||
return default
|
||||
|
||||
# END Class NWConfigParser
|
||||
|
||||
+170
-372
@@ -28,7 +28,6 @@ import sys
|
||||
import json
|
||||
import shutil
|
||||
import logging
|
||||
import configparser
|
||||
|
||||
from time import time
|
||||
|
||||
@@ -39,7 +38,7 @@ from PyQt5.QtCore import (
|
||||
)
|
||||
|
||||
from nw.error import logException
|
||||
from nw.common import splitVersionNumber, formatTimeStamp
|
||||
from nw.common import splitVersionNumber, formatTimeStamp, NWConfigParser
|
||||
from nw.constants import nwConst, nwFiles, nwUnicode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -47,12 +46,6 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class Config:
|
||||
|
||||
CNF_STR = 0
|
||||
CNF_INT = 1
|
||||
CNF_BOOL = 2
|
||||
CNF_S_LST = 3
|
||||
CNF_I_LST = 4
|
||||
|
||||
LANG_NW = 1
|
||||
LANG_PROJ = 2
|
||||
|
||||
@@ -432,11 +425,11 @@ class Config:
|
||||
if self.confPath is None:
|
||||
return False
|
||||
|
||||
cnfParse = configparser.ConfigParser()
|
||||
theConf = NWConfigParser()
|
||||
cnfPath = os.path.join(self.confPath, self.confFile)
|
||||
try:
|
||||
with open(cnfPath, mode="r", encoding="utf-8") as inFile:
|
||||
cnfParse.read_file(inFile)
|
||||
theConf.read_file(inFile)
|
||||
except Exception as e:
|
||||
logger.error("Could not load config file")
|
||||
logException()
|
||||
@@ -447,237 +440,95 @@ class Config:
|
||||
|
||||
# Main
|
||||
cnfSec = "Main"
|
||||
self.guiTheme = self._parseLine(
|
||||
cnfParse, cnfSec, "theme", self.CNF_STR, self.guiTheme
|
||||
)
|
||||
self.guiSyntax = self._parseLine(
|
||||
cnfParse, cnfSec, "syntax", self.CNF_STR, self.guiSyntax
|
||||
)
|
||||
self.guiIcons = self._parseLine(
|
||||
cnfParse, cnfSec, "icons", self.CNF_STR, self.guiIcons
|
||||
)
|
||||
self.guiDark = self._parseLine(
|
||||
cnfParse, cnfSec, "guidark", self.CNF_BOOL, self.guiDark
|
||||
)
|
||||
self.guiFont = self._parseLine(
|
||||
cnfParse, cnfSec, "guifont", self.CNF_STR, self.guiFont
|
||||
)
|
||||
self.guiFontSize = self._parseLine(
|
||||
cnfParse, cnfSec, "guifontsize", self.CNF_INT, self.guiFontSize
|
||||
)
|
||||
self.lastNotes = self._parseLine(
|
||||
cnfParse, cnfSec, "lastnotes", self.CNF_STR, self.lastNotes
|
||||
)
|
||||
self.guiLang = self._parseLine(
|
||||
cnfParse, cnfSec, "guilang", self.CNF_STR, self.guiLang
|
||||
)
|
||||
self.guiTheme = theConf.rdStr(cnfSec, "theme", self.guiTheme)
|
||||
self.guiSyntax = theConf.rdStr(cnfSec, "syntax", self.guiSyntax)
|
||||
self.guiIcons = theConf.rdStr(cnfSec, "icons", self.guiIcons)
|
||||
self.guiDark = theConf.rdBool(cnfSec, "guidark", self.guiDark)
|
||||
self.guiFont = theConf.rdStr(cnfSec, "guifont", self.guiFont)
|
||||
self.guiFontSize = theConf.rdInt(cnfSec, "guifontsize", self.guiFontSize)
|
||||
self.lastNotes = theConf.rdStr(cnfSec, "lastnotes", self.lastNotes)
|
||||
self.guiLang = theConf.rdStr(cnfSec, "guilang", self.guiLang)
|
||||
|
||||
# Sizes
|
||||
cnfSec = "Sizes"
|
||||
self.winGeometry = self._parseLine(
|
||||
cnfParse, cnfSec, "geometry", self.CNF_I_LST, self.winGeometry
|
||||
)
|
||||
self.prefGeometry = self._parseLine(
|
||||
cnfParse, cnfSec, "preferences", self.CNF_I_LST, self.prefGeometry
|
||||
)
|
||||
self.treeColWidth = self._parseLine(
|
||||
cnfParse, cnfSec, "treecols", self.CNF_I_LST, self.treeColWidth
|
||||
)
|
||||
self.novelColWidth = self._parseLine(
|
||||
cnfParse, cnfSec, "novelcols", self.CNF_I_LST, self.novelColWidth
|
||||
)
|
||||
self.projColWidth = self._parseLine(
|
||||
cnfParse, cnfSec, "projcols", self.CNF_I_LST, self.projColWidth
|
||||
)
|
||||
self.mainPanePos = self._parseLine(
|
||||
cnfParse, cnfSec, "mainpane", self.CNF_I_LST, self.mainPanePos
|
||||
)
|
||||
self.docPanePos = self._parseLine(
|
||||
cnfParse, cnfSec, "docpane", self.CNF_I_LST, self.docPanePos
|
||||
)
|
||||
self.viewPanePos = self._parseLine(
|
||||
cnfParse, cnfSec, "viewpane", self.CNF_I_LST, self.viewPanePos
|
||||
)
|
||||
self.outlnPanePos = self._parseLine(
|
||||
cnfParse, cnfSec, "outlinepane", self.CNF_I_LST, self.outlnPanePos
|
||||
)
|
||||
self.isFullScreen = self._parseLine(
|
||||
cnfParse, cnfSec, "fullscreen", self.CNF_BOOL, self.isFullScreen
|
||||
)
|
||||
self.hideVScroll = self._parseLine(
|
||||
cnfParse, cnfSec, "hidevscroll", self.CNF_BOOL, self.hideVScroll
|
||||
)
|
||||
self.hideHScroll = self._parseLine(
|
||||
cnfParse, cnfSec, "hidehscroll", self.CNF_BOOL, self.hideHScroll
|
||||
)
|
||||
self.winGeometry = theConf.rdIntList(cnfSec, "geometry", self.winGeometry)
|
||||
self.prefGeometry = theConf.rdIntList(cnfSec, "preferences", self.prefGeometry)
|
||||
self.treeColWidth = theConf.rdIntList(cnfSec, "treecols", self.treeColWidth)
|
||||
self.novelColWidth = theConf.rdIntList(cnfSec, "novelcols", self.novelColWidth)
|
||||
self.projColWidth = theConf.rdIntList(cnfSec, "projcols", self.projColWidth)
|
||||
self.mainPanePos = theConf.rdIntList(cnfSec, "mainpane", self.mainPanePos)
|
||||
self.docPanePos = theConf.rdIntList(cnfSec, "docpane", self.docPanePos)
|
||||
self.viewPanePos = theConf.rdIntList(cnfSec, "viewpane", self.viewPanePos)
|
||||
self.outlnPanePos = theConf.rdIntList(cnfSec, "outlinepane", self.outlnPanePos)
|
||||
self.isFullScreen = theConf.rdBool(cnfSec, "fullscreen", self.isFullScreen)
|
||||
self.hideVScroll = theConf.rdBool(cnfSec, "hidevscroll", self.hideVScroll)
|
||||
self.hideHScroll = theConf.rdBool(cnfSec, "hidehscroll", self.hideHScroll)
|
||||
|
||||
# Project
|
||||
cnfSec = "Project"
|
||||
self.autoSaveProj = self._parseLine(
|
||||
cnfParse, cnfSec, "autosaveproject", self.CNF_INT, self.autoSaveProj
|
||||
)
|
||||
self.autoSaveDoc = self._parseLine(
|
||||
cnfParse, cnfSec, "autosavedoc", self.CNF_INT, self.autoSaveDoc
|
||||
)
|
||||
self.autoSaveProj = theConf.rdInt(cnfSec, "autosaveproject", self.autoSaveProj)
|
||||
self.autoSaveDoc = theConf.rdInt(cnfSec, "autosavedoc", self.autoSaveDoc)
|
||||
|
||||
# Editor
|
||||
cnfSec = "Editor"
|
||||
self.textFont = self._parseLine(
|
||||
cnfParse, cnfSec, "textfont", self.CNF_STR, self.textFont
|
||||
)
|
||||
self.textSize = self._parseLine(
|
||||
cnfParse, cnfSec, "textsize", self.CNF_INT, self.textSize
|
||||
)
|
||||
self.textFixedW = self._parseLine(
|
||||
cnfParse, cnfSec, "fixedwidth", self.CNF_BOOL, self.textFixedW
|
||||
)
|
||||
self.textWidth = self._parseLine(
|
||||
cnfParse, cnfSec, "width", self.CNF_INT, self.textWidth
|
||||
)
|
||||
self.textMargin = self._parseLine(
|
||||
cnfParse, cnfSec, "margin", self.CNF_INT, self.textMargin
|
||||
)
|
||||
self.tabWidth = self._parseLine(
|
||||
cnfParse, cnfSec, "tabwidth", self.CNF_INT, self.tabWidth
|
||||
)
|
||||
self.focusWidth = self._parseLine(
|
||||
cnfParse, cnfSec, "focuswidth", self.CNF_INT, self.focusWidth
|
||||
)
|
||||
self.hideFocusFooter = self._parseLine(
|
||||
cnfParse, cnfSec, "hidefocusfooter", self.CNF_BOOL, self.hideFocusFooter
|
||||
)
|
||||
self.doJustify = self._parseLine(
|
||||
cnfParse, cnfSec, "justify", self.CNF_BOOL, self.doJustify
|
||||
)
|
||||
self.autoSelect = self._parseLine(
|
||||
cnfParse, cnfSec, "autoselect", self.CNF_BOOL, self.autoSelect
|
||||
)
|
||||
self.doReplace = self._parseLine(
|
||||
cnfParse, cnfSec, "autoreplace", self.CNF_BOOL, self.doReplace
|
||||
)
|
||||
self.doReplaceSQuote = self._parseLine(
|
||||
cnfParse, cnfSec, "repsquotes", self.CNF_BOOL, self.doReplaceSQuote
|
||||
)
|
||||
self.doReplaceDQuote = self._parseLine(
|
||||
cnfParse, cnfSec, "repdquotes", self.CNF_BOOL, self.doReplaceDQuote
|
||||
)
|
||||
self.doReplaceDash = self._parseLine(
|
||||
cnfParse, cnfSec, "repdash", self.CNF_BOOL, self.doReplaceDash
|
||||
)
|
||||
self.doReplaceDots = self._parseLine(
|
||||
cnfParse, cnfSec, "repdots", self.CNF_BOOL, self.doReplaceDots
|
||||
)
|
||||
self.scrollPastEnd = self._parseLine(
|
||||
cnfParse, cnfSec, "scrollpastend", self.CNF_BOOL, self.scrollPastEnd
|
||||
)
|
||||
self.autoScroll = self._parseLine(
|
||||
cnfParse, cnfSec, "autoscroll", self.CNF_BOOL, self.autoScroll
|
||||
)
|
||||
self.autoScrollPos = self._parseLine(
|
||||
cnfParse, cnfSec, "autoscrollpos", self.CNF_INT, self.autoScrollPos
|
||||
)
|
||||
self.fmtSingleQuotes = self._parseLine(
|
||||
cnfParse, cnfSec, "fmtsinglequote", self.CNF_S_LST, self.fmtSingleQuotes
|
||||
)
|
||||
self.fmtDoubleQuotes = self._parseLine(
|
||||
cnfParse, cnfSec, "fmtdoublequote", self.CNF_S_LST, self.fmtDoubleQuotes
|
||||
)
|
||||
self.fmtPadBefore = self._parseLine(
|
||||
cnfParse, cnfSec, "fmtpadbefore", self.CNF_STR, self.fmtPadBefore
|
||||
)
|
||||
self.fmtPadAfter = self._parseLine(
|
||||
cnfParse, cnfSec, "fmtpadafter", self.CNF_STR, self.fmtPadAfter
|
||||
)
|
||||
self.fmtPadThin = self._parseLine(
|
||||
cnfParse, cnfSec, "fmtpadthin", self.CNF_BOOL, self.fmtPadThin
|
||||
)
|
||||
self.spellTool = self._parseLine(
|
||||
cnfParse, cnfSec, "spelltool", self.CNF_STR, self.spellTool
|
||||
)
|
||||
self.spellLanguage = self._parseLine(
|
||||
cnfParse, cnfSec, "spellcheck", self.CNF_STR, self.spellLanguage
|
||||
)
|
||||
self.showTabsNSpaces = self._parseLine(
|
||||
cnfParse, cnfSec, "showtabsnspaces", self.CNF_BOOL, self.showTabsNSpaces
|
||||
)
|
||||
self.showLineEndings = self._parseLine(
|
||||
cnfParse, cnfSec, "showlineendings", self.CNF_BOOL, self.showLineEndings
|
||||
)
|
||||
self.showMultiSpaces = self._parseLine(
|
||||
cnfParse, cnfSec, "showmultispaces", self.CNF_BOOL, self.showMultiSpaces
|
||||
)
|
||||
self.bigDocLimit = self._parseLine(
|
||||
cnfParse, cnfSec, "bigdoclimit", self.CNF_INT, self.bigDocLimit
|
||||
)
|
||||
self.showFullPath = self._parseLine(
|
||||
cnfParse, cnfSec, "showfullpath", self.CNF_BOOL, self.showFullPath
|
||||
)
|
||||
self.highlightQuotes = self._parseLine(
|
||||
cnfParse, cnfSec, "highlightquotes", self.CNF_BOOL, self.highlightQuotes
|
||||
)
|
||||
self.allowOpenSQuote = self._parseLine(
|
||||
cnfParse, cnfSec, "allowopensquote", self.CNF_BOOL, self.allowOpenSQuote
|
||||
)
|
||||
self.allowOpenDQuote = self._parseLine(
|
||||
cnfParse, cnfSec, "allowopendquote", self.CNF_BOOL, self.allowOpenDQuote
|
||||
)
|
||||
self.highlightEmph = self._parseLine(
|
||||
cnfParse, cnfSec, "highlightemph", self.CNF_BOOL, self.highlightEmph
|
||||
)
|
||||
self.stopWhenIdle = self._parseLine(
|
||||
cnfParse, cnfSec, "stopwhenidle", self.CNF_BOOL, self.stopWhenIdle
|
||||
)
|
||||
self.userIdleTime = self._parseLine(
|
||||
cnfParse, cnfSec, "useridletime", self.CNF_INT, self.userIdleTime
|
||||
)
|
||||
self.textFont = theConf.rdStr(cnfSec, "textfont", self.textFont)
|
||||
self.textSize = theConf.rdInt(cnfSec, "textsize", self.textSize)
|
||||
self.textFixedW = theConf.rdBool(cnfSec, "fixedwidth", self.textFixedW)
|
||||
self.textWidth = theConf.rdInt(cnfSec, "width", self.textWidth)
|
||||
self.textMargin = theConf.rdInt(cnfSec, "margin", self.textMargin)
|
||||
self.tabWidth = theConf.rdInt(cnfSec, "tabwidth", self.tabWidth)
|
||||
self.focusWidth = theConf.rdInt(cnfSec, "focuswidth", self.focusWidth)
|
||||
self.hideFocusFooter = theConf.rdBool(cnfSec, "hidefocusfooter", self.hideFocusFooter)
|
||||
self.doJustify = theConf.rdBool(cnfSec, "justify", self.doJustify)
|
||||
self.autoSelect = theConf.rdBool(cnfSec, "autoselect", self.autoSelect)
|
||||
self.doReplace = theConf.rdBool(cnfSec, "autoreplace", self.doReplace)
|
||||
self.doReplaceSQuote = theConf.rdBool(cnfSec, "repsquotes", self.doReplaceSQuote)
|
||||
self.doReplaceDQuote = theConf.rdBool(cnfSec, "repdquotes", self.doReplaceDQuote)
|
||||
self.doReplaceDash = theConf.rdBool(cnfSec, "repdash", self.doReplaceDash)
|
||||
self.doReplaceDots = theConf.rdBool(cnfSec, "repdots", self.doReplaceDots)
|
||||
self.scrollPastEnd = theConf.rdBool(cnfSec, "scrollpastend", self.scrollPastEnd)
|
||||
self.autoScroll = theConf.rdBool(cnfSec, "autoscroll", self.autoScroll)
|
||||
self.autoScrollPos = theConf.rdInt(cnfSec, "autoscrollpos", self.autoScrollPos)
|
||||
self.fmtSingleQuotes = theConf.rdStrList(cnfSec, "fmtsinglequote", self.fmtSingleQuotes)
|
||||
self.fmtDoubleQuotes = theConf.rdStrList(cnfSec, "fmtdoublequote", self.fmtDoubleQuotes)
|
||||
self.fmtPadBefore = theConf.rdStr(cnfSec, "fmtpadbefore", self.fmtPadBefore)
|
||||
self.fmtPadAfter = theConf.rdStr(cnfSec, "fmtpadafter", self.fmtPadAfter)
|
||||
self.fmtPadThin = theConf.rdBool(cnfSec, "fmtpadthin", self.fmtPadThin)
|
||||
self.spellTool = theConf.rdStr(cnfSec, "spelltool", self.spellTool)
|
||||
self.spellLanguage = theConf.rdStr(cnfSec, "spellcheck", self.spellLanguage)
|
||||
self.showTabsNSpaces = theConf.rdBool(cnfSec, "showtabsnspaces", self.showTabsNSpaces)
|
||||
self.showLineEndings = theConf.rdBool(cnfSec, "showlineendings", self.showLineEndings)
|
||||
self.showMultiSpaces = theConf.rdBool(cnfSec, "showmultispaces", self.showMultiSpaces)
|
||||
self.bigDocLimit = theConf.rdInt(cnfSec, "bigdoclimit", self.bigDocLimit)
|
||||
self.showFullPath = theConf.rdBool(cnfSec, "showfullpath", self.showFullPath)
|
||||
self.highlightQuotes = theConf.rdBool(cnfSec, "highlightquotes", self.highlightQuotes)
|
||||
self.allowOpenSQuote = theConf.rdBool(cnfSec, "allowopensquote", self.allowOpenSQuote)
|
||||
self.allowOpenDQuote = theConf.rdBool(cnfSec, "allowopendquote", self.allowOpenDQuote)
|
||||
self.highlightEmph = theConf.rdBool(cnfSec, "highlightemph", self.highlightEmph)
|
||||
self.stopWhenIdle = theConf.rdBool(cnfSec, "stopwhenidle", self.stopWhenIdle)
|
||||
self.userIdleTime = theConf.rdInt(cnfSec, "useridletime", self.userIdleTime)
|
||||
|
||||
# Backup
|
||||
cnfSec = "Backup"
|
||||
self.backupPath = self._parseLine(
|
||||
cnfParse, cnfSec, "backuppath", self.CNF_STR, self.backupPath
|
||||
)
|
||||
self.backupOnClose = self._parseLine(
|
||||
cnfParse, cnfSec, "backuponclose", self.CNF_BOOL, self.backupOnClose
|
||||
)
|
||||
self.askBeforeBackup = self._parseLine(
|
||||
cnfParse, cnfSec, "askbeforebackup", self.CNF_BOOL, self.askBeforeBackup
|
||||
)
|
||||
self.backupPath = theConf.rdStr(cnfSec, "backuppath", self.backupPath)
|
||||
self.backupOnClose = theConf.rdBool(cnfSec, "backuponclose", self.backupOnClose)
|
||||
self.askBeforeBackup = theConf.rdBool(cnfSec, "askbeforebackup", self.askBeforeBackup)
|
||||
|
||||
# State
|
||||
cnfSec = "State"
|
||||
self.showRefPanel = self._parseLine(
|
||||
cnfParse, cnfSec, "showrefpanel", self.CNF_BOOL, self.showRefPanel
|
||||
)
|
||||
self.viewComments = self._parseLine(
|
||||
cnfParse, cnfSec, "viewcomments", self.CNF_BOOL, self.viewComments
|
||||
)
|
||||
self.viewSynopsis = self._parseLine(
|
||||
cnfParse, cnfSec, "viewsynopsis", self.CNF_BOOL, self.viewSynopsis
|
||||
)
|
||||
self.searchCase = self._parseLine(
|
||||
cnfParse, cnfSec, "searchcase", self.CNF_BOOL, self.searchCase
|
||||
)
|
||||
self.searchWord = self._parseLine(
|
||||
cnfParse, cnfSec, "searchword", self.CNF_BOOL, self.searchWord
|
||||
)
|
||||
self.searchRegEx = self._parseLine(
|
||||
cnfParse, cnfSec, "searchregex", self.CNF_BOOL, self.searchRegEx
|
||||
)
|
||||
self.searchLoop = self._parseLine(
|
||||
cnfParse, cnfSec, "searchloop", self.CNF_BOOL, self.searchLoop
|
||||
)
|
||||
self.searchNextFile = self._parseLine(
|
||||
cnfParse, cnfSec, "searchnextfile", self.CNF_BOOL, self.searchNextFile
|
||||
)
|
||||
self.searchMatchCap = self._parseLine(
|
||||
cnfParse, cnfSec, "searchmatchcap", self.CNF_BOOL, self.searchMatchCap
|
||||
)
|
||||
self.showRefPanel = theConf.rdBool(cnfSec, "showrefpanel", self.showRefPanel)
|
||||
self.viewComments = theConf.rdBool(cnfSec, "viewcomments", self.viewComments)
|
||||
self.viewSynopsis = theConf.rdBool(cnfSec, "viewsynopsis", self.viewSynopsis)
|
||||
self.searchCase = theConf.rdBool(cnfSec, "searchcase", self.searchCase)
|
||||
self.searchWord = theConf.rdBool(cnfSec, "searchword", self.searchWord)
|
||||
self.searchRegEx = theConf.rdBool(cnfSec, "searchregex", self.searchRegEx)
|
||||
self.searchLoop = theConf.rdBool(cnfSec, "searchloop", self.searchLoop)
|
||||
self.searchNextFile = theConf.rdBool(cnfSec, "searchnextfile", self.searchNextFile)
|
||||
self.searchMatchCap = theConf.rdBool(cnfSec, "searchmatchcap", self.searchMatchCap)
|
||||
|
||||
# Path
|
||||
cnfSec = "Path"
|
||||
self.lastPath = self._parseLine(
|
||||
cnfParse, cnfSec, "lastpath", self.CNF_STR, self.lastPath
|
||||
)
|
||||
self.lastPath = theConf.rdStr(cnfSec, "lastpath", self.lastPath)
|
||||
|
||||
# Check Certain Values for None
|
||||
self.spellLanguage = self._checkNone(self.spellLanguage)
|
||||
@@ -700,115 +551,106 @@ class Config:
|
||||
if self.confPath is None:
|
||||
return False
|
||||
|
||||
cnfParse = configparser.ConfigParser()
|
||||
theConf = NWConfigParser()
|
||||
|
||||
# Set options
|
||||
theConf["Main"] = {
|
||||
"timestamp": formatTimeStamp(time()),
|
||||
"theme": str(self.guiTheme),
|
||||
"syntax": str(self.guiSyntax),
|
||||
"icons": str(self.guiIcons),
|
||||
"guidark": str(self.guiDark),
|
||||
"guifont": str(self.guiFont),
|
||||
"guifontsize": str(self.guiFontSize),
|
||||
"lastnotes": str(self.lastNotes),
|
||||
"guilang": str(self.guiLang),
|
||||
}
|
||||
|
||||
# Main
|
||||
cnfSec = "Main"
|
||||
cnfParse.add_section(cnfSec)
|
||||
cnfParse.set(cnfSec, "timestamp", formatTimeStamp(time()))
|
||||
cnfParse.set(cnfSec, "theme", str(self.guiTheme))
|
||||
cnfParse.set(cnfSec, "syntax", str(self.guiSyntax))
|
||||
cnfParse.set(cnfSec, "icons", str(self.guiIcons))
|
||||
cnfParse.set(cnfSec, "guidark", str(self.guiDark))
|
||||
cnfParse.set(cnfSec, "guifont", str(self.guiFont))
|
||||
cnfParse.set(cnfSec, "guifontsize", str(self.guiFontSize))
|
||||
cnfParse.set(cnfSec, "lastnotes", str(self.lastNotes))
|
||||
cnfParse.set(cnfSec, "guilang", str(self.guiLang))
|
||||
theConf["Sizes"] = {
|
||||
"geometry": self._packList(self.winGeometry),
|
||||
"preferences": self._packList(self.prefGeometry),
|
||||
"treecols": self._packList(self.treeColWidth),
|
||||
"novelcols": self._packList(self.novelColWidth),
|
||||
"projcols": self._packList(self.projColWidth),
|
||||
"mainpane": self._packList(self.mainPanePos),
|
||||
"docpane": self._packList(self.docPanePos),
|
||||
"viewpane": self._packList(self.viewPanePos),
|
||||
"outlinepane": self._packList(self.outlnPanePos),
|
||||
"fullscreen": str(self.isFullScreen),
|
||||
"hidevscroll": str(self.hideVScroll),
|
||||
"hidehscroll": str(self.hideHScroll),
|
||||
}
|
||||
|
||||
# Sizes
|
||||
cnfSec = "Sizes"
|
||||
cnfParse.add_section(cnfSec)
|
||||
cnfParse.set(cnfSec, "geometry", self._packList(self.winGeometry))
|
||||
cnfParse.set(cnfSec, "preferences", self._packList(self.prefGeometry))
|
||||
cnfParse.set(cnfSec, "treecols", self._packList(self.treeColWidth))
|
||||
cnfParse.set(cnfSec, "novelcols", self._packList(self.novelColWidth))
|
||||
cnfParse.set(cnfSec, "projcols", self._packList(self.projColWidth))
|
||||
cnfParse.set(cnfSec, "mainpane", self._packList(self.mainPanePos))
|
||||
cnfParse.set(cnfSec, "docpane", self._packList(self.docPanePos))
|
||||
cnfParse.set(cnfSec, "viewpane", self._packList(self.viewPanePos))
|
||||
cnfParse.set(cnfSec, "outlinepane", self._packList(self.outlnPanePos))
|
||||
cnfParse.set(cnfSec, "fullscreen", str(self.isFullScreen))
|
||||
cnfParse.set(cnfSec, "hidevscroll", str(self.hideVScroll))
|
||||
cnfParse.set(cnfSec, "hidehscroll", str(self.hideHScroll))
|
||||
theConf["Project"] = {
|
||||
"autosaveproject": str(self.autoSaveProj),
|
||||
"autosavedoc": str(self.autoSaveDoc),
|
||||
}
|
||||
|
||||
# Project
|
||||
cnfSec = "Project"
|
||||
cnfParse.add_section(cnfSec)
|
||||
cnfParse.set(cnfSec, "autosaveproject", str(self.autoSaveProj))
|
||||
cnfParse.set(cnfSec, "autosavedoc", str(self.autoSaveDoc))
|
||||
theConf["Editor"] = {
|
||||
"textfont": str(self.textFont),
|
||||
"textsize": str(self.textSize),
|
||||
"fixedwidth": str(self.textFixedW),
|
||||
"width": str(self.textWidth),
|
||||
"margin": str(self.textMargin),
|
||||
"tabwidth": str(self.tabWidth),
|
||||
"focuswidth": str(self.focusWidth),
|
||||
"hidefocusfooter": str(self.hideFocusFooter),
|
||||
"justify": str(self.doJustify),
|
||||
"autoselect": str(self.autoSelect),
|
||||
"autoreplace": str(self.doReplace),
|
||||
"repsquotes": str(self.doReplaceSQuote),
|
||||
"repdquotes": str(self.doReplaceDQuote),
|
||||
"repdash": str(self.doReplaceDash),
|
||||
"repdots": str(self.doReplaceDots),
|
||||
"scrollpastend": str(self.scrollPastEnd),
|
||||
"autoscroll": str(self.autoScroll),
|
||||
"autoscrollpos": str(self.autoScrollPos),
|
||||
"fmtsinglequote": self._packList(self.fmtSingleQuotes),
|
||||
"fmtdoublequote": self._packList(self.fmtDoubleQuotes),
|
||||
"fmtpadbefore": str(self.fmtPadBefore),
|
||||
"fmtpadafter": str(self.fmtPadAfter),
|
||||
"fmtpadthin": str(self.fmtPadThin),
|
||||
"spelltool": str(self.spellTool),
|
||||
"spellcheck": str(self.spellLanguage),
|
||||
"showtabsnspaces": str(self.showTabsNSpaces),
|
||||
"showlineendings": str(self.showLineEndings),
|
||||
"showmultispaces": str(self.showMultiSpaces),
|
||||
"bigdoclimit": str(self.bigDocLimit),
|
||||
"showfullpath": str(self.showFullPath),
|
||||
"highlightquotes": str(self.highlightQuotes),
|
||||
"allowopensquote": str(self.allowOpenSQuote),
|
||||
"allowopendquote": str(self.allowOpenDQuote),
|
||||
"highlightemph": str(self.highlightEmph),
|
||||
"stopwhenidle": str(self.stopWhenIdle),
|
||||
"useridletime": str(self.userIdleTime),
|
||||
}
|
||||
|
||||
# Editor
|
||||
cnfSec = "Editor"
|
||||
cnfParse.add_section(cnfSec)
|
||||
cnfParse.set(cnfSec, "textfont", str(self.textFont))
|
||||
cnfParse.set(cnfSec, "textsize", str(self.textSize))
|
||||
cnfParse.set(cnfSec, "fixedwidth", str(self.textFixedW))
|
||||
cnfParse.set(cnfSec, "width", str(self.textWidth))
|
||||
cnfParse.set(cnfSec, "margin", str(self.textMargin))
|
||||
cnfParse.set(cnfSec, "tabwidth", str(self.tabWidth))
|
||||
cnfParse.set(cnfSec, "focuswidth", str(self.focusWidth))
|
||||
cnfParse.set(cnfSec, "hidefocusfooter", str(self.hideFocusFooter))
|
||||
cnfParse.set(cnfSec, "justify", str(self.doJustify))
|
||||
cnfParse.set(cnfSec, "autoselect", str(self.autoSelect))
|
||||
cnfParse.set(cnfSec, "autoreplace", str(self.doReplace))
|
||||
cnfParse.set(cnfSec, "repsquotes", str(self.doReplaceSQuote))
|
||||
cnfParse.set(cnfSec, "repdquotes", str(self.doReplaceDQuote))
|
||||
cnfParse.set(cnfSec, "repdash", str(self.doReplaceDash))
|
||||
cnfParse.set(cnfSec, "repdots", str(self.doReplaceDots))
|
||||
cnfParse.set(cnfSec, "scrollpastend", str(self.scrollPastEnd))
|
||||
cnfParse.set(cnfSec, "autoscroll", str(self.autoScroll))
|
||||
cnfParse.set(cnfSec, "autoscrollpos", str(self.autoScrollPos))
|
||||
cnfParse.set(cnfSec, "fmtsinglequote", self._packList(self.fmtSingleQuotes))
|
||||
cnfParse.set(cnfSec, "fmtdoublequote", self._packList(self.fmtDoubleQuotes))
|
||||
cnfParse.set(cnfSec, "fmtpadbefore", str(self.fmtPadBefore))
|
||||
cnfParse.set(cnfSec, "fmtpadafter", str(self.fmtPadAfter))
|
||||
cnfParse.set(cnfSec, "fmtpadthin", str(self.fmtPadThin))
|
||||
cnfParse.set(cnfSec, "spelltool", str(self.spellTool))
|
||||
cnfParse.set(cnfSec, "spellcheck", str(self.spellLanguage))
|
||||
cnfParse.set(cnfSec, "showtabsnspaces", str(self.showTabsNSpaces))
|
||||
cnfParse.set(cnfSec, "showlineendings", str(self.showLineEndings))
|
||||
cnfParse.set(cnfSec, "showmultispaces", str(self.showMultiSpaces))
|
||||
cnfParse.set(cnfSec, "bigdoclimit", str(self.bigDocLimit))
|
||||
cnfParse.set(cnfSec, "showfullpath", str(self.showFullPath))
|
||||
cnfParse.set(cnfSec, "highlightquotes", str(self.highlightQuotes))
|
||||
cnfParse.set(cnfSec, "allowopensquote", str(self.allowOpenSQuote))
|
||||
cnfParse.set(cnfSec, "allowopendquote", str(self.allowOpenDQuote))
|
||||
cnfParse.set(cnfSec, "highlightemph", str(self.highlightEmph))
|
||||
cnfParse.set(cnfSec, "stopwhenidle", str(self.stopWhenIdle))
|
||||
cnfParse.set(cnfSec, "useridletime", str(self.userIdleTime))
|
||||
theConf["Backup"] = {
|
||||
"backuppath": str(self.backupPath),
|
||||
"backuponclose": str(self.backupOnClose),
|
||||
"askbeforebackup": str(self.askBeforeBackup),
|
||||
}
|
||||
|
||||
# Backup
|
||||
cnfSec = "Backup"
|
||||
cnfParse.add_section(cnfSec)
|
||||
cnfParse.set(cnfSec, "backuppath", str(self.backupPath))
|
||||
cnfParse.set(cnfSec, "backuponclose", str(self.backupOnClose))
|
||||
cnfParse.set(cnfSec, "askbeforebackup", str(self.askBeforeBackup))
|
||||
theConf["State"] = {
|
||||
"showrefpanel": str(self.showRefPanel),
|
||||
"viewcomments": str(self.viewComments),
|
||||
"viewsynopsis": str(self.viewSynopsis),
|
||||
"searchcase": str(self.searchCase),
|
||||
"searchword": str(self.searchWord),
|
||||
"searchregex": str(self.searchRegEx),
|
||||
"searchloop": str(self.searchLoop),
|
||||
"searchnextfile": str(self.searchNextFile),
|
||||
"searchmatchcap": str(self.searchMatchCap),
|
||||
}
|
||||
|
||||
# State
|
||||
cnfSec = "State"
|
||||
cnfParse.add_section(cnfSec)
|
||||
cnfParse.set(cnfSec, "showrefpanel", str(self.showRefPanel))
|
||||
cnfParse.set(cnfSec, "viewcomments", str(self.viewComments))
|
||||
cnfParse.set(cnfSec, "viewsynopsis", str(self.viewSynopsis))
|
||||
cnfParse.set(cnfSec, "searchcase", str(self.searchCase))
|
||||
cnfParse.set(cnfSec, "searchword", str(self.searchWord))
|
||||
cnfParse.set(cnfSec, "searchregex", str(self.searchRegEx))
|
||||
cnfParse.set(cnfSec, "searchloop", str(self.searchLoop))
|
||||
cnfParse.set(cnfSec, "searchnextfile", str(self.searchNextFile))
|
||||
cnfParse.set(cnfSec, "searchmatchcap", str(self.searchMatchCap))
|
||||
|
||||
# Path
|
||||
cnfSec = "Path"
|
||||
cnfParse.add_section(cnfSec)
|
||||
cnfParse.set(cnfSec, "lastpath", str(self.lastPath))
|
||||
theConf["Path"] = {
|
||||
"lastpath": str(self.lastPath),
|
||||
}
|
||||
|
||||
# Write config file
|
||||
cnfPath = os.path.join(self.confPath, self.confFile)
|
||||
try:
|
||||
with open(cnfPath, mode="w", encoding="utf-8") as outFile:
|
||||
cnfParse.write(outFile)
|
||||
theConf.write(outFile)
|
||||
self.confChanged = False
|
||||
except Exception as e:
|
||||
logger.error("Could not save config file")
|
||||
@@ -884,7 +726,7 @@ class Config:
|
||||
return True
|
||||
|
||||
def updateRecentCache(self, projPath, projTitle, wordCount, saveTime):
|
||||
"""Add or update recent cache information o9n a given project.
|
||||
"""Add or update recent cache information on a given project.
|
||||
"""
|
||||
self.recentProj[os.path.abspath(projPath)] = {
|
||||
"title": projTitle,
|
||||
@@ -992,12 +834,6 @@ class Config:
|
||||
self.confChanged = True
|
||||
return self.showRefPanel
|
||||
|
||||
def getErrData(self):
|
||||
errMessage = "<br>".join(self.errData)
|
||||
self.hasError = False
|
||||
self.errData = []
|
||||
return errMessage
|
||||
|
||||
def setViewComments(self, viewState):
|
||||
self.viewComments = viewState
|
||||
self.confChanged = True
|
||||
@@ -1051,6 +887,12 @@ class Config:
|
||||
def getFocusWidth(self):
|
||||
return self.pxInt(self.focusWidth)
|
||||
|
||||
def getErrData(self):
|
||||
errMessage = "<br>".join(self.errData)
|
||||
self.hasError = False
|
||||
self.errData = []
|
||||
return errMessage
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
@@ -1060,52 +902,8 @@ class Config:
|
||||
"""
|
||||
return ", ".join([str(inVal) for inVal in inData])
|
||||
|
||||
def _unpackList(self, inStr, listDefault, cnfType):
|
||||
"""Unpack a comma-separated string of items into a list.
|
||||
"""
|
||||
inData = inStr.split(",")
|
||||
outData = listDefault.copy()
|
||||
for i in range(min(len(inData), len(listDefault))):
|
||||
try:
|
||||
if cnfType == self.CNF_S_LST:
|
||||
outData[i] = inData[i].strip()
|
||||
elif cnfType == self.CNF_I_LST:
|
||||
outData[i] = int(inData[i].strip())
|
||||
else:
|
||||
continue
|
||||
except Exception:
|
||||
continue
|
||||
return outData
|
||||
|
||||
def _parseLine(self, cnfParse, cnfSec, cnfName, cnfType, cnfDefault):
|
||||
"""Parse a line and return the correct datatype.
|
||||
"""
|
||||
if cnfParse.has_section(cnfSec):
|
||||
if cnfParse.has_option(cnfSec, cnfName):
|
||||
try:
|
||||
if cnfType == self.CNF_STR:
|
||||
return cnfParse.get(cnfSec, cnfName)
|
||||
elif cnfType == self.CNF_INT:
|
||||
return cnfParse.getint(cnfSec, cnfName)
|
||||
elif cnfType == self.CNF_BOOL:
|
||||
return cnfParse.getboolean(cnfSec, cnfName)
|
||||
elif cnfType == self.CNF_I_LST:
|
||||
return self._unpackList(
|
||||
cnfParse.get(cnfSec, cnfName), cnfDefault, self.CNF_I_LST
|
||||
)
|
||||
elif cnfType == self.CNF_S_LST:
|
||||
return self._unpackList(
|
||||
cnfParse.get(cnfSec, cnfName), cnfDefault, self.CNF_S_LST
|
||||
)
|
||||
except ValueError:
|
||||
logger.error("Failed to load value from config file.")
|
||||
logException()
|
||||
return cnfDefault
|
||||
|
||||
return cnfDefault
|
||||
|
||||
def _checkNone(self, checkVal):
|
||||
"""Return a NoneType if the value correspomds to None, otherwise
|
||||
"""Return a NoneType if the value corresponds to None, otherwise
|
||||
return the value unchanged.
|
||||
"""
|
||||
if checkVal is None:
|
||||
|
||||
+2
-2
@@ -257,10 +257,10 @@ class NWIndex():
|
||||
|
||||
# If the file is archived or trashed, we don't index the file itself
|
||||
if self.theProject.projTree.isTrashRoot(theItem.itemParent):
|
||||
logger.info("Not indexing trash item '%s'", tHandle)
|
||||
logger.debug("Not indexing trash item '%s'", tHandle)
|
||||
return False
|
||||
if theRoot.itemClass == nwItemClass.ARCHIVE:
|
||||
logger.info("Not indexing archived item '%s'", tHandle)
|
||||
logger.debug("Not indexing archived item '%s'", tHandle)
|
||||
return False
|
||||
|
||||
itemClass = theItem.itemClass
|
||||
|
||||
+2
-2
@@ -251,7 +251,7 @@ class NWItem():
|
||||
if isinstance(expState, str):
|
||||
self.isExpanded = (expState == str(True))
|
||||
else:
|
||||
self.isExpanded = (expState == True) # noqa: E712
|
||||
self.isExpanded = (expState is True)
|
||||
return
|
||||
|
||||
def setExported(self, expState):
|
||||
@@ -260,7 +260,7 @@ class NWItem():
|
||||
if isinstance(expState, str):
|
||||
self.isExported = (expState == str(True))
|
||||
else:
|
||||
self.isExported = (expState == True) # noqa: E712
|
||||
self.isExported = (expState is True)
|
||||
return
|
||||
|
||||
##
|
||||
|
||||
+3
-2
@@ -369,7 +369,7 @@ class NWProject():
|
||||
|
||||
self.clearProject()
|
||||
self.projPath = os.path.abspath(os.path.dirname(fileName))
|
||||
logger.debug("Opening project: %s", self.projPath)
|
||||
logger.info("Opening project: %s", self.projPath)
|
||||
|
||||
# Standard Folders and Files
|
||||
# ==========================
|
||||
@@ -611,7 +611,7 @@ class NWProject():
|
||||
if not self.ensureFolderStructure():
|
||||
return False
|
||||
|
||||
logger.debug("Saving project: %s", self.projPath)
|
||||
logger.info("Saving project: %s", self.projPath)
|
||||
|
||||
if autoSave:
|
||||
self.autoCount += 1
|
||||
@@ -712,6 +712,7 @@ class NWProject():
|
||||
def closeProject(self, idleTime=0):
|
||||
"""Close the current project and clear all meta data.
|
||||
"""
|
||||
logger.info("Closing project: %s", self.projPath)
|
||||
self.optState.saveSettings()
|
||||
self.projTree.writeToCFile()
|
||||
self._appendSessionStats(idleTime)
|
||||
|
||||
+28
-46
@@ -27,7 +27,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import nw
|
||||
import os
|
||||
import logging
|
||||
import configparser
|
||||
|
||||
from math import ceil
|
||||
from functools import partial
|
||||
@@ -39,6 +38,7 @@ from PyQt5.QtGui import (
|
||||
)
|
||||
|
||||
from nw.enum import nwAlert
|
||||
from nw.common import NWConfigParser
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -280,7 +280,7 @@ class GuiTheme:
|
||||
return False
|
||||
|
||||
# Config File
|
||||
confParser = configparser.ConfigParser()
|
||||
confParser = NWConfigParser()
|
||||
try:
|
||||
with open(self.confFile, mode="r", encoding="utf-8") as inFile:
|
||||
confParser.read_file(inFile)
|
||||
@@ -292,13 +292,13 @@ class GuiTheme:
|
||||
# Main
|
||||
cnfSec = "Main"
|
||||
if confParser.has_section(cnfSec):
|
||||
self.themeName = self._parseLine(confParser, cnfSec, "name", "")
|
||||
self.themeDescription = self._parseLine(confParser, cnfSec, "description", "N/A")
|
||||
self.themeAuthor = self._parseLine(confParser, cnfSec, "author", "N/A")
|
||||
self.themeCredit = self._parseLine(confParser, cnfSec, "credit", "N/A")
|
||||
self.themeUrl = self._parseLine(confParser, cnfSec, "url", "")
|
||||
self.themeLicense = self._parseLine(confParser, cnfSec, "license", "N/A")
|
||||
self.themeLicenseUrl = self._parseLine(confParser, cnfSec, "licenseurl", "")
|
||||
self.themeName = confParser.rdStr(cnfSec, "name", "")
|
||||
self.themeDescription = confParser.rdStr(cnfSec, "description", "N/A")
|
||||
self.themeAuthor = confParser.rdStr(cnfSec, "author", "N/A")
|
||||
self.themeCredit = confParser.rdStr(cnfSec, "credit", "N/A")
|
||||
self.themeUrl = confParser.rdStr(cnfSec, "url", "")
|
||||
self.themeLicense = confParser.rdStr(cnfSec, "license", "N/A")
|
||||
self.themeLicenseUrl = confParser.rdStr(cnfSec, "licenseurl", "")
|
||||
|
||||
# Palette
|
||||
cnfSec = "Palette"
|
||||
@@ -338,7 +338,7 @@ class GuiTheme:
|
||||
"""
|
||||
logger.debug("Loading syntax theme files")
|
||||
|
||||
confParser = configparser.ConfigParser()
|
||||
confParser = NWConfigParser()
|
||||
try:
|
||||
with open(self.syntaxFile, mode="r", encoding="utf-8") as inFile:
|
||||
confParser.read_file(inFile)
|
||||
@@ -350,13 +350,13 @@ class GuiTheme:
|
||||
# Main
|
||||
cnfSec = "Main"
|
||||
if confParser.has_section(cnfSec):
|
||||
self.syntaxName = self._parseLine(confParser, cnfSec, "name", "")
|
||||
self.syntaxDescription = self._parseLine(confParser, cnfSec, "description", "")
|
||||
self.syntaxAuthor = self._parseLine(confParser, cnfSec, "author", "")
|
||||
self.syntaxCredit = self._parseLine(confParser, cnfSec, "credit", "")
|
||||
self.syntaxUrl = self._parseLine(confParser, cnfSec, "url", "")
|
||||
self.syntaxLicense = self._parseLine(confParser, cnfSec, "license", "")
|
||||
self.syntaxLicenseUrl = self._parseLine(confParser, cnfSec, "licenseurl", "")
|
||||
self.syntaxName = confParser.rdStr(cnfSec, "name", "")
|
||||
self.syntaxDescription = confParser.rdStr(cnfSec, "description", "")
|
||||
self.syntaxAuthor = confParser.rdStr(cnfSec, "author", "")
|
||||
self.syntaxCredit = confParser.rdStr(cnfSec, "credit", "")
|
||||
self.syntaxUrl = confParser.rdStr(cnfSec, "url", "")
|
||||
self.syntaxLicense = confParser.rdStr(cnfSec, "license", "")
|
||||
self.syntaxLicenseUrl = confParser.rdStr(cnfSec, "licenseurl", "")
|
||||
|
||||
# Syntax
|
||||
cnfSec = "Syntax"
|
||||
@@ -388,7 +388,7 @@ class GuiTheme:
|
||||
if self.themeList:
|
||||
return self.themeList
|
||||
|
||||
confParser = configparser.ConfigParser()
|
||||
confParser = NWConfigParser()
|
||||
for themeDir in os.listdir(os.path.join(self.mainConf.themeRoot, self.guiPath)):
|
||||
themeConf = os.path.join(
|
||||
self.mainConf.themeRoot, self.guiPath, themeDir, self.confName
|
||||
@@ -420,7 +420,7 @@ class GuiTheme:
|
||||
if self.syntaxList:
|
||||
return self.syntaxList
|
||||
|
||||
confParser = configparser.ConfigParser()
|
||||
confParser = NWConfigParser()
|
||||
syntaxDir = os.path.join(self.mainConf.themeRoot, self.syntaxPath)
|
||||
for syntaxFile in os.listdir(syntaxDir):
|
||||
syntaxPath = os.path.join(syntaxDir, syntaxFile)
|
||||
@@ -486,15 +486,6 @@ class GuiTheme:
|
||||
self.guiPalette.setColor(paletteVal, QColor(*readCol))
|
||||
return
|
||||
|
||||
def _parseLine(self, confParser, cnfSec, cnfName, cnfDefault):
|
||||
"""Simple wrapper for the config parser to check that the entry
|
||||
exists before attempting to load it.
|
||||
"""
|
||||
if confParser.has_section(cnfSec):
|
||||
if confParser.has_option(cnfSec, cnfName):
|
||||
return confParser.get(cnfSec, cnfName)
|
||||
return cnfDefault
|
||||
|
||||
# End Class GuiTheme
|
||||
|
||||
|
||||
@@ -644,7 +635,7 @@ class GuiIcons:
|
||||
return False
|
||||
|
||||
# Config File
|
||||
confParser = configparser.ConfigParser()
|
||||
confParser = NWConfigParser()
|
||||
try:
|
||||
with open(self.confFile, mode="r", encoding="utf-8") as inFile:
|
||||
confParser.read_file(inFile)
|
||||
@@ -656,13 +647,13 @@ class GuiIcons:
|
||||
# Main
|
||||
cnfSec = "Main"
|
||||
if confParser.has_section(cnfSec):
|
||||
self.themeName = self._parseLine(confParser, cnfSec, "name", "")
|
||||
self.themeDescription = self._parseLine(confParser, cnfSec, "description", "")
|
||||
self.themeAuthor = self._parseLine(confParser, cnfSec, "author", "N/A")
|
||||
self.themeCredit = self._parseLine(confParser, cnfSec, "credit", "N/A")
|
||||
self.themeUrl = self._parseLine(confParser, cnfSec, "url", "")
|
||||
self.themeLicense = self._parseLine(confParser, cnfSec, "license", "N/A")
|
||||
self.themeLicenseUrl = self._parseLine(confParser, cnfSec, "licenseurl", "")
|
||||
self.themeName = confParser.rdStr(cnfSec, "name", "")
|
||||
self.themeDescription = confParser.rdStr(cnfSec, "description", "")
|
||||
self.themeAuthor = confParser.rdStr(cnfSec, "author", "N/A")
|
||||
self.themeCredit = confParser.rdStr(cnfSec, "credit", "N/A")
|
||||
self.themeUrl = confParser.rdStr(cnfSec, "url", "")
|
||||
self.themeLicense = confParser.rdStr(cnfSec, "license", "N/A")
|
||||
self.themeLicenseUrl = confParser.rdStr(cnfSec, "licenseurl", "")
|
||||
|
||||
# Palette
|
||||
cnfSec = "Map"
|
||||
@@ -736,7 +727,7 @@ class GuiIcons:
|
||||
if self.themeList:
|
||||
return self.themeList
|
||||
|
||||
confParser = configparser.ConfigParser()
|
||||
confParser = NWConfigParser()
|
||||
for themeDir in os.listdir(self.mainConf.iconPath):
|
||||
themePath = os.path.join(self.mainConf.iconPath, themeDir)
|
||||
if not os.path.isdir(themePath) or themeDir == self.fbackName:
|
||||
@@ -818,13 +809,4 @@ class GuiIcons:
|
||||
|
||||
return QIcon()
|
||||
|
||||
def _parseLine(self, confParser, cnfSec, cnfName, cnfDefault):
|
||||
"""Simple wrapper for the config parser to check that the entry
|
||||
exists before attempting to load it.
|
||||
"""
|
||||
if confParser.has_section(cnfSec):
|
||||
if confParser.has_option(cnfSec, cnfName):
|
||||
return confParser.get(cnfSec, cnfName)
|
||||
return cnfDefault
|
||||
|
||||
# END Class GuiIcons
|
||||
|
||||
+5
-8
@@ -71,12 +71,9 @@ class GuiMain(QMainWindow):
|
||||
logger.info("OS: %s", self.mainConf.osType)
|
||||
logger.info("Kernel: %s", self.mainConf.kernelVer)
|
||||
logger.info("Host: %s", self.mainConf.hostName)
|
||||
logger.info("Qt5 Version: %s (%d)",
|
||||
self.mainConf.verQtString, self.mainConf.verQtValue)
|
||||
logger.info("PyQt5 Version: %s (%d)",
|
||||
self.mainConf.verPyQtString, self.mainConf.verPyQtValue)
|
||||
logger.info("Python Version: %s (0x%x)",
|
||||
self.mainConf.verPyString, self.mainConf.verPyHexVal)
|
||||
logger.info("Qt5: %s (%d)", self.mainConf.verQtString, self.mainConf.verQtValue)
|
||||
logger.info("PyQt5: %s (%d)", self.mainConf.verPyQtString, self.mainConf.verPyQtValue)
|
||||
logger.info("Python: %s (0x%x)", self.mainConf.verPyString, self.mainConf.verPyHexVal)
|
||||
logger.info("GUI Language: %s", self.mainConf.guiLang)
|
||||
|
||||
# Core Classes
|
||||
@@ -297,7 +294,7 @@ class GuiMain(QMainWindow):
|
||||
logger.debug("Opening project from additional command line option")
|
||||
self.openProject(self.mainConf.cmdOpen)
|
||||
|
||||
logger.debug("novelWriter is ready ...")
|
||||
logger.info("novelWriter is ready ...")
|
||||
self.setStatus(self.tr("novelWriter is ready ..."))
|
||||
|
||||
return
|
||||
@@ -872,7 +869,7 @@ class GuiMain(QMainWindow):
|
||||
logger.error("No project open")
|
||||
return False
|
||||
|
||||
logger.debug("Rebuilding index ...")
|
||||
logger.info("Rebuilding index ...")
|
||||
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||
tStart = time()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user