Merge pull request #3 from vkbo/spellcheck_updates

Spellcheck updates
This commit is contained in:
Veronica K. Berglyd Olsen
2019-05-12 16:20:46 +02:00
committed by GitHub
9 changed files with 195 additions and 72 deletions
+52
View File
@@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
"""novelWriter Common Functions
novelWriter Common Functions
================================
Various functions used multiple places
File History:
Created: 2019-05-12 [0.1.0]
"""
import logging
import nw
logger = logging.getLogger(__name__)
def checkString(checkValue, defaultValue, allowNone=False):
if allowNone:
if checkValue == None: return None
if checkValue == "None": return None
if isinstance(checkValue,str): return str(checkValue)
return defaultValue
def checkInt(checkValue, defaultValue, allowNone=False):
if allowNone:
if checkValue == None: return None
if checkValue == "None": return None
try:
return int(checkValue)
except:
return defaultValue
def checkBool(checkValue, defaultValue, allowNone=False):
if allowNone:
if checkValue == None: return None
if checkValue == "None": return None
if isinstance(checkValue, str):
if checkValue == "True":
return True
elif checkValue == "False":
return False
else:
return defaultValue
elif isinstance(checkValue, int):
if checkValue == 1:
return True
elif checkValue == 0:
return False
else:
return defaultValue
return defaultValue
+23 -3
View File
@@ -38,6 +38,7 @@ class GuiDocEditor(QTextEdit):
self.theParent = theParent self.theParent = theParent
self.docChanged = False self.docChanged = False
self.pwlFile = None self.pwlFile = None
self.spellCheck = False
# Document Variables # Document Variables
self.charCount = 0 self.charCount = 0
@@ -105,7 +106,7 @@ class GuiDocEditor(QTextEdit):
def setDocumentChanged(self, bValue): def setDocumentChanged(self, bValue):
self.docChanged = bValue self.docChanged = bValue
self.theParent.statusBar.setDocumentStatus(self.docChanged) self.theParent.statusBar.setDocumentStatus(self.docChanged)
return return self.docChanged
def setText(self, theText): def setText(self, theText):
self.setPlainText(theText) self.setPlainText(theText)
@@ -120,7 +121,18 @@ class GuiDocEditor(QTextEdit):
self.pwlFile = pwlFile self.pwlFile = pwlFile
self.theDict = enchant.DictWithPWL(self.mainConf.spellLanguage,pwlFile) self.theDict = enchant.DictWithPWL(self.mainConf.spellLanguage,pwlFile)
self.hLight.setDict(self.theDict) self.hLight.setDict(self.theDict)
return return True
def setSpellCheck(self, theMode):
self.spellCheck = theMode
self.hLight.setSpellCheck(theMode)
self.rehighlightDocument()
return True
def updateSpellCheck(self):
if self.spellCheck:
self.rehighlightDocument()
return True
def getText(self): def getText(self):
theText = self.toPlainText() theText = self.toPlainText()
@@ -154,6 +166,11 @@ class GuiDocEditor(QTextEdit):
elif theAction == nwDocAction.SEL_PARA: self._makeSelection(QTextCursor.BlockUnderCursor) elif theAction == nwDocAction.SEL_PARA: self._makeSelection(QTextCursor.BlockUnderCursor)
else: else:
logger.error("Unknown or unsupported document action %s" % str(theAction)) logger.error("Unknown or unsupported document action %s" % str(theAction))
return False
return True
def rehighlightDocument(self):
self.hLight.rehighlight()
return return
## ##
@@ -181,6 +198,9 @@ class GuiDocEditor(QTextEdit):
def _openContextMenu(self, thePos): def _openContextMenu(self, thePos):
if not self.spellCheck:
return
theCursor = self.cursorForPosition(thePos) theCursor = self.cursorForPosition(thePos)
theCursor.select(QTextCursor.WordUnderCursor) theCursor.select(QTextCursor.WordUnderCursor)
theWord = theCursor.selectedText() theWord = theCursor.selectedText()
@@ -237,7 +257,7 @@ class GuiDocEditor(QTextEdit):
self.wcTimer.start() self.wcTimer.start()
if self.mainConf.doReplace and not self.hasSelection: if self.mainConf.doReplace and not self.hasSelection:
self._docAutoReplace(self.theDoc.findBlock(thePos)) self._docAutoReplace(self.theDoc.findBlock(thePos))
# logger.verbose("Doc change signal took %.3f µs" % ((time()-self.lastEdit)*1e6)) logger.verbose("Doc change signal took %.3f µs" % ((time()-self.lastEdit)*1e6))
return return
def _docAutoReplace(self, theBlock): def _docAutoReplace(self, theBlock):
+21 -16
View File
@@ -24,22 +24,23 @@ class GuiDocHighlighter(QSyntaxHighlighter):
QSyntaxHighlighter.__init__(self, theDoc) QSyntaxHighlighter.__init__(self, theDoc)
logger.debug("Initialising DocHighlighter ...") logger.debug("Initialising DocHighlighter ...")
self.mainConf = nw.CONFIG self.mainConf = nw.CONFIG
self.theDoc = theDoc self.theDoc = theDoc
self.theDict = None self.theDict = None
self.hRules = [] self.spellCheck = False
self.hRules = []
self.colHead = QColor( 0,155,200) self.colHead = QColor( 0,155,200)
self.colHeadH = QColor( 0,105,135) self.colHeadH = QColor( 0,105,135)
self.colEmph = QColor(200,120, 0) self.colEmph = QColor(200,120, 0)
self.colDialN = QColor(200, 46, 0) self.colDialN = QColor(200, 46, 0)
self.colDialD = QColor(184,200, 0) self.colDialD = QColor(184,200, 0)
self.colDialS = QColor(136,200, 0) self.colDialS = QColor(136,200, 0)
self.colComm = QColor(150,150,150) self.colComm = QColor(150,150,150)
self.colKey = QColor(200, 46, 0) self.colKey = QColor(200, 46, 0)
self.colVal = QColor(184,200, 0) self.colVal = QColor(184,200, 0)
self.colSpell = QColor(200, 46, 0) self.colSpell = QColor(200, 46, 0)
self.hStyles = { self.hStyles = {
"header1" : self._makeFormat(self.colHead, "bold",1.8), "header1" : self._makeFormat(self.colHead, "bold",1.8),
@@ -153,7 +154,11 @@ class GuiDocHighlighter(QSyntaxHighlighter):
def setDict(self, theDict): def setDict(self, theDict):
self.theDict = theDict self.theDict = theDict
return return True
def setSpellCheck(self, theMode):
self.spellCheck = theMode
return True
def _makeFormat(self, fmtCol=None, fmtStyle=None, fmtSize=None): def _makeFormat(self, fmtCol=None, fmtStyle=None, fmtSize=None):
theFormat = QTextCharFormat() theFormat = QTextCharFormat()
@@ -189,7 +194,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
self.setCurrentBlockState(0) self.setCurrentBlockState(0)
if self.theDict is None: if self.theDict is None or not self.spellCheck:
return return
rxSpell = self.spellRx.globalMatch(theText.replace("_"," "), 0) rxSpell = self.spellRx.globalMatch(theText.replace("_"," "), 0)
+38 -2
View File
@@ -61,6 +61,15 @@ class GuiMainMenu(QMenuBar):
) )
return return
##
# Update Menu on Settings Changed
##
def updateMenu(self):
self.updateRecentProjects()
self.updateSpellCheck()
return
def updateRecentProjects(self): def updateRecentProjects(self):
self.recentMenu.clear() self.recentMenu.clear()
for n in range(len(self.mainConf.recentList)): for n in range(len(self.mainConf.recentList)):
@@ -71,6 +80,11 @@ class GuiMainMenu(QMenuBar):
self.recentMenu.addAction(menuItem) self.recentMenu.addAction(menuItem)
return return
def updateSpellCheck(self):
self.toolsSpellCheck.setChecked(self.theProject.spellCheck)
logger.verbose("Spell check is set to %s" % str(self.theProject.spellCheck))
return
## ##
# Menu Action # Menu Action
## ##
@@ -80,6 +94,12 @@ class GuiMainMenu(QMenuBar):
qApp.quit() qApp.quit()
return True return True
def _toggleSpellCheck(self):
self.theProject.setSpellCheck(self.toolsSpellCheck.isChecked())
self.theParent.docEditor.setSpellCheck(self.toolsSpellCheck.isChecked())
logger.verbose("Spell check is set to %s" % str(self.theProject.spellCheck))
return
def _showAbout(self): def _showAbout(self):
msgBox = QMessageBox() msgBox = QMessageBox()
msgBox.about(self.theParent, "About %s" % nw.__package__, ( msgBox.about(self.theParent, "About %s" % nw.__package__, (
@@ -407,8 +427,24 @@ class GuiMainMenu(QMenuBar):
self.toolsMoveDown.triggered.connect(lambda : self._moveTreeItem(1)) self.toolsMoveDown.triggered.connect(lambda : self._moveTreeItem(1))
self.toolsMenu.addAction(self.toolsMoveDown) self.toolsMenu.addAction(self.toolsMoveDown)
# # Tools > Separator # Tools > Separator
# self.toolsMenu.addSeparator() self.toolsMenu.addSeparator()
# Tools > Toggle Spell Check
self.toolsSpellCheck = QAction("Check Spelling", self)
self.toolsSpellCheck.setStatusTip("Toggle Check Spelling")
self.toolsSpellCheck.setCheckable(True)
self.toolsSpellCheck.setChecked(self.theProject.spellCheck)
self.toolsSpellCheck.toggled.connect(self._toggleSpellCheck)
self.toolsSpellCheck.setShortcut("Ctrl+F7")
self.toolsMenu.addAction(self.toolsSpellCheck)
# Tools > Update Spell Check
menuItem = QAction(QIcon.fromTheme("tools-check-spelling"), "Re-Run Spell Check", self)
menuItem.setStatusTip("Rus the Spell Checker on Current Document")
menuItem.setShortcut("F7")
menuItem.triggered.connect(self.theParent.docEditor.updateSpellCheck)
self.toolsMenu.addAction(menuItem)
# # Tools > Settings # # Tools > Settings
# menuItem = QAction(QIcon.fromTheme("preferences-system"), "Preferences", self) # menuItem = QAction(QIcon.fromTheme("preferences-system"), "Preferences", self)
+2 -1
View File
@@ -172,10 +172,11 @@ class GuiMain(QMainWindow):
self.treeView.clearTree() self.treeView.clearTree()
self.theProject.openProject(projFile) self.theProject.openProject(projFile)
self.treeView.buildTree() self.treeView.buildTree()
self.mainMenu.updateRecentProjects()
self._setWindowTitle(self.theProject.projName) self._setWindowTitle(self.theProject.projName)
self._makeStatusIcons() self._makeStatusIcons()
self.docEditor.setPwl(path.join(self.theProject.projMeta,"wordlist.txt")) self.docEditor.setPwl(path.join(self.theProject.projMeta,"wordlist.txt"))
self.docEditor.setSpellCheck(self.theProject.spellCheck)
self.mainMenu.updateMenu()
return True return True
def saveProject(self): def saveProject(self):
+9 -21
View File
@@ -13,11 +13,12 @@
import logging import logging
import nw import nw
from os import path, mkdir from os import path, mkdir
from lxml import etree from lxml import etree
from datetime import datetime from datetime import datetime
from nw.enum import nwItemType, nwItemClass, nwItemLayout from nw.enum import nwItemType, nwItemClass, nwItemLayout
from nw.common import checkInt
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -153,7 +154,7 @@ class NWItem():
return return
def setStatus(self, theStatus): def setStatus(self, theStatus):
theStatus = self._checkInt(theStatus,0) theStatus = checkInt(theStatus,0)
self.itemStatus = theStatus self.itemStatus = theStatus
return return
@@ -169,31 +170,18 @@ class NWItem():
## ##
def setCharCount(self, theCount): def setCharCount(self, theCount):
theCount = self._checkInt(theCount,0) theCount = checkInt(theCount,0)
self.charCount = theCount self.charCount = theCount
return return
def setWordCount(self, theCount): def setWordCount(self, theCount):
theCount = self._checkInt(theCount,0) theCount = checkInt(theCount,0)
self.wordCount = theCount self.wordCount = theCount
return return
def setParaCount(self, theCount): def setParaCount(self, theCount):
theCount = self._checkInt(theCount,0) theCount = checkInt(theCount,0)
self.paraCount = theCount self.paraCount = theCount
return return
##
# Internal Functions
##
def _checkInt(self,checkValue,defaultValue,allowNone=False):
if allowNone:
if checkValue == None: return None
if checkValue == "None": return None
try:
return int(checkValue)
except:
return defaultValue
# END Class NWItem # END Class NWItem
+44 -29
View File
@@ -20,6 +20,7 @@ from datetime import datetime
from time import time from time import time
from nw.enum import nwItemType, nwItemClass, nwItemLayout from nw.enum import nwItemType, nwItemClass, nwItemLayout
from nw.common import checkString, checkBool
from nw.project.item import NWItem from nw.project.item import NWItem
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -36,7 +37,7 @@ class NWProject():
# Debug # Debug
self.handleSeed = None self.handleSeed = None
# Project Settings # Class Settings
self.projTree = None self.projTree = None
self.treeOrder = None self.treeOrder = None
self.treeRoots = None self.treeRoots = None
@@ -45,11 +46,17 @@ class NWProject():
self.projMeta = None self.projMeta = None
self.projCache = None self.projCache = None
self.projFile = None self.projFile = None
self.statusCols = None
# Project Meta
self.projName = None self.projName = None
self.bookTitle = None self.bookTitle = None
self.bookAuthors = None self.bookAuthors = None
self.statusCols = None
# Project Settings
self.spellCheck = False
# Set Defaults
self.clearProject() self.clearProject()
return return
@@ -130,6 +137,7 @@ class NWProject():
self.projName = "" self.projName = ""
self.bookTitle = "" self.bookTitle = ""
self.bookAuthors = [] self.bookAuthors = []
self.spellCheck = False
self.statusCols = [ self.statusCols = [
("New", 100,100,100), ("New", 100,100,100),
("Note", 200, 50, 0), ("Note", 200, 50, 0),
@@ -185,6 +193,12 @@ class NWProject():
elif xItem.tag == "author": elif xItem.tag == "author":
logger.verbose("Author: '%s'" % xItem.text) logger.verbose("Author: '%s'" % xItem.text)
self.bookAuthors.append(xItem.text) self.bookAuthors.append(xItem.text)
elif xChild.tag == "settings":
logger.debug("Found project settings")
for xItem in xChild:
if xItem.text is None: continue
if xItem.tag == "spellCheck":
self.spellCheck = checkBool(xItem.text,False)
elif xChild.tag == "content": elif xChild.tag == "content":
logger.debug("Found project content") logger.debug("Found project content")
for xItem in xChild: for xItem in xChild:
@@ -233,15 +247,16 @@ class NWProject():
"appVersion" : str(nw.__version__), "appVersion" : str(nw.__version__),
"timeStamp" : datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "timeStamp" : datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
}) })
xProject = etree.SubElement(nwXML,"project")
xProjName = etree.SubElement(xProject,"name") # Save Project Meta
xProjName.text = self.projName xProject = etree.SubElement(nwXML,"project")
xBookTitle = etree.SubElement(xProject,"title") self._saveProjectValue(xProject,"name", self.projName, True)
xBookTitle.text = self.bookTitle self._saveProjectValue(xProject,"title", self.bookTitle, True)
for bookAuthor in self.bookAuthors: self._saveProjectValue(xProject,"author",self.bookAuthors)
if bookAuthor == "": continue
xBookAuthor = etree.SubElement(xProject,"author") # Save Project Settings
xBookAuthor.text = bookAuthor xSettings = etree.SubElement(nwXML,"settings")
self._saveProjectValue(xSettings,"spellCheck",self.spellCheck)
# Save Tree Content # Save Tree Content
logger.debug("Writing project content") logger.debug("Writing project content")
@@ -298,6 +313,11 @@ class NWProject():
self.setProjectChanged(True) self.setProjectChanged(True)
return True return True
def setSpellCheck(self, theMode):
self.spellCheck = theMode
self.setProjectChanged(True)
return True
def setTreeOrder(self, newOrder): def setTreeOrder(self, newOrder):
if len(self.treeOrder) != len(newOrder): if len(self.treeOrder) != len(newOrder):
logger.warning("Size of new and old tree order does not match") logger.warning("Size of new and old tree order does not match")
@@ -351,6 +371,17 @@ class NWProject():
return False return False
return True return True
def _saveProjectValue(self, xParent, theName, theValue, allowNone=True):
if not isinstance(theValue, list):
theValue = [theValue]
for aValue in theValue:
if not isinstance(aValue, str):
aValue = str(aValue)
if aValue == "" and not allowNone: continue
xItem = etree.SubElement(xParent,theName)
xItem.text = aValue
return
def _scanProjectFolder(self): def _scanProjectFolder(self):
if self.projPath is None: if self.projPath is None:
@@ -402,8 +433,8 @@ class NWProject():
return return
def _appendItem(self, tHandle, pHandle, nwItem): def _appendItem(self, tHandle, pHandle, nwItem):
tHandle = self._checkString(tHandle,self._makeHandle(),False) tHandle = checkString(tHandle,self._makeHandle(),False)
pHandle = self._checkString(pHandle,None,True) pHandle = checkString(pHandle,None,True)
logger.verbose("Adding entry %s with parent %s" % (str(tHandle),str(pHandle))) logger.verbose("Adding entry %s with parent %s" % (str(tHandle),str(pHandle)))
nwItem.setHandle(tHandle) nwItem.setHandle(tHandle)
@@ -441,20 +472,4 @@ class NWProject():
itemHandle = self._makeHandle(addSeed+"!") itemHandle = self._makeHandle(addSeed+"!")
return itemHandle return itemHandle
def _checkString(self,checkValue,defaultValue,allowNone=False):
if allowNone:
if checkValue == None: return None
if checkValue == "None": return None
if isinstance(checkValue,str): return str(checkValue)
return defaultValue
def _checkInt(self,checkValue,defaultValue,allowNone=False):
if allowNone:
if checkValue == None: return None
if checkValue == "None": return None
try:
return int(checkValue)
except:
return defaultValue
# END Class NWProject # END Class NWProject
+3
View File
@@ -4,6 +4,9 @@
<name></name> <name></name>
<title></title> <title></title>
</project> </project>
<settings>
<spellCheck>False</spellCheck>
</settings>
<content count="6"> <content count="6">
<item handle="73475cb40a568" order="None" parent="None"> <item handle="73475cb40a568" order="None" parent="None">
<name>Novel</name> <name>Novel</name>
+3
View File
@@ -4,6 +4,9 @@
<name></name> <name></name>
<title></title> <title></title>
</project> </project>
<settings>
<spellCheck>False</spellCheck>
</settings>
<content count="10"> <content count="10">
<item handle="73475cb40a568" order="None" parent="None"> <item handle="73475cb40a568" order="None" parent="None">
<name>Novel</name> <name>Novel</name>