Move recent cache out of config, and update all tests
This commit is contained in:
+114
-92
@@ -74,8 +74,8 @@ class Config:
|
||||
self._appPath = self._appRoot
|
||||
|
||||
# Runtime Settings and Variables
|
||||
self.hasError = False # True if the config class encountered an error
|
||||
self.errData = [] # List of error messages
|
||||
self._hasError = False # True if the config class encountered an error
|
||||
self._errData = [] # List of error messages
|
||||
self.confChanged = False # True whenever the config has chenged, false after save
|
||||
self.cmdOpen = None # Path from command line for project to be opened on launch
|
||||
|
||||
@@ -92,6 +92,8 @@ class Config:
|
||||
# User Settings
|
||||
# =============
|
||||
|
||||
self._recentProj = RecentProjects(self._dataPath)
|
||||
|
||||
# General GUI Settings
|
||||
self.guiLang = self._qLocal.name()
|
||||
self.guiTheme = "" # GUI theme
|
||||
@@ -245,6 +247,18 @@ class Config:
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
|
||||
@property
|
||||
def hasError(self):
|
||||
return self._hasError
|
||||
|
||||
@property
|
||||
def recentProjects(self):
|
||||
return self._recentProj
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -282,6 +296,15 @@ class Config:
|
||||
return self._lastPath
|
||||
return Path.home().absolute()
|
||||
|
||||
def errorText(self):
|
||||
"""Compile and return error messages from the initialisation of
|
||||
the Config class, and clear the error buffer.
|
||||
"""
|
||||
errMessage = "<br>".join(self._errData)
|
||||
self._hasError = False
|
||||
self._errData = []
|
||||
return errMessage
|
||||
|
||||
##
|
||||
# Config Actions
|
||||
##
|
||||
@@ -321,12 +344,12 @@ class Config:
|
||||
else:
|
||||
self.saveConfig()
|
||||
|
||||
self.loadRecentCache()
|
||||
self._recentProj.loadCache()
|
||||
self._checkOptionalPackages()
|
||||
|
||||
logger.debug("Config initialisation complete")
|
||||
|
||||
return True
|
||||
return
|
||||
|
||||
def initLocalisation(self, nwApp):
|
||||
"""Initialise the localisation of the GUI.
|
||||
@@ -345,7 +368,7 @@ class Config:
|
||||
qTrans = QTranslator()
|
||||
lngFile = "%s_%s" % (lngBase, lngCode.replace("-", "_"))
|
||||
if lngFile not in self._qtTrans:
|
||||
if qTrans.load(lngFile, lngPath):
|
||||
if qTrans.load(lngFile, str(lngPath)):
|
||||
logger.debug("Loaded: %s", os.path.join(lngPath, lngFile))
|
||||
nwApp.installTranslator(qTrans)
|
||||
self._qtTrans[lngFile] = qTrans
|
||||
@@ -367,12 +390,12 @@ class Config:
|
||||
else:
|
||||
return []
|
||||
|
||||
for qmFile in os.listdir(self._nwLangPath):
|
||||
if not os.path.isfile(os.path.join(self._nwLangPath, qmFile)):
|
||||
for qmFile in Path(self._nwLangPath).iterdir():
|
||||
qmName = qmFile.name
|
||||
if not (qmFile.is_file() and qmName.startswith(fPre) and qmName.endswith(fExt)):
|
||||
continue
|
||||
if not qmFile.startswith(fPre) or not qmFile.endswith(fExt):
|
||||
continue
|
||||
qmLang = qmFile[len(fPre):-len(fExt)]
|
||||
|
||||
qmLang = qmName[len(fPre):-len(fExt)]
|
||||
qmName = QLocale(qmLang).nativeLanguageName().title()
|
||||
if qmLang and qmName and qmLang != "en_GB":
|
||||
langList[qmLang] = qmName
|
||||
@@ -392,9 +415,9 @@ class Config:
|
||||
except Exception as exc:
|
||||
logger.error("Could not load config file")
|
||||
logException()
|
||||
self.hasError = True
|
||||
self.errData.append("Could not load config file")
|
||||
self.errData.append(formatException(exc))
|
||||
self._hasError = True
|
||||
self._errData.append("Could not load config file")
|
||||
self._errData.append(formatException(exc))
|
||||
return False
|
||||
|
||||
# Main
|
||||
@@ -606,80 +629,13 @@ class Config:
|
||||
except Exception as exc:
|
||||
logger.error("Could not save config file")
|
||||
logException()
|
||||
self.hasError = True
|
||||
self.errData.append("Could not save config file")
|
||||
self.errData.append(formatException(exc))
|
||||
self._hasError = True
|
||||
self._errData.append("Could not save config file")
|
||||
self._errData.append(formatException(exc))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def loadRecentCache(self):
|
||||
"""Load the cache file for recent projects.
|
||||
"""
|
||||
self.recentProj = {}
|
||||
|
||||
cacheFile = self._dataPath / nwFiles.RECENT_FILE
|
||||
if not os.path.isfile(cacheFile):
|
||||
return True
|
||||
|
||||
try:
|
||||
with open(cacheFile, mode="r", encoding="utf-8") as inFile:
|
||||
theData = json.load(inFile)
|
||||
|
||||
for projPath, theEntry in theData.items():
|
||||
self.recentProj[projPath] = {
|
||||
"title": theEntry.get("title", ""),
|
||||
"time": theEntry.get("time", 0),
|
||||
"words": theEntry.get("words", 0),
|
||||
}
|
||||
|
||||
except Exception as exc:
|
||||
self.hasError = True
|
||||
self.errData.append("Could not load recent project cache")
|
||||
self.errData.append(formatException(exc))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def saveRecentCache(self):
|
||||
"""Save the cache dictionary of recent projects.
|
||||
"""
|
||||
cacheFile = self._dataPath / nwFiles.RECENT_FILE
|
||||
cacheTemp = cacheFile.with_suffix(".tmp")
|
||||
try:
|
||||
with open(cacheTemp, mode="w+", encoding="utf-8") as outFile:
|
||||
json.dump(self.recentProj, outFile, indent=2)
|
||||
cacheTemp.replace(cacheFile)
|
||||
except Exception as exc:
|
||||
self.hasError = True
|
||||
self.errData.append("Could not save recent project cache")
|
||||
self.errData.append(formatException(exc))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def updateRecentCache(self, projPath, projTitle, wordCount, saveTime):
|
||||
"""Add or update recent cache information on a given project.
|
||||
"""
|
||||
self.recentProj[os.path.abspath(projPath)] = {
|
||||
"title": projTitle,
|
||||
"time": int(saveTime),
|
||||
"words": int(wordCount),
|
||||
}
|
||||
return True
|
||||
|
||||
def removeFromRecentCache(self, thePath):
|
||||
"""Trying to remove a path from the recent projects cache.
|
||||
"""
|
||||
if thePath in self.recentProj:
|
||||
del self.recentProj[thePath]
|
||||
logger.debug("Removed recent: %s", thePath)
|
||||
self.saveRecentCache()
|
||||
else:
|
||||
logger.error("Unknown recent: %s", thePath)
|
||||
return False
|
||||
return True
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
@@ -828,15 +784,6 @@ class Config:
|
||||
def getTabWidth(self):
|
||||
return self.pxInt(max(self.tabWidth, 0))
|
||||
|
||||
def getErrData(self):
|
||||
"""Compile and return error messages from the initialisation of
|
||||
the Config class, and clear the error buffer.
|
||||
"""
|
||||
errMessage = "<br>".join(self.errData)
|
||||
self.hasError = False
|
||||
self.errData = []
|
||||
return errMessage
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
@@ -872,3 +819,78 @@ class Config:
|
||||
return
|
||||
|
||||
# END Class Config
|
||||
|
||||
|
||||
class RecentProjects:
|
||||
|
||||
def __init__(self, dataPath):
|
||||
self._dataPath = dataPath
|
||||
self._data = {}
|
||||
return
|
||||
|
||||
def loadCache(self):
|
||||
"""Load the cache file for recent projects.
|
||||
"""
|
||||
self._data = {}
|
||||
|
||||
cacheFile = self._dataPath / nwFiles.RECENT_FILE
|
||||
if not cacheFile.is_file():
|
||||
return True
|
||||
|
||||
try:
|
||||
with open(cacheFile, mode="r", encoding="utf-8") as inFile:
|
||||
theData = json.load(inFile)
|
||||
for projPath, theEntry in theData.items():
|
||||
self._data[projPath] = {
|
||||
"title": theEntry.get("title", ""),
|
||||
"words": theEntry.get("words", 0),
|
||||
"time": theEntry.get("time", 0),
|
||||
}
|
||||
except Exception:
|
||||
logger.error("Could not load recent project cache")
|
||||
logException()
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def saveCache(self):
|
||||
"""Save the cache dictionary of recent projects.
|
||||
"""
|
||||
cacheFile = self._dataPath / nwFiles.RECENT_FILE
|
||||
cacheTemp = cacheFile.with_suffix(".tmp")
|
||||
try:
|
||||
with open(cacheTemp, mode="w+", encoding="utf-8") as outFile:
|
||||
json.dump(self._data, outFile, indent=2)
|
||||
cacheTemp.replace(cacheFile)
|
||||
except Exception:
|
||||
logger.error("Could not save recent project cache")
|
||||
logException()
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def listEntries(self):
|
||||
"""List all items in the cache.
|
||||
"""
|
||||
return [(k, e["title"], e["words"], e["time"]) for k, e in self._data.items()]
|
||||
|
||||
def update(self, projPath, projTitle, wordCount, saveTime):
|
||||
"""Add or update recent cache information on a given project.
|
||||
"""
|
||||
self._data[str(projPath)] = {
|
||||
"title": projTitle,
|
||||
"words": int(wordCount),
|
||||
"time": int(saveTime),
|
||||
}
|
||||
self.saveCache()
|
||||
return
|
||||
|
||||
def remove(self, projPath):
|
||||
"""Try to remove a path from the recent projects cache.
|
||||
"""
|
||||
if self._data.pop(str(projPath), None) is not None:
|
||||
logger.debug("Removed recent: %s", projPath)
|
||||
self.saveCache()
|
||||
return
|
||||
|
||||
# END Class RecentProjects
|
||||
|
||||
@@ -354,10 +354,9 @@ class NWProject(QObject):
|
||||
self._loadProjectLocalisation()
|
||||
|
||||
# Update recent projects
|
||||
self.mainConf.updateRecentCache(
|
||||
self.mainConf.recentProjects.update(
|
||||
self._storage.storagePath, self._data.name, sum(self._data.initCounts), time()
|
||||
)
|
||||
self.mainConf.saveRecentCache()
|
||||
|
||||
# Check the project tree consistency
|
||||
for tItem in self._tree:
|
||||
@@ -424,10 +423,9 @@ class NWProject(QObject):
|
||||
self._storage.runPostSaveTasks(autoSave=autoSave)
|
||||
|
||||
# Update recent projects
|
||||
self.mainConf.updateRecentCache(
|
||||
self.mainConf.recentProjects.update(
|
||||
self._storage.storagePath, self._data.name, sum(self._data.currCounts), saveTime
|
||||
)
|
||||
self.mainConf.saveRecentCache()
|
||||
|
||||
self._storage.writeLockFile()
|
||||
self.mainGui.setStatus(self.tr("Saved Project: {0}").format(self._data.name))
|
||||
|
||||
@@ -229,7 +229,7 @@ class GuiProjectLoad(QDialog):
|
||||
).format(projName)
|
||||
)
|
||||
if msgYes:
|
||||
self.mainConf.removeFromRecentCache(
|
||||
self.mainConf.recentProjects.remove(
|
||||
selList[0].data(self.C_NAME, Qt.UserRole)
|
||||
)
|
||||
self._populateList()
|
||||
@@ -264,23 +264,17 @@ class GuiProjectLoad(QDialog):
|
||||
def _populateList(self):
|
||||
"""Populate the list box with recent project data.
|
||||
"""
|
||||
dataList = []
|
||||
for projPath in self.mainConf.recentProj:
|
||||
theEntry = self.mainConf.recentProj[projPath]
|
||||
theTitle = theEntry.get("title", "")
|
||||
theTime = theEntry.get("time", 0)
|
||||
theWords = theEntry.get("words", 0)
|
||||
dataList.append([theTitle, theTime, theWords, projPath])
|
||||
|
||||
self.listBox.clear()
|
||||
sortList = sorted(dataList, key=lambda x: x[1], reverse=True)
|
||||
for theTitle, theTime, theWords, projPath in sortList:
|
||||
dataList = self.mainConf.recentProjects.listEntries()
|
||||
sortList = sorted(dataList, key=lambda x: x[3], reverse=True)
|
||||
nwxIcon = self.mainGui.mainTheme.getIcon("proj_nwx")
|
||||
for path, title, words, time in sortList:
|
||||
newItem = QTreeWidgetItem([""]*4)
|
||||
newItem.setIcon(self.C_NAME, self.mainGui.mainTheme.getIcon("proj_nwx"))
|
||||
newItem.setText(self.C_NAME, theTitle)
|
||||
newItem.setData(self.C_NAME, Qt.UserRole, projPath)
|
||||
newItem.setText(self.C_COUNT, formatInt(theWords))
|
||||
newItem.setText(self.C_TIME, datetime.fromtimestamp(theTime).strftime("%x %X"))
|
||||
newItem.setIcon(self.C_NAME, nwxIcon)
|
||||
newItem.setText(self.C_NAME, title)
|
||||
newItem.setData(self.C_NAME, Qt.UserRole, path)
|
||||
newItem.setText(self.C_COUNT, formatInt(words))
|
||||
newItem.setText(self.C_TIME, datetime.fromtimestamp(time).strftime("%x %X"))
|
||||
newItem.setTextAlignment(self.C_NAME, Qt.AlignLeft | Qt.AlignVCenter)
|
||||
newItem.setTextAlignment(self.C_COUNT, Qt.AlignRight | Qt.AlignVCenter)
|
||||
newItem.setTextAlignment(self.C_TIME, Qt.AlignRight | Qt.AlignVCenter)
|
||||
|
||||
@@ -1144,7 +1144,7 @@ class GuiMain(QMainWindow):
|
||||
errors since it is initialised before the GUI itself.
|
||||
"""
|
||||
if self.mainConf.hasError:
|
||||
self.makeAlert(self.mainConf.getErrData(), nwAlert.ERROR)
|
||||
self.makeAlert(self.mainConf.errorText(), nwAlert.ERROR)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
Reference in New Issue
Block a user