diff --git a/nw/config.py b/nw/config.py index 5acf8774..fbb384ab 100644 --- a/nw/config.py +++ b/nw/config.py @@ -288,7 +288,8 @@ class Config: return True def loadConfig(self): - + """Load preferences from file and replace default settings. + """ logger.debug("Loading config file") cnfParse = configparser.ConfigParser() try: @@ -453,7 +454,8 @@ class Config: return True def saveConfig(self): - + """Save the current preferences to file. + """ logger.debug("Saving config file") cnfParse = configparser.ConfigParser() @@ -546,7 +548,6 @@ class Config: def loadRecentCache(self): """Load the cache file for recent projects. """ - if self.dataPath is None: return False @@ -587,7 +588,6 @@ class Config: def saveRecentCache(self): """Save the cache dictionary of recent projects. """ - if self.dataPath is None: return False @@ -619,6 +619,18 @@ class Config: } 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.verbose("Removed recent: %s" % thePath) + self.saveRecentCache() + else: + logger.error("Unknown recent: %s" % thePath) + return False + return True + ## # Setters and Getters ## @@ -737,7 +749,6 @@ class Config: def _checkOptionalPackages(self): """Cheks if we have the optional packages used by some features. """ - try: import enchant self.hasEnchant = True diff --git a/nw/gui/dialogs/projectload.py b/nw/gui/dialogs/projectload.py index 17950b37..3b64848b 100644 --- a/nw/gui/dialogs/projectload.py +++ b/nw/gui/dialogs/projectload.py @@ -28,24 +28,27 @@ import logging import nw +from os import path from datetime import datetime from PyQt5.QtCore import Qt +from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import ( QDialog, QHBoxLayout, QVBoxLayout, QGridLayout, QPushButton, QTreeWidget, - QAbstractItemView, QTreeWidgetItem, QDialogButtonBox, QLabel + QAbstractItemView, QTreeWidgetItem, QDialogButtonBox, QLabel, QShortcut, + QFileDialog, QLineEdit ) from nw.common import formatInt +from nw.constants import nwFiles logger = logging.getLogger(__name__) class GuiProjectLoad(QDialog): - NONE_STATE = 0 - BROWSE_STATE = 1 - NEW_STATE = 2 - OPEN_STATE = 3 + NONE_STATE = 0 + NEW_STATE = 1 + OPEN_STATE = 2 def __init__(self, theParent): QDialog.__init__(self, theParent) @@ -87,16 +90,23 @@ class GuiProjectLoad(QDialog): treeHead.setTextAlignment(1, Qt.AlignRight) treeHead.setTextAlignment(2, Qt.AlignRight) - self.lblRecent = QLabel("Recently Opened:") - self.lblPath = QLabel("Path:") - self.selPath = QLabel("") - self.selPath.setWordWrap(True) + self.lblRecent = QLabel("Recently Opened Projects") + self.lblPath = QLabel("Path") + self.selPath = QLineEdit("") + self.selPath.setEnabled(False) - self.projectForm.addWidget(self.lblRecent, 0, 0, 1, 2) - self.projectForm.addWidget(self.listBox, 1, 0, 1, 2) - self.projectForm.addWidget(self.lblPath, 2, 0, 1, 1, Qt.AlignTop) - self.projectForm.addWidget(self.selPath, 2, 1, 1, 1, Qt.AlignTop) + self.browseButton = QPushButton("...") + self.browseButton.setMaximumWidth(30) + self.browseButton.clicked.connect(self._doBrowse) + + self.projectForm.addWidget(self.lblRecent, 0, 0, 1, 3) + self.projectForm.addWidget(self.listBox, 1, 0, 1, 3) + self.projectForm.addWidget(self.lblPath, 2, 0, 1, 1) + self.projectForm.addWidget(self.selPath, 2, 1, 1, 1) + self.projectForm.addWidget(self.browseButton, 2, 2, 1, 1) + self.projectForm.setColumnStretch(0, 0) self.projectForm.setColumnStretch(1, 1) + self.projectForm.setColumnStretch(2, 0) self.projectForm.setVerticalSpacing(4) self.projectForm.setHorizontalSpacing(8) @@ -109,9 +119,6 @@ class GuiProjectLoad(QDialog): self.newButton = self.buttonBox.addButton("New", QDialogButtonBox.ActionRole) self.newButton.clicked.connect(self._doNewProject) - self.browseButton = self.buttonBox.addButton("Browse", QDialogButtonBox.ActionRole) - self.browseButton.clicked.connect(self._doBrowse) - self.outerBox.addLayout(self.innerBox) self.outerBox.addWidget(self.buttonBox) self.setLayout(self.outerBox) @@ -119,6 +126,10 @@ class GuiProjectLoad(QDialog): self._populateList() self._doSelectRecent() + keyDelete = QShortcut(self.listBox) + keyDelete.setKey(QKeySequence(Qt.Key_Delete)) + keyDelete.activated.connect(self._keyPressDelete) + logger.debug("GuiProjectLoad initialisation complete") return @@ -155,10 +166,20 @@ class GuiProjectLoad(QDialog): project browser dialog. """ logger.verbose("GuiProjectLoad browse button clicked") - self._saveDialogState() - self.openPath = None - self.openState = self.BROWSE_STATE - self.accept() + if self.mainConf.showGUI: + dlgOpt = QFileDialog.Options() + dlgOpt |= QFileDialog.DontUseNativeDialog + projFile, _ = QFileDialog.getOpenFileName( + self, "Open novelWriter Project", "", + "novelWriter Project File (%s);;All Files (*)" % nwFiles.PROJ_FILE, + options=dlgOpt + ) + if projFile: + thePath = path.abspath(path.dirname(projFile)) + self.selPath.setText(thePath) + self.openPath = thePath + self.openState = self.OPEN_STATE + self.accept() return def _doClose(self): @@ -179,6 +200,15 @@ class GuiProjectLoad(QDialog): self.accept() return + def _keyPressDelete(self): + """Remove an entry from the recent projects list. + """ + selList = self.listBox.selectedItems() + if selList: + self.mainConf.removeFromRecentCache(selList[0].text(3)) + self._populateList() + return + ## # Internal Functions ## diff --git a/nw/guimain.py b/nw/guimain.py index b15edbe9..9c4d5d3a 100644 --- a/nw/guimain.py +++ b/nw/guimain.py @@ -264,8 +264,6 @@ class GuiMain(QMainWindow): if dlgProj.result() == QDialog.Accepted: if dlgProj.openState == GuiProjectLoad.OPEN_STATE: self.openProject(dlgProj.openPath) - elif dlgProj.openState == GuiProjectLoad.BROWSE_STATE: - self.openProject(dlgProj.openPath) elif dlgProj.openState == GuiProjectLoad.NEW_STATE: self.newProject() @@ -274,7 +272,6 @@ class GuiMain(QMainWindow): def newProject(self, projPath=None, forceNew=False): """Create new project with a few default files and folders. """ - if self.hasProject: msgBox = QMessageBox() msgRes = msgBox.warning( @@ -354,13 +351,11 @@ class GuiMain(QMainWindow): return saveOK - def openProject(self, projFile=None): + def openProject(self, projFile): """Open a project. The parameter projFile is passed from the - open recent projects menu, so it can be set. If not, we pop the - dialog. + open recent projects menu, and must be set to be forwarded to + the project class. Otherwise, we just return. """ - if projFile is None: - projFile = self.openProjectDialog() if projFile is None: return False @@ -484,6 +479,8 @@ class GuiMain(QMainWindow): return True def saveDocument(self): + """Save the current documents. + """ if self.hasProject: self.docEditor.saveText() return True @@ -491,7 +488,6 @@ class GuiMain(QMainWindow): def viewDocument(self, tHandle=None): """Load a document for viewing in the view panel. """ - if tHandle is None: tHandle = self.treeView.getSelectedHandle() if tHandle is None: @@ -521,7 +517,6 @@ class GuiMain(QMainWindow): """Import the text contained in an out-of-project text file, and insert the text into the currently open document. """ - lastPath = self.mainConf.lastPath extFilter = [ @@ -610,6 +605,8 @@ class GuiMain(QMainWindow): ## def openSelectedItem(self): + """Open the selected documents. + """ tHandle = self.treeView.getSelectedHandle() if tHandle is None: logger.warning("No item selected") @@ -626,6 +623,8 @@ class GuiMain(QMainWindow): return True def editItem(self): + """Open the edit item dialog. + """ tHandle = self.treeView.getSelectedHandle() if tHandle is None: logger.warning("No item selected") @@ -654,7 +653,6 @@ class GuiMain(QMainWindow): def rebuildIndex(self): """Rebuild the entire index. """ - if not self.hasProject: return False @@ -708,19 +706,9 @@ class GuiMain(QMainWindow): # Main Dialogs ## - def openProjectDialog(self): - dlgOpt = QFileDialog.Options() - dlgOpt |= QFileDialog.DontUseNativeDialog - projFile, _ = QFileDialog.getOpenFileName( - self, "Open novelWriter Project", "", - "novelWriter Project File (%s);;All Files (*)" % nwFiles.PROJ_FILE, - options=dlgOpt - ) - if projFile: - return projFile - return None - def saveProjectDialog(self): + """Select where to save project. + """ dlgOpt = QFileDialog.Options() dlgOpt |= QFileDialog.ShowDirsOnly dlgOpt |= QFileDialog.DontUseNativeDialog @@ -732,6 +720,8 @@ class GuiMain(QMainWindow): return None def newProjectDialog(self): + """Select where to save new project. + """ dlgOpt = QFileDialog.Options() dlgOpt |= QFileDialog.ShowDirsOnly dlgOpt |= QFileDialog.DontUseNativeDialog @@ -743,6 +733,8 @@ class GuiMain(QMainWindow): return None def editConfigDialog(self): + """Open the preferences dialog. + """ dlgConf = GuiConfigEditor(self, self.theProject) if dlgConf.exec_() == QDialog.Accepted: logger.debug("Applying new preferences") @@ -754,6 +746,8 @@ class GuiMain(QMainWindow): return True def editProjectDialog(self): + """Open the project settings dialog. + """ if self.hasProject: dlgProj = GuiProjectEditor(self, self.theProject) dlgProj.exec_() @@ -761,12 +755,16 @@ class GuiMain(QMainWindow): return True def buildProjectDialog(self): + """Open the build project dialog. + """ if self.hasProject: dlgExport = GuiBuildNovel(self, self.theProject) dlgExport.exec_() return True def showSessionLogDialog(self): + """Open the session log dialog. + """ if self.hasProject: dlgTLine = GuiSessionLogView(self, self.theProject) dlgTLine.exec_() @@ -777,7 +775,6 @@ class GuiMain(QMainWindow): can be either a string or an array of strings. Severity level is 0 = info, 1 = warning, and 2 = error. """ - if isinstance(theMessage, list): popMsg = " ".join(theMessage) logMsg = theMessage @@ -821,7 +818,8 @@ class GuiMain(QMainWindow): ## def closeMain(self): - + """Save everything, and close novelWriter. + """ if self.mainConf.showGUI and self.hasProject: msgBox = QMessageBox() msgRes = msgBox.question( @@ -874,7 +872,6 @@ class GuiMain(QMainWindow): """Main GUI Zen Mode hides tree, view pane and optionally also statusbar and menu. """ - if self.docEditor.theHandle is None: logger.error("No document open, so not activating Zen Mode") return False @@ -906,7 +903,6 @@ class GuiMain(QMainWindow): if the user uses the system window manager. Currently, Qt doesn't have access to the exact state of the window. """ - self.setWindowState(self.windowState() ^ Qt.WindowFullScreen) winState = self.windowState() & Qt.WindowFullScreen == Qt.WindowFullScreen