19 #include "QtSpell.hpp"
20 #include "TextEditChecker_p.hpp"
21 #include "UndoRedoStack.hpp"
24 #include <QPlainTextEdit>
34 testCursor.movePosition(NextCharacter, MoveAnchor, num - 1);
36 testCursor.setPosition(testCursor.position());
37 testCursor.movePosition(NextCharacter, KeepAnchor);
38 return testCursor.selectedText();
45 testCursor.movePosition(PreviousCharacter, MoveAnchor, num - 1);
47 testCursor.setPosition(testCursor.position());
48 testCursor.movePosition(PreviousCharacter, KeepAnchor);
49 return testCursor.selectedText();
54 movePosition(StartOfWord, moveMode);
59 if(
prevChar().contains(m_wordRegEx)){
60 movePosition(WordLeft, moveMode);
62 movePosition(NextCharacter, moveMode);
67 movePosition(WordLeft, moveMode, 2);
73 movePosition(EndOfWord, moveMode);
78 if(
nextChar().contains(m_wordRegEx)){
79 movePosition(WordRight, moveMode);
81 movePosition(PreviousCharacter, moveMode);
86 movePosition(WordRight, moveMode, 2);
104 setTextEdit(textEdit ?
new TextEditProxyT<QTextEdit>(textEdit) :
static_cast<TextEditProxyT<QTextEdit>*
>(
nullptr));
109 setTextEdit(textEdit ?
new TextEditProxyT<QPlainTextEdit>(textEdit) :
static_cast<TextEditProxyT<QPlainTextEdit>*
>(
nullptr));
115 disconnect(m_textEdit, &TextEditProxy::editDestroyed,
this, &TextEditChecker::slotDetachTextEdit);
116 disconnect(m_textEdit, &TextEditProxy::textChanged,
this, &TextEditChecker::slotCheckDocumentChanged);
117 disconnect(m_textEdit, &TextEditProxy::customContextMenuRequested,
this, &TextEditChecker::slotShowContextMenu);
118 disconnect(m_textEdit->document(), &QTextDocument::contentsChange,
this, &TextEditChecker::slotCheckRange);
119 m_textEdit->setContextMenuPolicy(m_oldContextMenuPolicy);
120 m_textEdit->removeEventFilter(
this);
123 QTextCursor cursor = m_textEdit->textCursor();
124 cursor.movePosition(QTextCursor::Start);
125 cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
126 QTextCharFormat fmt = cursor.charFormat();
127 QTextCharFormat defaultFormat = QTextCharFormat();
128 fmt.setFontUnderline(defaultFormat.fontUnderline());
129 fmt.setUnderlineColor(defaultFormat.underlineColor());
130 fmt.setUnderlineStyle(defaultFormat.underlineStyle());
131 cursor.setCharFormat(fmt);
133 bool undoWasEnabled = m_undoRedoStack !=
nullptr;
136 m_document =
nullptr;
137 m_textEdit = textEdit;
139 m_document = m_textEdit->document();
140 connect(m_textEdit, &TextEditProxy::editDestroyed,
this, &TextEditChecker::slotDetachTextEdit);
141 connect(m_textEdit, &TextEditProxy::textChanged,
this, &TextEditChecker::slotCheckDocumentChanged);
142 connect(m_textEdit, &TextEditProxy::customContextMenuRequested,
this, &TextEditChecker::slotShowContextMenu);
143 connect(m_textEdit->document(), &QTextDocument::contentsChange,
this, &TextEditChecker::slotCheckRange);
144 m_oldContextMenuPolicy = m_textEdit->contextMenuPolicy();
146 m_textEdit->setContextMenuPolicy(Qt::CustomContextMenu);
147 m_textEdit->installEventFilter(
this);
152 bool TextEditChecker::eventFilter(QObject* obj, QEvent* event)
154 if(event->type() == QEvent::KeyPress){
155 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
156 if(keyEvent->key() == Qt::Key_Z && keyEvent->modifiers() == Qt::CTRL){
159 }
else if(keyEvent->key() == Qt::Key_Z && keyEvent->modifiers() == (Qt::CTRL | Qt::SHIFT)){
164 return QObject::eventFilter(obj, event);
170 QTextCursor tmpCursor(m_textEdit->textCursor());
171 tmpCursor.movePosition(QTextCursor::End);
172 end = tmpCursor.position();
176 m_textEdit->document()->blockSignals(
true);
178 qDebug() <<
"Checking range " << start <<
" - " << end;
180 QTextCharFormat errorFmt;
181 errorFmt.setFontUnderline(
true);
182 errorFmt.setUnderlineColor(Qt::red);
183 errorFmt.setUnderlineStyle(QTextCharFormat::WaveUnderline);
184 QTextCharFormat defaultFormat = QTextCharFormat();
187 cursor.beginEditBlock();
188 cursor.setPosition(start);
189 while(cursor.position() < end) {
192 QString word = cursor.selectedText();
193 if(noSpellingPropertySet(cursor)) {
195 qDebug() <<
"Skipping word:" << word <<
"(" << cursor.anchor() <<
"-" << cursor.position() <<
")";
198 qDebug() <<
"Checking word:" << word <<
"(" << cursor.anchor() <<
"-" << cursor.position() <<
"), correct:" << correct;
201 cursor.mergeCharFormat(errorFmt);
203 QTextCharFormat fmt = cursor.charFormat();
204 fmt.setFontUnderline(defaultFormat.fontUnderline());
205 fmt.setUnderlineColor(defaultFormat.underlineColor());
206 fmt.setUnderlineStyle(defaultFormat.underlineStyle());
207 cursor.setCharFormat(fmt);
210 while(cursor.position() < end && !cursor.isWordChar(cursor.nextChar())){
211 cursor.movePosition(QTextCursor::NextCharacter);
214 cursor.endEditBlock();
216 m_textEdit->document()->blockSignals(
false);
219 bool TextEditChecker::noSpellingPropertySet(
const QTextCursor &cursor)
const
221 if(m_noSpellingProperty < QTextFormat::UserProperty) {
224 if(cursor.charFormat().intProperty(m_noSpellingProperty) == 1) {
227 const QVector<QTextLayout::FormatRange>& formats = cursor.block().layout()->formats();
228 int pos = cursor.positionInBlock();
229 foreach(
const QTextLayout::FormatRange& range, formats) {
230 if(pos > range.start && pos <= range.start + range.length && range.format.intProperty(m_noSpellingProperty) == 1) {
240 m_undoRedoStack->clear();
246 if(enabled == (m_undoRedoStack !=
nullptr)){
250 delete m_undoRedoStack;
251 m_undoRedoStack =
nullptr;
255 m_undoRedoStack =
new UndoRedoStack(m_textEdit);
264 cursor.setPosition(pos);
266 cursor.moveWordEnd(QTextCursor::KeepAnchor);
268 *start = cursor.anchor();
270 *end = cursor.position();
271 return cursor.selectedText();
276 QTextCursor cursor(m_textEdit->textCursor());
277 cursor.setPosition(start);
278 cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, end - start);
279 cursor.insertText(word);
282 void TextEditChecker::slotShowContextMenu(
const QPoint &pos)
284 QPoint globalPos = m_textEdit->mapToGlobal(pos);
285 QMenu* menu = m_textEdit->createStandardContextMenu();
286 int wordPos = m_textEdit->cursorForPosition(pos).position();
287 showContextMenu(menu, globalPos, wordPos);
290 void TextEditChecker::slotCheckDocumentChanged()
292 if(m_document != m_textEdit->document()) {
293 bool undoWasEnabled = m_undoRedoStack !=
nullptr;
296 disconnect(m_document, &QTextDocument::contentsChange,
this, &TextEditChecker::slotCheckRange);
298 m_document = m_textEdit->document();
299 connect(m_document, &QTextDocument::contentsChange,
this, &TextEditChecker::slotCheckRange);
304 void TextEditChecker::slotDetachTextEdit()
306 bool undoWasEnabled = m_undoRedoStack !=
nullptr;
309 m_textEdit =
nullptr;
310 m_document =
nullptr;
317 void TextEditChecker::slotCheckRange(
int pos,
int removed,
int added)
319 if(m_undoRedoStack !=
nullptr && !m_undoRedoInProgress){
320 m_undoRedoStack->handleContentsChange(pos, removed, added);
324 TextCursor c(m_textEdit->textCursor());
325 c.movePosition(QTextCursor::End);
326 int len = c.position();
327 if(pos == 0 && added > len){
335 c.setPosition(pos + added, QTextCursor::KeepAnchor);
336 c.moveWordEnd(QTextCursor::KeepAnchor);
337 QTextCharFormat fmt = c.charFormat();
338 QTextCharFormat defaultFormat = QTextCharFormat();
339 fmt.setFontUnderline(defaultFormat.fontUnderline());
340 fmt.setUnderlineColor(defaultFormat.underlineColor());
341 fmt.setUnderlineStyle(defaultFormat.underlineStyle());
342 c.setCharFormat(fmt);
349 if(m_undoRedoStack !=
nullptr){
350 m_undoRedoInProgress =
true;
351 m_undoRedoStack->undo();
352 m_textEdit->ensureCursorVisible();
353 m_undoRedoInProgress =
false;
359 if(m_undoRedoStack !=
nullptr){
360 m_undoRedoInProgress =
true;
361 m_undoRedoStack->redo();
362 m_textEdit->ensureCursorVisible();
363 m_undoRedoInProgress =
false;