From ca0a756fe5fbb32294a47993462c3520539f6e12 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Mon, 10 Jun 2019 14:41:32 +0200 Subject: [PATCH] Added autosave and theme to preferences dialog --- nw/config.py | 6 +- nw/gui/configeditor.py | 81 +++++++++++++++++-- nw/gui/winmain.py | 23 ++++-- nw/project/project.py | 20 +++-- nw/theme.py | 43 +++++++++- .../{default => default_dark}/styles.css | 4 + .../{default => default_dark}/theme.conf | 3 + nw/themes/default_light/styles.css | 7 ++ nw/themes/default_light/theme.conf | 18 +++++ 9 files changed, 177 insertions(+), 28 deletions(-) rename nw/themes/{default => default_dark}/styles.css (87%) rename nw/themes/{default => default_dark}/theme.conf (92%) create mode 100644 nw/themes/default_light/styles.css create mode 100644 nw/themes/default_light/theme.conf diff --git a/nw/config.py b/nw/config.py index f65f9554..8db01cfd 100644 --- a/nw/config.py +++ b/nw/config.py @@ -43,13 +43,14 @@ class Config: self.appPath = None self.appRoot = None self.guiPath = None + self.themeRoot = None self.themePath = None # Set default values self.confChanged = False ## General - self.guiTheme = "default" + self.guiTheme = "default_dark" self.winGeometry = [1100, 650] self.treeColWidth = [120, 30, 50] self.mainPanePos = [300, 800] @@ -106,7 +107,8 @@ class Config: self.appRoot = path.join(self.appPath,path.pardir) self.helpPath = path.join(self.appRoot,"help","en_GB") self.guiPath = path.join(self.appPath,"gui") - self.themePath = path.join(self.appPath,"themes") + self.themeRoot = path.join(self.appPath,"themes") + self.themePath = path.join(self.themeRoot) # If config folder does not exist, make it. # This assumes that the os config folder itself exists. diff --git a/nw/gui/configeditor.py b/nw/gui/configeditor.py index bd440272..bd67eb72 100644 --- a/nw/gui/configeditor.py +++ b/nw/gui/configeditor.py @@ -20,8 +20,7 @@ from PyQt5.QtGui import QIcon, QPixmap, QColor, QBrush, QStandardItemModel from PyQt5.QtSvg import QSvgWidget from PyQt5.QtWidgets import ( QDialog, QHBoxLayout, QVBoxLayout, QFormLayout, QLineEdit, QPlainTextEdit, QLabel, - QWidget, QTabWidget, QDialogButtonBox, QListWidget, QListWidgetItem, QPushButton, - QColorDialog, QAbstractItemView, QTreeWidget, QTreeWidgetItem + QWidget, QTabWidget, QDialogButtonBox, QSpinBox, QGroupBox, QComboBox, QMessageBox ) from nw.enum import nwAlert @@ -40,7 +39,7 @@ class GuiConfigEditor(QDialog): self.outerBox = QHBoxLayout() self.innerBox = QVBoxLayout() - self.setWindowTitle("%s Configuration" % nw.__package__) + self.setWindowTitle("Preferences") self.gradPath = path.abspath(path.join(self.mainConf.appPath,"graphics","block.svg")) self.svgGradient = QSvgWidget(self.gradPath) @@ -70,8 +69,21 @@ class GuiConfigEditor(QDialog): return def _doSave(self): + logger.verbose("ConfigEditor save button clicked") - self.close() + + needsRestart = False + needsRestart |= self.tabMain.saveValues() + + if needsRestart: + msgBox = QMessageBox() + msgBox.information( + self, "Preferences", + "Some changes will not be applied until
%s has been restarted." % nw.__package__ + ) + + self.accept() + return def _doClose(self): @@ -86,12 +98,65 @@ class GuiConfigEditGeneral(QWidget): def __init__(self, theParent, theProject): QWidget.__init__(self, theParent) - self.theParent = theParent - self.theProject = theProject - self.mainForm = QFormLayout() + self.mainConf = nw.CONFIG + self.theParent = theParent + self.theProject = theProject + self.outerBox = QVBoxLayout() - self.setLayout(self.mainForm) + # User Interface + self.guiLook = QGroupBox("User Interface", self) + self.guiLookForm = QFormLayout(self) + self.guiLook.setLayout(self.guiLookForm) + + self.theThemes = self.theParent.theTheme.listThemes() + self.guiLookTheme = QComboBox() + for themeDir, themeName in self.theThemes: + self.guiLookTheme.addItem(themeName, themeDir) + themeIdx = self.guiLookTheme.findData(self.mainConf.guiTheme) + if themeIdx != -1: + self.guiLookTheme.setCurrentIndex(themeIdx) + self.guiLookForm.addRow("Theme", self.guiLookTheme) + + # AutoSave + self.autoSave = QGroupBox("Auto-Save", self) + self.autoSaveForm = QFormLayout(self) + self.autoSave.setLayout(self.autoSaveForm) + + self.autoSaveDoc = QSpinBox(self) + self.autoSaveDoc.setMinimum(5) + self.autoSaveDoc.setMaximum(600) + self.autoSaveDoc.setSingleStep(1) + self.autoSaveDoc.setValue(self.mainConf.autoSaveDoc) + self.autoSaveForm.addRow("Save Document (seconds)", self.autoSaveDoc) + + self.autoSaveProj = QSpinBox(self) + self.autoSaveProj.setMinimum(5) + self.autoSaveProj.setMaximum(600) + self.autoSaveProj.setSingleStep(1) + self.autoSaveProj.setValue(self.mainConf.autoSaveProj) + self.autoSaveForm.addRow("Save Project (seconds)", self.autoSaveProj) + + self.outerBox.addWidget(self.guiLook) + self.outerBox.addWidget(self.autoSave) + self.setLayout(self.outerBox) return + def saveValues(self): + + autoSaveDoc = self.autoSaveDoc.value() + autoSaveProj = self.autoSaveProj.value() + guiTheme = self.guiLookTheme.currentData() + + # Check if restart is needed + needsRestart = False + needsRestart |= self.mainConf.guiTheme != guiTheme + + self.mainConf.autoSaveDoc = autoSaveDoc + self.mainConf.autoSaveProj = autoSaveProj + self.mainConf.guiTheme = guiTheme + self.mainConf.confChanged = True + + return needsRestart + # END Class GuiConfigEditGeneral diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py index dad460ef..8e2400c4 100644 --- a/nw/gui/winmain.py +++ b/nw/gui/winmain.py @@ -19,7 +19,7 @@ from PyQt5.QtCore import Qt, QTimer from PyQt5.QtGui import QIcon, QPixmap, QColor from PyQt5.QtWidgets import ( qApp, QWidget, QMainWindow, QVBoxLayout, QFrame, QSplitter, QFileDialog, - QShortcut, QMessageBox, QProgressDialog + QShortcut, QMessageBox, QProgressDialog, QDialog ) from nw.gui.doctree import GuiDocTree @@ -50,7 +50,7 @@ class GuiMain(QMainWindow): logger.debug("Initialising GUI ...") self.mainConf = nw.CONFIG - self.theTheme = Theme() + self.theTheme = Theme(self) self.theProject = NWProject(self) self.theIndex = NWIndex(self.theProject, self) self.hasProject = False @@ -119,15 +119,11 @@ class GuiMain(QMainWindow): # Set Up Autosaving Project Timer self.asProjTimer = QTimer() - self.asProjTimer.setInterval(int(self.mainConf.autoSaveProj*1000)) self.asProjTimer.timeout.connect(self._autoSaveProject) - self.asProjTimer.start() # Set Up Autosaving Document Timer self.asDocTimer = QTimer() - self.asDocTimer.setInterval(int(self.mainConf.autoSaveDoc*1000)) self.asDocTimer.timeout.connect(self._autoSaveDocument) - self.asDocTimer.start() # Keyboard Shortcuts QShortcut(Qt.Key_Return, self.treeView, context=Qt.WidgetShortcut, activated=self._treeKeyPressReturn) @@ -139,6 +135,10 @@ class GuiMain(QMainWindow): if self.mainConf.showGUI: self.show() + self.initMain() + self.asProjTimer.start() + self.asDocTimer.start() + logger.debug("GUI initialisation complete") return @@ -150,6 +150,11 @@ class GuiMain(QMainWindow): self.statusBar.clearStatus() return True + def initMain(self): + self.asProjTimer.setInterval(int(self.mainConf.autoSaveProj*1000)) + self.asDocTimer.setInterval(int(self.mainConf.autoSaveDoc*1000)) + return True + ## # Project Actions ## @@ -456,8 +461,10 @@ class GuiMain(QMainWindow): return None def editConfigDialog(self): - dlgProj = GuiConfigEditor(self, self.theProject) - dlgProj.exec_() + dlgConf = GuiConfigEditor(self, self.theProject) + if dlgConf.exec_() == QDialog.Accepted: + logger.debug("Applying new preferences") + self.initMain() return True def editProjectDialog(self): diff --git a/nw/project/project.py b/nw/project/project.py index 81979f2e..d4035aa2 100644 --- a/nw/project/project.py +++ b/nw/project/project.py @@ -373,8 +373,9 @@ class NWProject(): return True def setSpellCheck(self, theMode): - self.spellCheck = theMode - self.setProjectChanged(True) + if self.spellCheck != theMode: + self.spellCheck = theMode + self.setProjectChanged(True) return True def setTreeOrder(self, newOrder): @@ -385,18 +386,21 @@ class NWProject(): return True def setLastEdited(self, tHandle): - self.lastEdited = tHandle - self.setProjectChanged(True) + if self.lastEdited != tHandle: + self.lastEdited = tHandle + self.setProjectChanged(True) return True def setLastViewed(self, tHandle): - self.lastViewed = tHandle - self.setProjectChanged(True) + if self.lastViewed != tHandle: + self.lastViewed = tHandle + self.setProjectChanged(True) return True def setProjectWordCount(self, theCount): - self.currWCount = theCount - self.setProjectChanged(True) + if self.currWCount != theCount: + self.currWCount = theCount + self.setProjectChanged(True) return True def getSessionWordCount(self): diff --git a/nw/theme.py b/nw/theme.py index 806e7b46..f0a8db3c 100644 --- a/nw/theme.py +++ b/nw/theme.py @@ -14,19 +14,30 @@ import logging import configparser import nw -from os import path +from os import path, listdir + +from nw.enum import nwAlert logger = logging.getLogger(__name__) class Theme: - def __init__(self): + def __init__(self, theParent): self.mainConf = nw.CONFIG + self.theParent = theParent self.cssName = "styles.css" self.confName = "theme.conf" + self.themeList = [] # Loaded Theme Settings + + ## Main + self.themeName = "No Name" + + ## Syntax + self.colText = [0,0,0] + self.colLink = [0,0,0] self.colHead = [0,0,0] self.colHeadH = [0,0,0] self.colEmph = [0,0,0] @@ -83,6 +94,11 @@ class Theme: logger.error("Could not load theme config file") return False + ## Main + cnfSec = "Main" + if confParser.has_section(cnfSec): + self.themeName = confParser.get(cnfSec,"name") + ## Syntax cnfSec = "Syntax" if confParser.has_section(cnfSec): @@ -103,6 +119,29 @@ class Theme: return True + def listThemes(self): + + if len(self.themeList) > 0: + return self.themeList + + confParser = configparser.ConfigParser() + for themeDir in listdir(self.mainConf.themeRoot): + themeConf = path.join(self.mainConf.themeRoot, themeDir, self.confName) + logger.verbose("Checking theme config for '%s'" % themeDir) + try: + confParser.read_file(open(themeConf)) + except Exception as e: + self.theParent.makeAlert(["Could not load theme config file",str(e)],nwAlert.ERROR) + return [] + themeName = "" + if confParser.has_section("Main"): + themeName = confParser.get("Main","name") + logger.verbose("Theme name is '%s'" % themeName) + if themeName != "": + self.themeList.append((themeDir, themeName)) + + return self.themeList + ## # Internal Functions ## diff --git a/nw/themes/default/styles.css b/nw/themes/default_dark/styles.css similarity index 87% rename from nw/themes/default/styles.css rename to nw/themes/default_dark/styles.css index ddf008ae..c81aecf3 100644 --- a/nw/themes/default/styles.css +++ b/nw/themes/default_dark/styles.css @@ -1,3 +1,7 @@ +/** + * Default Theme: Dark + */ + * { background-color: #999999; } diff --git a/nw/themes/default/theme.conf b/nw/themes/default_dark/theme.conf similarity index 92% rename from nw/themes/default/theme.conf rename to nw/themes/default_dark/theme.conf index 7f4729e8..86b04b45 100644 --- a/nw/themes/default/theme.conf +++ b/nw/themes/default_dark/theme.conf @@ -1,3 +1,6 @@ +[Main] +name = Default Dark + [Syntax] text = 199, 207, 208 link = 184, 200, 0 diff --git a/nw/themes/default_light/styles.css b/nw/themes/default_light/styles.css new file mode 100644 index 00000000..90ef623f --- /dev/null +++ b/nw/themes/default_light/styles.css @@ -0,0 +1,7 @@ +/** + * Default Theme: Light + */ + +QTreeView, QHeaderView { + font-size: 13px; +} diff --git a/nw/themes/default_light/theme.conf b/nw/themes/default_light/theme.conf new file mode 100644 index 00000000..b3d0d5be --- /dev/null +++ b/nw/themes/default_light/theme.conf @@ -0,0 +1,18 @@ +[Main] +name = Default Light + +[Syntax] +text = 0, 0, 0 +link = 0, 0, 0 +headertext = 0, 0, 0 +headertag = 0, 0, 0 +emphasis = 0, 0, 0 +straightquotes = 0, 0, 0 +doublequotes = 0, 0, 0 +singlequotes = 0, 0, 0 +hidden = 50, 50, 50 +keyword = 0, 0, 0 +value = 0, 0, 0 +spellcheckline = 0, 0, 0 +tagerror = 0, 0, 0 +replacetag = 0, 0, 0