diff --git a/nw/core/spellcheck.py b/nw/core/spellcheck.py index 8dd33bbe..e221f8b5 100644 --- a/nw/core/spellcheck.py +++ b/nw/core/spellcheck.py @@ -123,6 +123,7 @@ class NWSpellCheck(): if len(theLine) > 0 and theLine not in self.projDict: self.projDict.append(theLine) logger.debug("Project word list contains %d words" % len(self.projDict)) + except Exception: logger.error("Failed to load project word list") nw.logException() @@ -141,6 +142,7 @@ class NWSpellEnchant(NWSpellCheck): def __init__(self): NWSpellCheck.__init__(self) logger.debug("Enchant spell checking activated") + self.theBroker = None return def setLanguage(self, theLang, projectDict=None): @@ -150,9 +152,15 @@ class NWSpellEnchant(NWSpellCheck): """ try: import enchant - self.theDict = enchant.Dict(theLang) + if self.theBroker is not None: + logger.verbose("Deleting old pyenchant Broker") + del self.theBroker + + self.theBroker = enchant.Broker() + self.theDict = self.theBroker.request_dict(theLang) self.spellLanguage = theLang logger.debug("Enchant spell checking for language %s loaded" % theLang) + except Exception: logger.error("Failed to load enchant spell checking for language %s" % theLang) self.theDict = NWSpellEnchantDummy() @@ -258,9 +266,11 @@ class NWSpellSimple(NWSpellCheck): if len(theLine) == 0 or theLine.startswith("#"): continue self.WORDS.append(theLine.strip().lower()) + logger.debug("Spell check word list for language %s loaded" % theLang) logger.debug("Word list contains %d words" % len(self.WORDS)) self.spellLanguage = theLang + except Exception: logger.error("Failed to load spell check word list for language %s" % theLang) nw.logException() diff --git a/nw/gui/wordlist.py b/nw/gui/wordlist.py index fcf8682f..5ce377cc 100644 --- a/nw/gui/wordlist.py +++ b/nw/gui/wordlist.py @@ -28,11 +28,13 @@ import nw import logging import os +from PyQt5.QtCore import Qt from PyQt5.QtWidgets import ( - QDialog, QDialogButtonBox, QVBoxLayout, QListWidget, QAbstractItemView + QDialog, QDialogButtonBox, QVBoxLayout, QHBoxLayout, QListWidget, + QAbstractItemView, QPushButton, QLineEdit, QLabel ) -from nw.constants import nwFiles +from nw.constants import nwFiles, nwAlert logger = logging.getLogger(__name__) @@ -46,16 +48,18 @@ class GuiWordList(QDialog): self.mainConf = nw.CONFIG self.theParent = theParent + self.theTheme = theParent.theTheme self.theProject = theProject self.optState = theProject.optState self.setWindowTitle("Project Word List") - wW = self.mainConf.pxInt(250) - wH = self.mainConf.pxInt(300) + mS = self.mainConf.pxInt(250) + wW = self.mainConf.pxInt(320) + wH = self.mainConf.pxInt(340) - self.setMinimumWidth(wW) - self.setMinimumHeight(wH) + self.setMinimumWidth(mS) + self.setMinimumHeight(mS) self.resize( self.mainConf.pxInt(self.optState.getInt("GuiWordList", "winWidth", wW)), self.mainConf.pxInt(self.optState.getInt("GuiWordList", "winHeight", wH)) @@ -64,10 +68,27 @@ class GuiWordList(QDialog): # Main Widgets # ============ + self.headLabel = QLabel("Project Word List") + self.listBox = QListWidget() self.listBox.setDragDropMode(QAbstractItemView.NoDragDrop) self.listBox.setSortingEnabled(True) + self.newEntry = QLineEdit() + + self.addButton = QPushButton(self.theTheme.getIcon("add"), "") + self.addButton.setToolTip("Add new entry") + self.addButton.clicked.connect(self._doAdd) + + self.delButton = QPushButton(self.theTheme.getIcon("remove"), "") + self.delButton.setToolTip("Delete selected entry") + self.delButton.clicked.connect(self._doDelete) + + self.editBox = QHBoxLayout() + self.editBox.addWidget(self.newEntry, 1) + self.editBox.addWidget(self.addButton, 0) + self.editBox.addWidget(self.delButton, 0) + self.buttonBox = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Close) self.buttonBox.accepted.connect(self._doSave) self.buttonBox.rejected.connect(self._doClose) @@ -76,7 +97,11 @@ class GuiWordList(QDialog): # ======== self.outerBox = QVBoxLayout() + self.outerBox.addWidget(self.headLabel) + self.outerBox.addSpacing(self.mainConf.pxInt(8)) self.outerBox.addWidget(self.listBox, 1) + self.outerBox.addLayout(self.editBox, 0) + self.outerBox.addSpacing(self.mainConf.pxInt(12)) self.outerBox.addWidget(self.buttonBox, 0) self.setLayout(self.outerBox) @@ -91,11 +116,56 @@ class GuiWordList(QDialog): # Slots ## + def _doAdd(self): + """Add a new word to the word list. + """ + newWord = self.newEntry.text().strip() + if newWord == "": + self.theParent.makeAlert("Cannot add a blank word.", nwAlert.ERROR) + return False + + if self.listBox.findItems(newWord, Qt.MatchExactly): + self.theParent.makeAlert( + "The word '%s' is already in the word list." % newWord, nwAlert.ERROR + ) + return False + + self.listBox.addItem(newWord) + self.newEntry.setText("") + + return True + + def _doDelete(self): + """Delete the selected item. + """ + selItem = self.listBox.selectedItems() + if selItem: + self.listBox.takeItem(self.listBox.row(selItem[0])) + return + def _doSave(self): """Save the new word list and close. """ self._saveGuiSettings() + + dctFile = os.path.join(self.theProject.projMeta, nwFiles.PROJ_DICT) + tmpFile = dctFile + "~" + + try: + with open(tmpFile, mode="w", encoding="utf8") as outFile: + for i in range(self.listBox.count()): + outFile.write(self.listBox.item(i).text() + "\n") + + except Exception as e: + logger.error("Could not save new word list") + logger.error(str(e)) + self.reject() + + if os.path.isfile(dctFile): + os.unlink(dctFile) + os.rename(tmpFile, dctFile) self.accept() + return def _doClose(self): diff --git a/nw/guimain.py b/nw/guimain.py index 268862b3..6cb68cb3 100644 --- a/nw/guimain.py +++ b/nw/guimain.py @@ -1029,7 +1029,7 @@ class GuiMain(QMainWindow): if dlgWords.result() == QDialog.Accepted: logger.debug("Reloading word list") - # ToDo + self.docEditor.setDictionaries() return