Adds: Spellcheck

This commit is contained in:
Olivier Keshavjee 2015-06-06 19:10:44 +02:00
parent 03a0124093
commit bfc255bed0
9 changed files with 276 additions and 90 deletions

View file

@ -15,7 +15,16 @@ from models.outlineModel import *
from models.persosProxyModel import *
from functions import *
# Spell checker support
try:
import enchant
except ImportError:
enchant = None
class MainWindow(QMainWindow, Ui_MainWindow):
dictChanged = pyqtSignal(unicode)
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
@ -186,7 +195,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.mprOutline = QDataWidgetMapper()
self.mprOutline.setModel(self.mdlOutline)
mapping = [
(self.redacEditor.txtRedacText, Outline.text.value),
(self.txtRedacSummarySentance, Outline.summarySentance.value),
(self.txtRedacSummaryFull, Outline.summaryFull.value),
(self.txtRedacNotes, Outline.notes.value),
@ -202,6 +210,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.treeRedacOutline.selectionModel().currentChanged.connect(self.cmbRedacStatus.setCurrentModelIndex)
self.treeRedacOutline.selectionModel().currentChanged.connect(self.chkRedacCompile.setCurrentModelIndex)
self.treeRedacOutline.selectionModel().currentChanged.connect(self.redacEditor.setCurrentModelIndex)
self.treeRedacOutline.selectionModel().currentChanged.connect(self.redacEditor.txtRedacText.setCurrentModelIndex)
self.tabMain.currentChanged.connect(self.mprOutline.submit)
self.treeRedacOutline.selectionModel().currentChanged.connect(self.outlineSelectionChanged)
@ -425,7 +435,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.splitterRedac.setStretchFactor(2, 20)
# Help box
references = [
(self.lytTabOverview,
"Entrez toutes les informations relatives au livre, ainsi qu'à vous."),
@ -448,4 +457,40 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.actShowHelp.toggled.connect(label.setVisible)
widget.layout().insertWidget(0, label)
self.actShowHelp.setChecked(False)
self.actShowHelp.setChecked(False)
# Spellcheck
if enchant:
self.menuDict = QMenu("Dictionary")
self.menuDictGroup = QActionGroup(self)
for i in enchant.list_dicts():
a = QAction(unicode(i[0]), self)
a.setCheckable(True)
a.triggered.connect(self.setDictionary)
if unicode(i[0]) == enchant.get_default_language(): # "fr_CH"
a.setChecked(True)
self.menuDictGroup.addAction(a)
self.menuDict.addAction(a)
self.menuTools.addMenu(self.menuDict)
self.actSpellcheck.toggled.connect(self.redacEditor.toggleSpellcheck)
self.dictChanged.connect(self.redacEditor.setDict)
else:
# No Spell check support
self.actSpellcheck.setVisible(False)
a = QAction("Install PyEnchant to use spellcheck", self)
a.setIcon(self.style().standardIcon(QStyle.SP_MessageBoxWarning))
a.triggered.connect(self.openPyEnchantWebPage)
self.menuTools.addAction(a)
def setDictionary(self):
for i in self.menuDictGroup.actions():
if i.isChecked():
self.dictChanged.emit(i.text().replace("&", ""))
def openPyEnchantWebPage(self):
QDesktopServices.openUrl(QUrl("http://pythonhosted.org/pyenchant/"))

View file

@ -411,10 +411,6 @@ class outlineItem():
if column == Outline.text.value and self.isFolder():
# Folder have no text
return
if column == Outline.text.value:
wc = wordCount(data)
self.setData(Outline.wordCount.value, wc)
if column == Outline.goal.value:
self._data[Outline.setGoal] = toInt(data) if toInt(data) > 0 else ""
@ -425,6 +421,10 @@ class outlineItem():
self._data[Outline(column)] = data
if column == Outline.text.value:
wc = wordCount(data)
self.setData(Outline.wordCount.value, wc)
if updateWordCount:
self.updateWordCount()

View file

@ -14,18 +14,141 @@ except ImportError:
class customTextEdit(QTextEdit):
def __init__(self, parent=None):
def __init__(self, parent=None, index=None, html=None, spellcheck=True, dict=""):
QTextEdit.__init__(self, parent)
self.document().contentsChanged.connect(self.sizeChange)
self.defaultFontPointSize = 9
self.highlightWord = ""
self.highligtCS = False
self.highlighter = t2tHighlighter(self)
self.currentIndex = None
# Spellchecking
if enchant:
self.dict = enchant.Dict("fr_CH")
self.spellcheck = True
else:
self.spellcheck = False
self.heightMin = 0
self.heightMax = 65000
self.sizeChange()
self.item = None
self.spellcheck = spellcheck
self.currentDict = dict
if index:
self.setCurrentModelIndex(index)
elif html:
self.document().setHtml(html)
self.setReadOnly(True)
def setCurrentModelIndex(self, index):
if index.isValid():
self.currentIndex = index
self.item = index.internalPointer()
self._model = index.model()
self.document().contentsChanged.connect(self.submit)
self._model.dataChanged.connect(self.update)
self.updateText()
self.defaultFontPointSize = qApp.font().pointSize()
self.highlightWord = ""
self.highligtCS = False
self.highlighter = t2tHighlighter(self)
# Spellchecking
if enchant and self.spellcheck:
self.dict = enchant.Dict(self.currentDict if self.currentDict else enchant.get_default_language())
def submit(self):
if self.toPlainText() <> self.item.data(Outline.text.value):
#self._model.setData(self.item.index(), self.toPlainText(), Outline.text.value)
self.item.setData(Outline.text.value, self.toPlainText())
def update(self, topLeft, bottomRight):
if topLeft.row() <= self.currentIndex.row() <= bottomRight.row():
self.updateText()
def updateText(self):
if self.item:
if self.toPlainText() <> self.item.data(Outline.text.value):
self.document().setPlainText(self.item.data(Outline.text.value))
def resizeEvent(self, e):
QTextEdit.resizeEvent(self, e)
self.sizeChange()
def sizeChange(self):
docHeight = self.document().size().height()
if self.heightMin <= docHeight <= self.heightMax:
self.setMinimumHeight(docHeight)
# -----------------------------------------------------------------------------------------------------
# Spellchecking based on http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/
def setDict(self, d):
self.dict = enchant.Dict(d)
self.highlighter.rehighlight()
def toggleSpellcheck(self, v):
self.spellcheck = v
self.highlighter.rehighlight()
def mousePressEvent(self, event):
if event.button() == Qt.RightButton:
# Rewrite the mouse event to a left button event so the cursor is
# moved to the location of the pointer.
event = QMouseEvent(QEvent.MouseButtonPress, event.pos(),
Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
QTextEdit.mousePressEvent(self, event)
class SpellAction(QAction):
"A special QAction that returns the text in a signal. Used for spellckech."
correct = pyqtSignal(unicode)
def __init__(self, *args):
QAction.__init__(self, *args)
self.triggered.connect(lambda x: self.correct.emit(
unicode(self.text())))
def contextMenuEvent(self, event):
# Based on http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/
if not self.spellcheck:
QTextEdit.contextMenuEvent(self, event)
return
popup_menu = self.createStandardContextMenu()
# Select the word under the cursor.
cursor = self.textCursor()
cursor.select(QTextCursor.WordUnderCursor)
self.setTextCursor(cursor)
# Check if the selected word is misspelled and offer spelling
# suggestions if it is.
if self.textCursor().hasSelection():
text = unicode(self.textCursor().selectedText())
if not self.dict.check(text):
spell_menu = QMenu('Spelling Suggestions')
for word in self.dict.suggest(text):
action = self.SpellAction(word, spell_menu)
action.correct.connect(self.correctWord)
spell_menu.addAction(action)
# Only add the spelling suggests to the menu if there are
# suggestions.
if len(spell_menu.actions()) != 0:
popup_menu.insertSeparator(popup_menu.actions()[0])
popup_menu.insertMenu(popup_menu.actions()[0], spell_menu)
popup_menu.exec_(event.globalPos())
def correctWord(self, word):
'''
Replaces the selected text with word.
'''
cursor = self.textCursor()
cursor.beginEditBlock()
cursor.removeSelectedText()
cursor.insertText(word)
cursor.endEditBlock()
# -----------------------------------------------------------------------------------------------------

View file

@ -7,61 +7,24 @@ from __future__ import unicode_literals
from qt import *
from enums import *
from ui.editors.editorWidget_ui import *
class GrowingTextEdit(QTextEdit):
def __init__(self, index=None, html=None, parent=None):
QTextEdit.__init__(self, parent)
self.document().contentsChanged.connect(self.sizeChange)
self.heightMin = 0
self.heightMax = 65000
self.sizeChange()
self.item = None
if index:
self.currentIndex = index
self.item = index.internalPointer()
self._model = index.model()
self._model.dataChanged.connect(self.update)
self.document().contentsChanged.connect(self.submit)
else:
self.document().setHtml(html)
self.setReadOnly(True)
self.updateText()
def submit(self):
self.item.setData(Outline.text.value, self.toPlainText())
def update(self, topLeft, bottomRight):
if topLeft.row() <= self.currentIndex.row() <= bottomRight.row():
self.updateText()
def updateText(self):
if self.item:
self.document().setPlainText(self.item.data(Outline.text.value))
def resizeEvent(self, e):
QTextEdit.resizeEvent(self, e)
self.sizeChange()
def sizeChange(self):
docHeight = self.document().size().height()
if self.heightMin <= docHeight <= self.heightMax:
self.setMinimumHeight(docHeight)
from ui.editors.customTextEdit import *
class editorWidget(QWidget, Ui_editorWidget_ui):
toggledSpellcheck = pyqtSignal(bool)
dictChanged = pyqtSignal(str)
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setupUi(self)
self.currentIndex = None
self.txtEdits = []
self.scroll.setBackgroundRole(QPalette.Base)
self.toggledSpellcheck.connect(self.txtRedacText.toggleSpellcheck)
self.dictChanged.connect(self.txtRedacText.setDict)
self.currentDict = ""
self.spellcheck = True
def setCurrentModelIndex(self, index):
@ -82,7 +45,7 @@ class editorWidget(QWidget, Ui_editorWidget_ui):
self.txtEdits = []
def addTitle(itm):
edt = GrowingTextEdit(html="<h{l}>{t}</h{l}>".format(l=min(itm.level()+1, 5), t=itm.title()))
edt = customTextEdit(self, html="<h{l}>{t}</h{l}>".format(l=min(itm.level()+1, 5), t=itm.title()))
edt.setFrameShape(QFrame.NoFrame)
self.txtEdits.append(edt)
l.addWidget(edt)
@ -94,9 +57,11 @@ class editorWidget(QWidget, Ui_editorWidget_ui):
l.addWidget(line)
def addScene(itm):
edt = GrowingTextEdit(index=itm.index())
edt = customTextEdit(self, index=itm.index(), spellcheck=self.spellcheck, dict=self.currentDict)
edt.setFrameShape(QFrame.NoFrame)
edt.setStatusTip(itm.path())
self.toggledSpellcheck.connect(edt.toggleSpellcheck)
self.dictChanged.connect(edt.setDict)
#edt.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
self.txtEdits.append(edt)
l.addWidget(edt)
@ -125,4 +90,11 @@ class editorWidget(QWidget, Ui_editorWidget_ui):
else:
self.currentIndex = None
def toggleSpellcheck(self, v):
self.spellcheck = v
self.toggledSpellcheck.emit(v)
def setDict(self, dct):
self.currentDict = dct
self.dictChanged.emit(dct)

View file

@ -343,13 +343,14 @@ class t2tHighlighter (QSyntaxHighlighter):
data = blockUserData.getUserData(block)
# Header Lines
if block.blockNumber() == 0:
block.setUserState(State.HEADER_LINE)
return
elif block.blockNumber() in [1, 2] and \
self.document().findBlockByNumber(0).text():
block.setUserState(State.HEADER_LINE)
return
# No header line here
#if block.blockNumber() == 0:
#block.setUserState(State.HEADER_LINE)
#return
#elif block.blockNumber() in [1, 2] and \
#self.document().findBlockByNumber(0).text():
#block.setUserState(State.HEADER_LINE)
#return
state = 0
inList = False

View file

@ -21,11 +21,11 @@ class t2tHighlighterStyle ():
# Defaults
self.defaultFontPointSize = self.editor.defaultFontPointSize
self.defaultFontFamily = ""
self.defaultFontFamily = qApp.font().family()
self.tabStopWidth = 40
self.setupEditor()
if self.name == "Default":
self.initDefaults()
#Temporary other theme
@ -126,7 +126,7 @@ class t2tHighlighterStyle ():
blockFormat.setBackground(QColor("#EEEEFA"))
n = blockUserData.getUserData(block).leadingSpaces() + 1
f = QFontMetrics(QFont(self.defaultFontFamily,
self.defaultFontPointSize))
self.defaultFontPointSize))
fm = f.width(" " * n +
blockUserData.getUserData(block).listSymbol())
blockFormat.setTextIndent(-fm)
@ -170,7 +170,7 @@ class t2tHighlighterStyle ():
if preset in [State.HEADER_LINE]:
size = size * 2
print size
#print size
if preset in [State.RAW_AREA, State.RAW_LINE, "raw"]:
color = "blue"

View file

@ -1051,6 +1051,8 @@ class Ui_MainWindow(object):
self.menuMode.setObjectName("menuMode")
self.menu_Aide = QtWidgets.QMenu(self.menubar)
self.menu_Aide.setObjectName("menu_Aide")
self.menuTools = QtWidgets.QMenu(self.menubar)
self.menuTools.setObjectName("menuTools")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
@ -1089,6 +1091,14 @@ class Ui_MainWindow(object):
icon = QtGui.QIcon.fromTheme("system-help")
self.actShowHelp.setIcon(icon)
self.actShowHelp.setObjectName("actShowHelp")
self.actSpellcheck = QtWidgets.QAction(MainWindow)
self.actSpellcheck.setCheckable(True)
self.actSpellcheck.setChecked(True)
icon = QtGui.QIcon.fromTheme("tools-check-spelling")
self.actSpellcheck.setIcon(icon)
self.actSpellcheck.setObjectName("actSpellcheck")
self.actSpellcheckDict = QtWidgets.QAction(MainWindow)
self.actSpellcheckDict.setObjectName("actSpellcheckDict")
self.menu_Fichier.addAction(self.actionNouveau)
self.menu_Fichier.addAction(self.actionOuvrir)
self.menu_Fichier.addAction(self.action_R_cents)
@ -1098,9 +1108,11 @@ class Ui_MainWindow(object):
self.menu_Fichier.addAction(self.actionQuitter)
self.menuMode.addAction(self.actionSnowflakeMode)
self.menu_Aide.addAction(self.actShowHelp)
self.menuTools.addAction(self.actSpellcheck)
self.menubar.addAction(self.menu_Fichier.menuAction())
self.menubar.addAction(self.menuMode.menuAction())
self.menubar.addAction(self.menu_Aide.menuAction())
self.menubar.addAction(self.menuTools.menuAction())
self.retranslateUi(MainWindow)
self.tabMain.setCurrentIndex(6)
@ -1257,6 +1269,7 @@ class Ui_MainWindow(object):
self.menu_Fichier.setTitle(_translate("MainWindow", "&Fichier"))
self.menuMode.setTitle(_translate("MainWindow", "Mo&de"))
self.menu_Aide.setTitle(_translate("MainWindow", "&Aide"))
self.menuTools.setTitle(_translate("MainWindow", "&Outlis"))
self.actionOuvrir.setText(_translate("MainWindow", "&Ouvrir"))
self.actionOuvrir.setShortcut(_translate("MainWindow", "Ctrl+O"))
self.action_R_cents.setText(_translate("MainWindow", "&Récents"))
@ -1272,10 +1285,13 @@ class Ui_MainWindow(object):
self.actionNouveau.setShortcut(_translate("MainWindow", "Ctrl+N"))
self.actShowHelp.setText(_translate("MainWindow", "Afficher les &bulles d\'aide"))
self.actShowHelp.setShortcut(_translate("MainWindow", "Ctrl+Shift+B"))
self.actSpellcheck.setText(_translate("MainWindow", "Correcteur ortographique"))
self.actSpellcheck.setShortcut(_translate("MainWindow", "F8"))
self.actSpellcheckDict.setText(_translate("MainWindow", "Dictionnaire"))
from ui.cmbOutlineStatusChoser import cmbOutlineStatusChoser
from ui.cmbOutlinePersoChoser import cmbOutlinePersoChoser
from ui.collapsibleGroupBox2 import collapsibleGroupBox2
from ui.chkOutlineCompile import chkOutlineCompile
from ui.sldImportance import sldImportance
from ui.editors.editorWidget import editorWidget
from ui.cmbOutlinePersoChoser import cmbOutlinePersoChoser
from ui.chkOutlineCompile import chkOutlineCompile
from ui.collapsibleGroupBox2 import collapsibleGroupBox2

View file

@ -2046,9 +2046,16 @@
</property>
<addaction name="actShowHelp"/>
</widget>
<widget class="QMenu" name="menuTools">
<property name="title">
<string>&amp;Outlis</string>
</property>
<addaction name="actSpellcheck"/>
</widget>
<addaction name="menu_Fichier"/>
<addaction name="menuMode"/>
<addaction name="menu_Aide"/>
<addaction name="menuTools"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionOuvrir">
@ -2159,6 +2166,28 @@
<string>Ctrl+Shift+B</string>
</property>
</action>
<action name="actSpellcheck">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="icon">
<iconset theme="tools-check-spelling"/>
</property>
<property name="text">
<string>Correcteur ortographique</string>
</property>
<property name="shortcut">
<string>F8</string>
</property>
</action>
<action name="actSpellcheckDict">
<property name="text">
<string>Dictionnaire</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View file

@ -1,25 +1,25 @@
<?xml version='1.0' encoding='UTF-8'?>
<outlineItem title="root" type="folder" compile="2" wordCount="389" setGoal="112">
<outlineItem title="root" type="folder" compile="2" wordCount="298" setGoal="112">
<outlineItem title="Nouveau" type="folder" compile="2" wordCount="15">
<outlineItem title="Nouveau" type="scene" compile="2" text="return QTextEdit.resizeEvent(self, e) ad ad ad ad adaasd ad adsdasd ad e drset" wordCount="15"/>
</outlineItem>
<outlineItem title="Parent" type="folder" status="TODO" compile="2" wordCount="127">
<outlineItem title="Nouveau" type="folder" summarySentance="asd asd asd " status="First draft" compile="2" wordCount="99">
<outlineItem title="A" type="scene" compile="2" text="Du texteDu texteDu text ad ad ad ad " wordCount="8" setGoal="10"/>
<outlineItem title="Parent" type="folder" status="TODO" compile="2" wordCount="43">
<outlineItem title="Nouveau" type="folder" summarySentance="asd asd asd " status="First draft" compile="2" wordCount="13">
<outlineItem title="A" type="scene" compile="2" text="Du texteDu texteDu text ad ad ad ad a" wordCount="9" setGoal="10"/>
<outlineItem title="B" type="scene" compile="2" setGoal="3"/>
<outlineItem title="C" type="scene" compile="2" text="adasd ad ad " wordCount="3" setGoal="3"/>
<outlineItem title="Nouveau" type="folder" compile="2" wordCount="88">
<outlineItem title="Interest" type="scene" compile="2" text="asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as asd asd asd as " wordCount="88" setGoal="100"/>
<outlineItem title="Nouveau" type="folder" compile="2" wordCount="1">
<outlineItem title="Interest" type="scene" compile="2" text="s" wordCount="1" setGoal="100"/>
<outlineItem title="Nouveau" type="scene" compile="2"/>
</outlineItem>
</outlineItem>
<outlineItem title="MOIMOIMOI" type="scene" POV="1" compile="2" text="ASDASd ASD ASDASd ASD ASDASd ASD " wordCount="6" setGoal="10"/>
<outlineItem title="Nouveau" type="scene" POV="1" compile="2" text="ASDASd ASD ASDASd ASD asd sss ad ad " wordCount="8" setGoal="10"/>
<outlineItem title="MOIMOIMOI" type="scene" POV="1" compile="2" text="ASDASd ASD ASDASd ASD ASDASd ASD **ssss**" wordCount="7" setGoal="10"/>
<outlineItem title="Nouveau" type="scene" POV="1" compile="2" text="ASDASd ASD ASDASd ASD asd sss ad ad ssss" wordCount="9" setGoal="10"/>
<outlineItem title="Nouveau" type="scene" compile="2" text="ASDASd ASD ASDASd ASD " wordCount="4" setGoal="10"/>
<outlineItem title="B" type="scene" compile="2" text="asd asd asd asd asd asd asd asd asd " wordCount="10" setGoal="10"/>
<outlineItem title="Nouveau" type="folder" compile="2"/>
</outlineItem>
<outlineItem title="MOIMOIMOI" type="scene" status="Second draft" compile="2" text="&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;&#10;&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;&#10;p, li { white-space: pre-wrap; }&#10;&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Oxygen-Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;&#10;&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:37;&quot;&gt;Text **gras**&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;" wordCount="30" setGoal="2500"/>
<outlineItem title="MOIMOIMOI" type="scene" summaryFull="Là ça joue, et on est content. Pas de raison de se plaindre. **OK**?" status="Second draft" compile="2" text="Là ça joue, et on est content. Pas de raison de se plaindre. **OK**?&#10;&#10;Ben voilà, suffisait de demander ! asd asdads asd a" wordCount="23" setGoal="2500"/>
<outlineItem title="A" type="scene" compile="2" setGoal="146"/>
<outlineItem title="Nouveau A" type="folder" compile="2" wordCount="217">
<outlineItem title="Nouveau" type="scene" compile="2" text="ASDASd ASD ASDASd ASD " wordCount="4"/>