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);
98 m_undoRedoInProgress =
false;
99 m_noSpellingProperty = -1;
109 setTextEdit(textEdit ?
new TextEditProxyT<QTextEdit>(textEdit) :
reinterpret_cast<TextEditProxyT<QTextEdit>*
>(0));
114 setTextEdit(textEdit ?
new TextEditProxyT<QPlainTextEdit>(textEdit) :
reinterpret_cast<TextEditProxyT<QPlainTextEdit>*
>(0));
119 if(!textEdit && m_textEdit){
120 disconnect(m_textEdit->object(), SIGNAL(destroyed()),
this, SLOT(slotDetachTextEdit()));
121 disconnect(m_textEdit->object(), SIGNAL(textChanged()),
this, SLOT(slotCheckDocumentChanged()));
122 disconnect(m_textEdit->object(), SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(slotShowContextMenu(QPoint)));
123 disconnect(m_textEdit->document(), SIGNAL(contentsChange(
int,
int,
int)),
this, SLOT(slotCheckRange(
int,
int,
int)));
124 m_textEdit->setContextMenuPolicy(m_oldContextMenuPolicy);
125 m_textEdit->removeEventFilter(
this);
128 QTextCursor cursor = m_textEdit->textCursor();
129 cursor.movePosition(QTextCursor::Start);
130 cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
131 QTextCharFormat fmt = cursor.charFormat();
132 QTextCharFormat defaultFormat = QTextCharFormat();
133 fmt.setFontUnderline(defaultFormat.fontUnderline());
134 fmt.setUnderlineColor(defaultFormat.underlineColor());
135 fmt.setUnderlineStyle(defaultFormat.underlineStyle());
136 cursor.setCharFormat(fmt);
138 bool undoWasEnabled = m_undoRedoStack != 0;
142 m_textEdit = textEdit;
144 m_document = m_textEdit->document();
145 connect(m_textEdit->object(), SIGNAL(destroyed()),
this, SLOT(slotDetachTextEdit()));
146 connect(m_textEdit->object(), SIGNAL(textChanged()),
this, SLOT(slotCheckDocumentChanged()));
147 connect(m_textEdit->object(), SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(slotShowContextMenu(QPoint)));
148 connect(m_textEdit->document(), SIGNAL(contentsChange(
int,
int,
int)),
this, SLOT(slotCheckRange(
int,
int,
int)));
149 m_oldContextMenuPolicy = m_textEdit->contextMenuPolicy();
151 m_textEdit->setContextMenuPolicy(Qt::CustomContextMenu);
152 m_textEdit->installEventFilter(
this);
157 bool TextEditChecker::eventFilter(QObject* obj, QEvent* event)
159 if(event->type() == QEvent::KeyPress){
160 QKeyEvent *keyEvent =
static_cast<QKeyEvent *
>(event);
161 if(keyEvent->key() == Qt::Key_Z && keyEvent->modifiers() == Qt::CTRL){
164 }
else if(keyEvent->key() == Qt::Key_Z && keyEvent->modifiers() == (Qt::CTRL | Qt::SHIFT)){
169 return QObject::eventFilter(obj, event);
175 QTextCursor tmpCursor(m_textEdit->textCursor());
176 tmpCursor.movePosition(QTextCursor::End);
177 end = tmpCursor.position();
181 m_textEdit->document()->blockSignals(
true);
183 qDebug() <<
"Checking range " << start <<
" - " << end;
185 QTextCharFormat errorFmt;
186 errorFmt.setFontUnderline(
true);
187 errorFmt.setUnderlineColor(Qt::red);
188 errorFmt.setUnderlineStyle(QTextCharFormat::WaveUnderline);
189 QTextCharFormat defaultFormat = QTextCharFormat();
192 cursor.beginEditBlock();
193 cursor.setPosition(start);
194 while(cursor.position() < end) {
197 QString word = cursor.selectedText();
198 if(noSpellingPropertySet(cursor)) {
200 qDebug() <<
"Skipping word:" << word <<
"(" << cursor.anchor() <<
"-" << cursor.position() <<
")";
203 qDebug() <<
"Checking word:" << word <<
"(" << cursor.anchor() <<
"-" << cursor.position() <<
"), correct:" << correct;
206 cursor.mergeCharFormat(errorFmt);
208 QTextCharFormat fmt = cursor.charFormat();
209 fmt.setFontUnderline(defaultFormat.fontUnderline());
210 fmt.setUnderlineColor(defaultFormat.underlineColor());
211 fmt.setUnderlineStyle(defaultFormat.underlineStyle());
212 cursor.setCharFormat(fmt);
216 cursor.movePosition(QTextCursor::NextCharacter);
219 cursor.endEditBlock();
221 m_textEdit->document()->blockSignals(
false);
224 bool TextEditChecker::noSpellingPropertySet(
const QTextCursor &cursor)
const
226 if(m_noSpellingProperty < QTextFormat::UserProperty) {
229 if(cursor.charFormat().intProperty(m_noSpellingProperty) == 1) {
232 const QList<QTextLayout::FormatRange>& formats = cursor.block().layout()->additionalFormats();
233 int pos = cursor.positionInBlock();
234 foreach(
const QTextLayout::FormatRange& range, formats) {
235 if(pos > range.start && pos <= range.start + range.length && range.format.intProperty(m_noSpellingProperty) == 1) {
245 m_undoRedoStack->clear();
251 if(enabled == (m_undoRedoStack != 0)){
255 delete m_undoRedoStack;
260 m_undoRedoStack =
new UndoRedoStack(m_textEdit);
269 cursor.setPosition(pos);
273 *start = cursor.anchor();
275 *end = cursor.position();
276 return cursor.selectedText();
281 QTextCursor cursor(m_textEdit->textCursor());
282 cursor.setPosition(start);
283 cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, end - start);
284 cursor.insertText(word);
287 void TextEditChecker::slotShowContextMenu(
const QPoint &pos)
289 QPoint globalPos = m_textEdit->mapToGlobal(pos);
290 QMenu* menu = m_textEdit->createStandardContextMenu();
291 int wordPos = m_textEdit->cursorForPosition(pos).position();
292 showContextMenu(menu, globalPos, wordPos);
295 void TextEditChecker::slotCheckDocumentChanged()
297 if(m_document != m_textEdit->document()) {
298 bool undoWasEnabled = m_undoRedoStack != 0;
301 disconnect(m_document, SIGNAL(contentsChange(
int,
int,
int)),
this, SLOT(slotCheckRange(
int,
int,
int)));
303 m_document = m_textEdit->document();
304 connect(m_document, SIGNAL(contentsChange(
int,
int,
int)),
this, SLOT(slotCheckRange(
int,
int,
int)));
309 void TextEditChecker::slotDetachTextEdit()
311 bool undoWasEnabled = m_undoRedoStack != 0;
323 void TextEditChecker::slotCheckRange(
int pos,
int removed,
int added)
325 if(m_undoRedoStack != 0 && !m_undoRedoInProgress){
326 m_undoRedoStack->handleContentsChange(pos, removed, added);
330 TextCursor c(m_textEdit->textCursor());
331 c.movePosition(QTextCursor::End);
332 int len = c.position();
333 if(pos == 0 && added > len){
341 c.setPosition(pos + added, QTextCursor::KeepAnchor);
342 c.moveWordEnd(QTextCursor::KeepAnchor);
343 QTextCharFormat fmt = c.charFormat();
344 QTextCharFormat defaultFormat = QTextCharFormat();
345 fmt.setFontUnderline(defaultFormat.fontUnderline());
346 fmt.setUnderlineColor(defaultFormat.underlineColor());
347 fmt.setUnderlineStyle(defaultFormat.underlineStyle());
348 c.setCharFormat(fmt);
355 if(m_undoRedoStack != 0){
356 m_undoRedoInProgress =
true;
357 m_undoRedoStack->undo();
358 m_textEdit->ensureCursorVisible();
359 m_undoRedoInProgress =
false;
365 if(m_undoRedoStack != 0){
366 m_undoRedoInProgress =
true;
367 m_undoRedoStack->redo();
368 m_textEdit->ensureCursorVisible();
369 m_undoRedoInProgress =
false;
An abstract class providing spell checking support.
bool checkWord(const QString &word) const
Check the specified word.
void moveWordStart(MoveMode moveMode=MoveAnchor)
Move the cursor to the start of the current word. Cursor must be inside a word. This method correctly...
QString prevChar(int num=1) const
Retreive the num-th previous character.
bool isWordChar(const QString &character) const
Returns whether the specified character is a word character.
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...
QString nextChar(int num=1) const
Retreive the num-th next character.
TextEditChecker(QObject *parent=0)
TextEditChecker object constructor.
void setUndoRedoEnabled(bool enabled)
Sets whether undo/redo functionality is enabled.
void clearUndoRedo()
Clears the undo/redo stack.
void setTextEdit(QTextEdit *textEdit)
Set the QTextEdit to check.
void checkSpelling(int start=0, int end=-1)
Check the spelling.
~TextEditChecker()
TextEditChecker object destructor.
void redo()
Redo the last edit operation.
void redoAvailable(bool available)
Emitted when the redo stak changes.
void undo()
Undo the last edit operation.
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.