Fixed merge conflicts

This commit is contained in:
Veronica K. B. Olsen
2019-05-12 14:10:41 +02:00
4 changed files with 108 additions and 66 deletions
+70 -53
View File
@@ -16,9 +16,9 @@ import enchant
from time import time from time import time
from PyQt5.QtWidgets import QTextEdit, QAction, QMenu from PyQt5.QtWidgets import QTextEdit, QAction, QMenu, QShortcut
from PyQt5.QtCore import Qt, QTimer, QEvent, pyqtSignal from PyQt5.QtGui import QTextCursor, QTextOption, QIcon, QKeySequence
from PyQt5.QtGui import QTextCursor, QTextOption, QMouseEvent from PyQt5.QtCore import Qt, QTimer
from nw.gui.dochighlight import GuiDocHighlighter from nw.gui.dochighlight import GuiDocHighlighter
from nw.gui.wordcounter import WordCounter from nw.gui.wordcounter import WordCounter
@@ -37,6 +37,7 @@ class GuiDocEditor(QTextEdit):
self.mainConf = nw.CONFIG self.mainConf = nw.CONFIG
self.theParent = theParent self.theParent = theParent
self.docChanged = False self.docChanged = False
self.pwlFile = None
# Document Variables # Document Variables
self.charCount = 0 self.charCount = 0
@@ -54,7 +55,12 @@ class GuiDocEditor(QTextEdit):
# Core Elements # Core Elements
self.theDoc = self.document() self.theDoc = self.document()
self.theDict = enchant.Dict(self.mainConf.spellLanguage) self.theDict = enchant.Dict(self.mainConf.spellLanguage)
self.hLight = GuiDocHighlighter(self.theDoc, self.theDict) self.hLight = GuiDocHighlighter(self.theDoc)
self.hLight.setDict(self.theDict)
# Context Menu
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self._openContextMenu)
# Editor State # Editor State
self.hasSelection = False self.hasSelection = False
@@ -76,6 +82,9 @@ class GuiDocEditor(QTextEdit):
self.setAcceptRichText(False) self.setAcceptRichText(False)
self.setFontPointSize(self.mainConf.textSize) self.setFontPointSize(self.mainConf.textSize)
# Custom Shortcuts
QShortcut(QKeySequence("Ctrl+."), self, context=Qt.WidgetShortcut, activated=self._openSpellContext)
# Set Up Word Count Thread and Timer # Set Up Word Count Thread and Timer
self.wcInterval = self.mainConf.wordCountTimer self.wcInterval = self.mainConf.wordCountTimer
self.wcTimer = QTimer() self.wcTimer = QTimer()
@@ -106,6 +115,13 @@ class GuiDocEditor(QTextEdit):
self.setDocumentChanged(False) self.setDocumentChanged(False)
return True return True
def setPwl(self, pwlFile):
if pwlFile is not None:
self.pwlFile = pwlFile
self.theDict = enchant.DictWithPWL(self.mainConf.spellLanguage,pwlFile)
self.hLight.setDict(self.theDict)
return
def getText(self): def getText(self):
theText = self.toPlainText() theText = self.toPlainText()
return theText return theText
@@ -155,54 +171,63 @@ class GuiDocEditor(QTextEdit):
QTextEdit.keyPressEvent(self, keyEvent) QTextEdit.keyPressEvent(self, keyEvent)
return return
def mousePressEvent(self, theEvent):
"""Capture right click events and rewrite them to left button event. This moves the cursor
to the location of the pointer. Needed to select the word under the right click.
Adapted from: https://nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check
"""
if theEvent.button() == Qt.RightButton:
theEvent = QMouseEvent(
QEvent.MouseButtonPress, theEvent.pos(), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier
)
QTextEdit.mousePressEvent(self, theEvent)
return
def contextMenuEvent(self, theEvent):
"""Intercept the context menu and insert spelling suggestions, if any.
Uses the custom QAction class SpellAction from the same example code.
Adapted from: https://nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check
"""
mnuSpell = self.createStandardContextMenu()
theCursor = self.textCursor()
theCursor.select(QTextCursor.WordUnderCursor)
self.setTextCursor(theCursor)
if self.textCursor().hasSelection():
theText = self.textCursor().selectedText()
if not self.theDict.check(theText):
mnuSuggest = QMenu("Spelling Suggestions")
for aWord in self.theDict.suggest(theText):
action = SpellAction(aWord, mnuSuggest)
action.correct.connect(self._correctWord)
mnuSuggest.addAction(action)
if len(mnuSuggest.actions()) > 0:
theActions = mnuSpell.actions()
mnuSpell.insertSeparator(theActions[0])
mnuSpell.insertMenu(theActions[0], mnuSuggest)
mnuSpell.exec_(theEvent.globalPos())
return
## ##
# Internal Functions # Internal Functions
## ##
def _correctWord(self, word): def _openSpellContext(self):
theCursor = self.textCursor() self._openContextMenu(self.cursorRect().center())
return
def _openContextMenu(self, thePos):
theCursor = self.cursorForPosition(thePos)
theCursor.select(QTextCursor.WordUnderCursor)
theWord = theCursor.selectedText()
if theWord == "":
return
if self.theDict.check(theWord):
return
mnuSuggest = QMenu()
spIcon = QIcon.fromTheme("tools-check-spelling")
mnuHead = QAction(spIcon,"Spelling Suggestion", mnuSuggest)
mnuSuggest.addAction(mnuHead)
mnuSuggest.addSeparator()
theSuggest = self.theDict.suggest(theWord)
if len(theSuggest) > 0:
for aWord in theSuggest:
mnuWord = QAction(aWord, mnuSuggest)
mnuWord.triggered.connect(lambda thePos, aWord=aWord : self._correctWord(theCursor, aWord))
mnuSuggest.addAction(mnuWord)
mnuSuggest.addSeparator()
mnuAdd = QAction("Add Word to Dictionary", mnuSuggest)
mnuAdd.triggered.connect(lambda thePos : self._addWord(theCursor))
mnuSuggest.addAction(mnuAdd)
else:
mnuHead = QAction("No Suggestions", mnuSuggest)
mnuSuggest.addAction(mnuHead)
mnuSuggest.exec_(self.viewport().mapToGlobal(thePos))
return
def _correctWord(self, theCursor, theWord):
xPos = theCursor.selectionStart()
theCursor.beginEditBlock() theCursor.beginEditBlock()
theCursor.removeSelectedText() theCursor.removeSelectedText()
theCursor.insertText(word) theCursor.insertText(theWord)
theCursor.endEditBlock() theCursor.endEditBlock()
theCursor.setPosition(xPos)
self.setTextCursor(theCursor)
return
def _addWord(self, theCursor):
theWord = theCursor.selectedText().strip()
logger.info("Added '%s' to project dictionary" % theWord)
self.theDict.add_to_pwl(theWord)
self.hLight.setDict(self.theDict)
self.hLight.rehighlightBlock(theCursor.block())
return return
def _docChange(self, thePos, charsRemoved, charsAdded): def _docChange(self, thePos, charsRemoved, charsAdded):
@@ -328,11 +353,3 @@ class GuiDocEditor(QTextEdit):
return return
# END Class GuiDocEditor # END Class GuiDocEditor
class SpellAction(QAction):
correct = pyqtSignal(str)
def __init__(self, *args):
QAction.__init__(self, *args)
self.triggered.connect(lambda x: self.correct.emit(self.text()))
# END Class SpellAction
+8 -4
View File
@@ -20,13 +20,13 @@ logger = logging.getLogger(__name__)
class GuiDocHighlighter(QSyntaxHighlighter): class GuiDocHighlighter(QSyntaxHighlighter):
def __init__(self, theDoc, theDict): def __init__(self, theDoc):
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 = theDict self.theDict = None
self.hRules = [] self.hRules = []
self.colHead = QColor( 0,155,200) self.colHead = QColor( 0,155,200)
@@ -145,12 +145,16 @@ class GuiDocHighlighter(QSyntaxHighlighter):
# Build a QRegExp for each pattern and for the spell checker # Build a QRegExp for each pattern and for the spell checker
self.rules = [(QRegularExpression(a),b) for (a,b) in self.hRules] self.rules = [(QRegularExpression(a),b) for (a,b) in self.hRules]
self.spellRx = QRegularExpression(r"[\w\'{:s}]+".format(self.mainConf.fmtApostrophe)) self.spellRx = QRegularExpression(r"\b[^\s]+\b")
logger.debug("DocHighlighter initialisation complete") logger.debug("DocHighlighter initialisation complete")
return return
def setDict(self, theDict):
self.theDict = theDict
return
def _makeFormat(self, fmtCol=None, fmtStyle=None, fmtSize=None): def _makeFormat(self, fmtCol=None, fmtStyle=None, fmtSize=None):
theFormat = QTextCharFormat() theFormat = QTextCharFormat()
@@ -188,7 +192,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
if self.theDict is None: if self.theDict is None:
return return
rxSpell = self.spellRx.globalMatch(theText, 0) rxSpell = self.spellRx.globalMatch(theText.replace("_"," "), 0)
while rxSpell.hasNext(): while rxSpell.hasNext():
rxMatch = rxSpell.next() rxMatch = rxSpell.next()
if not self.theDict.check(rxMatch.captured(0)): if not self.theDict.check(rxMatch.captured(0)):
+4 -2
View File
@@ -159,8 +159,9 @@ class GuiMain(QMainWindow):
def newProject(self): def newProject(self):
logger.info("Creating new project") logger.info("Creating new project")
self.treeView.clearTree() self.treeView.clearTree()
self.theProject.newProject() if self.saveProject():
self.treeView.buildTree() self.theProject.newProject()
self.treeView.buildTree()
return return
def openProject(self, projFile=None): def openProject(self, projFile=None):
@@ -174,6 +175,7 @@ class GuiMain(QMainWindow):
self.mainMenu.updateRecentProjects() 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"))
return True return True
def saveProject(self): def saveProject(self):
+26 -7
View File
@@ -39,6 +39,8 @@ class NWProject():
self.treeRoots = None self.treeRoots = None
self.trashRoot = None self.trashRoot = None
self.projPath = None self.projPath = None
self.projMeta = None
self.projCache = None
self.projFile = None self.projFile = None
self.projName = None self.projName = None
self.bookTitle = None self.bookTitle = None
@@ -116,6 +118,8 @@ class NWProject():
self.treeRoots = [] self.treeRoots = []
self.trashRoot = None self.trashRoot = None
self.projPath = None self.projPath = None
self.projMeta = None
self.projCache = None
self.projFile = "nwProject.nwx" self.projFile = "nwProject.nwx"
self.projName = "" self.projName = ""
self.bookTitle = "" self.bookTitle = ""
@@ -141,6 +145,12 @@ class NWProject():
self.projPath = path.dirname(fileName) self.projPath = path.dirname(fileName)
logger.debug("Opening project: %s" % self.projPath) logger.debug("Opening project: %s" % self.projPath)
self.projMeta = path.join(self.projPath,"meta")
self.projCache = path.join(self.projPath,"cache")
if not self._checkFolder(self.projMeta): return
if not self._checkFolder(self.projCache): return
nwXML = etree.parse(fileName) nwXML = etree.parse(fileName)
xRoot = nwXML.getroot() xRoot = nwXML.getroot()
@@ -201,13 +211,12 @@ class NWProject():
self.theParent.makeAlert("Project path not set, cannot save.",2) self.theParent.makeAlert("Project path not set, cannot save.",2)
return False return False
if not path.isdir(self.projPath): self.projMeta = path.join(self.projPath,"meta")
try: self.projCache = path.join(self.projPath,"cache")
mkdir(self.projPath)
logger.info("Created folder %s" % self.projPath) if not self._checkFolder(self.projPath): return
except Exception as e: if not self._checkFolder(self.projMeta): return
self.theParent.makeAlert(["Could not create folder.",str(e)],2) if not self._checkFolder(self.projCache): return
return False
logger.debug("Saving project: %s" % self.projPath) logger.debug("Saving project: %s" % self.projPath)
@@ -326,6 +335,16 @@ class NWProject():
# Internal Functions # Internal Functions
## ##
def _checkFolder(self, thePath):
if not path.isdir(thePath):
try:
mkdir(thePath)
logger.info("Created folder %s" % thePath)
except Exception as e:
self.theParent.makeAlert(["Could not create folder.",str(e)],2)
return False
return True
def _scanProjectFolder(self): def _scanProjectFolder(self):
if self.projPath is None: if self.projPath is None: