19 #include "QtSpell.hpp"
20 #include "TextEditChecker_p.hpp"
21 #include "UndoRedoStack.hpp"
24 #include <QPlainTextEdit>
33 testCursor.movePosition(NextCharacter, MoveAnchor, num - 1);
35 testCursor.setPosition(testCursor.position());
36 testCursor.movePosition(NextCharacter, KeepAnchor);
37 return testCursor.selectedText();
44 testCursor.movePosition(PreviousCharacter, MoveAnchor, num - 1);
46 testCursor.setPosition(testCursor.position());
47 testCursor.movePosition(PreviousCharacter, KeepAnchor);
48 return testCursor.selectedText();
53 movePosition(StartOfWord, moveMode);
58 if(
prevChar().contains(m_wordRegEx)){
59 movePosition(WordLeft, moveMode);
61 movePosition(NextCharacter, moveMode);
66 movePosition(WordLeft, moveMode, 2);
72 movePosition(EndOfWord, moveMode);
77 if(
nextChar().contains(m_wordRegEx)){
78 movePosition(WordRight, moveMode);
80 movePosition(PreviousCharacter, moveMode);
85 movePosition(WordRight, moveMode, 2);
97 m_undoRedoInProgress =
false;
107 setTextEdit(textEdit ?
new TextEditProxyT<QTextEdit>(textEdit) :
reinterpret_cast<TextEditProxyT<QTextEdit>*
>(0));
112 setTextEdit(textEdit ?
new TextEditProxyT<QPlainTextEdit>(textEdit) :
reinterpret_cast<TextEditProxyT<QPlainTextEdit>*
>(0));
117 if(!textEdit && m_textEdit){
118 disconnect(m_textEdit->object(), SIGNAL(destroyed()),
this, SLOT(slotDetachTextEdit()));
119 disconnect(m_textEdit->object(), SIGNAL(textChanged()),
this, SLOT(slotCheckDocumentChanged()));
120 disconnect(m_textEdit->object(), SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(slotShowContextMenu(QPoint)));
121 disconnect(m_textEdit->document(), SIGNAL(contentsChange(
int,
int,
int)),
this, SLOT(slotCheckRange(
int,
int,
int)));
122 m_textEdit->setContextMenuPolicy(m_oldContextMenuPolicy);
123 m_textEdit->removeEventFilter(
this);
126 QTextCursor cursor = m_textEdit->textCursor();
127 cursor.movePosition(QTextCursor::Start);
128 cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
129 QTextCharFormat fmt = cursor.charFormat();
130 QTextCharFormat defaultFormat = QTextCharFormat();
131 fmt.setFontUnderline(defaultFormat.fontUnderline());
132 fmt.setUnderlineColor(defaultFormat.underlineColor());
133 fmt.setUnderlineStyle(defaultFormat.underlineStyle());
134 cursor.setCharFormat(fmt);
136 bool undoWasEnabled = m_undoRedoStack != 0;
140 m_textEdit = textEdit;
142 m_document = m_textEdit->document();
143 connect(m_textEdit->object(), SIGNAL(destroyed()),
this, SLOT(slotDetachTextEdit()));
144 connect(m_textEdit->object(), SIGNAL(textChanged()),
this, SLOT(slotCheckDocumentChanged()));
145 connect(m_textEdit->object(), SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(slotShowContextMenu(QPoint)));
146 connect(m_textEdit->document(), SIGNAL(contentsChange(
int,
int,
int)),
this, SLOT(slotCheckRange(
int,
int,
int)));
147 m_oldContextMenuPolicy = m_textEdit->contextMenuPolicy();
149 m_textEdit->setContextMenuPolicy(Qt::CustomContextMenu);
150 m_textEdit->installEventFilter(
this);
155 bool TextEditChecker::eventFilter(QObject* obj, QEvent* event)
157 if(event->type() == QEvent::KeyPress){
158 QKeyEvent *keyEvent =
static_cast<QKeyEvent *
>(event);
159 if(keyEvent->key() == Qt::Key_Z && keyEvent->modifiers() == Qt::CTRL){
162 }
else if(keyEvent->key() == Qt::Key_Z && keyEvent->modifiers() == (Qt::CTRL | Qt::SHIFT)){
167 return QObject::eventFilter(obj, event);
173 QTextCursor tmpCursor(m_textEdit->textCursor());
174 tmpCursor.movePosition(QTextCursor::End);
175 end = tmpCursor.position();
179 m_textEdit->document()->blockSignals(
true);
181 qDebug() <<
"Checking range " << start <<
" - " << end;
183 QTextCharFormat errorFmt;
184 errorFmt.setFontUnderline(
true);
185 errorFmt.setUnderlineColor(Qt::red);
186 errorFmt.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
187 QTextCharFormat defaultFormat = QTextCharFormat();
190 cursor.beginEditBlock();
191 cursor.setPosition(start);
192 while(cursor.position() < end) {
194 QString word = cursor.selectedText();
196 qDebug() <<
"Checking word:" << word <<
"(" << cursor.anchor() <<
"-" << cursor.position() <<
"), correct:" << correct;
198 cursor.mergeCharFormat(errorFmt);
200 QTextCharFormat fmt = cursor.charFormat();
201 fmt.setFontUnderline(defaultFormat.fontUnderline());
202 fmt.setUnderlineColor(defaultFormat.underlineColor());
203 fmt.setUnderlineStyle(defaultFormat.underlineStyle());
204 cursor.setCharFormat(fmt);
207 while(cursor.position() < end && !cursor.isWordChar(cursor.nextChar())){
208 cursor.movePosition(QTextCursor::NextCharacter);
211 cursor.endEditBlock();
213 m_textEdit->document()->blockSignals(
false);
219 m_undoRedoStack->clear();
225 if(enabled == (m_undoRedoStack != 0)){
229 delete m_undoRedoStack;
234 m_undoRedoStack =
new UndoRedoStack(m_textEdit);
243 cursor.setPosition(pos);
245 cursor.moveWordEnd(QTextCursor::KeepAnchor);
247 *start = cursor.anchor();
249 *end = cursor.position();
250 return cursor.selectedText();
255 QTextCursor cursor(m_textEdit->textCursor());
256 cursor.setPosition(start);
257 cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, end - start);
258 cursor.insertText(word);
261 void TextEditChecker::slotShowContextMenu(
const QPoint &pos)
263 QPoint globalPos = m_textEdit->mapToGlobal(pos);
264 QMenu* menu = m_textEdit->createStandardContextMenu();
265 int wordPos = m_textEdit->cursorForPosition(pos).position();
266 showContextMenu(menu, globalPos, wordPos);
269 void TextEditChecker::slotCheckDocumentChanged()
271 if(m_document != m_textEdit->document()) {
272 bool undoWasEnabled = m_undoRedoStack != 0;
275 disconnect(m_document, SIGNAL(contentsChange(
int,
int,
int)),
this, SLOT(slotCheckRange(
int,
int,
int)));
277 m_document = m_textEdit->document();
278 connect(m_document, SIGNAL(contentsChange(
int,
int,
int)),
this, SLOT(slotCheckRange(
int,
int,
int)));
283 void TextEditChecker::slotDetachTextEdit()
285 bool undoWasEnabled = m_undoRedoStack != 0;
297 void TextEditChecker::slotCheckRange(
int pos,
int removed,
int added)
299 if(m_undoRedoStack != 0 && !m_undoRedoInProgress){
300 m_undoRedoStack->handleContentsChange(pos, removed, added);
304 TextCursor c(m_textEdit->textCursor());
305 c.movePosition(QTextCursor::End);
306 int len = c.position();
307 if(pos == 0 && added > len){
315 c.setPosition(pos + added, QTextCursor::KeepAnchor);
316 c.moveWordEnd(QTextCursor::KeepAnchor);
317 QTextCharFormat fmt = c.charFormat();
318 QTextCharFormat defaultFormat = QTextCharFormat();
319 fmt.setFontUnderline(defaultFormat.fontUnderline());
320 fmt.setUnderlineColor(defaultFormat.underlineColor());
321 fmt.setUnderlineStyle(defaultFormat.underlineStyle());
322 c.setCharFormat(fmt);
329 if(m_undoRedoStack != 0){
330 m_undoRedoInProgress =
true;
331 m_undoRedoStack->undo();
332 m_textEdit->ensureCursorVisible();
333 m_undoRedoInProgress =
false;
339 if(m_undoRedoStack != 0){
340 m_undoRedoInProgress =
true;
341 m_undoRedoStack->redo();
342 m_textEdit->ensureCursorVisible();
343 m_undoRedoInProgress =
false;
QString prevChar(int num=1) const
Retreive the num-th previous character.
void undo()
Undo the last edit operation.
TextEditChecker(QObject *parent=0)
TextEditChecker object constructor.
void clearUndoRedo()
Clears the undo/redo stack.
void setTextEdit(QTextEdit *textEdit)
Set the QTextEdit to check.
void setUndoRedoEnabled(bool enabled)
Sets whether undo/redo functionality is enabled.
void redoAvailable(bool available)
Emitted when the redo stak changes.
void undoAvailable(bool available)
Emitted when the undo stack changes.
void insertWord(int start, int end, const QString &word)
Replaces the specified range with the specified word.
QString getWord(int pos, int *start=0, int *end=0) const
Get the word at the specified cursor position.
void checkSpelling(int start=0, int end=-1)
Check the spelling.
QString nextChar(int num=1) const
Retreive the num-th next character.
bool checkWord(const QString &word) const
Check the specified word.
void moveWordEnd(MoveMode moveMode=MoveAnchor)
Move the cursor to the end of the current word. Cursor must be inside a word. This method correctly h...
void moveWordStart(MoveMode moveMode=MoveAnchor)
Move the cursor to the start of the current word. Cursor must be inside a word. This method correctly...
void redo()
Redo the last edit operation.
An abstract class providing spell checking support.
~TextEditChecker()
TextEditChecker object destructor.