8#include "spellcheckdecorator.h"
11#include <highlighter.h>
14#include <QContextMenuEvent>
16#include <QPlainTextEdit>
21class SpellCheckDecoratorPrivate
24 SpellCheckDecoratorPrivate(SpellCheckDecorator *installer, QPlainTextEdit *textEdit)
26 , m_plainTextEdit(textEdit)
28 createDefaultHighlighter();
30 m_plainTextEdit->installEventFilter(q);
32 m_plainTextEdit->viewport()->installEventFilter(q);
35 SpellCheckDecoratorPrivate(SpellCheckDecorator *installer, QTextEdit *textEdit)
37 , m_textEdit(textEdit)
39 createDefaultHighlighter();
41 m_textEdit->installEventFilter(q);
43 m_textEdit->viewport()->installEventFilter(q);
46 ~SpellCheckDecoratorPrivate()
48 if (m_plainTextEdit) {
49 m_plainTextEdit->removeEventFilter(q);
50 m_plainTextEdit->viewport()->removeEventFilter(q);
53 m_textEdit->removeEventFilter(q);
54 m_textEdit->viewport()->removeEventFilter(q);
58 bool onContextMenuEvent(QContextMenuEvent *event);
59 void execSuggestionMenu(
const QPoint &pos,
const QString &word,
const QTextCursor &cursor);
60 void createDefaultHighlighter();
62 SpellCheckDecorator *
const q;
63 QTextEdit *m_textEdit =
nullptr;
64 QPlainTextEdit *m_plainTextEdit =
nullptr;
65 Highlighter *m_highlighter =
nullptr;
68bool SpellCheckDecoratorPrivate::onContextMenuEvent(QContextMenuEvent *event)
71 createDefaultHighlighter();
75 QTextCursor cursorAtMouse;
77 cursorAtMouse = m_textEdit->cursorForPosition(
event->pos());
79 cursorAtMouse = m_plainTextEdit->cursorForPosition(
event->pos());
81 const int mousePos = cursorAtMouse.
position();
84 cursor = m_textEdit->textCursor();
86 cursor = m_plainTextEdit->textCursor();
98 QTextCursor wordSelectCursor(cursorAtMouse);
99 wordSelectCursor.clearSelection();
101 QString selectedWord = wordSelectCursor.selectedText();
103 bool isMouseCursorInsideWord =
true;
104 if ((mousePos < wordSelectCursor.selectionStart() || mousePos >= wordSelectCursor.selectionEnd())
105 && (selectedWord.
length() > 1)) {
106 isMouseCursorInsideWord =
false;
110 wordSelectCursor.setPosition(wordSelectCursor.position() - selectedWord.
size());
112 selectedWord = selectedWord.
right(selectedWord.
size() - 1);
115 if (selectedWord.
endsWith(QLatin1Char(
'\'')) || selectedWord.
endsWith(QLatin1Char(
'\"'))) {
116 selectedWord.
chop(1);
122 const bool wordIsMisspelled = isMouseCursorInsideWord
124 && m_highlighter->isActive()
126 && m_highlighter->isWordMisspelled(selectedWord);
133 bool checkBlock = q->isSpellCheckingEnabledForBlock(cursorAtMouse.
block().
text());
134 if (!selectedWordClicked) {
135 if (wordIsMisspelled && checkBlock) {
137 m_textEdit->setTextCursor(wordSelectCursor);
139 m_plainTextEdit->setTextCursor(wordSelectCursor);
143 m_textEdit->setTextCursor(cursorAtMouse);
145 m_plainTextEdit->setTextCursor(cursorAtMouse);
149 cursor = m_textEdit->textCursor();
151 cursor = m_plainTextEdit->textCursor();
157 if (!wordIsMisspelled || selectedWordClicked || !checkBlock) {
160 execSuggestionMenu(
event->globalPos(), selectedWord, cursor);
164void SpellCheckDecoratorPrivate::execSuggestionMenu(
const QPoint &pos,
const QString &selectedWord,
const QTextCursor &_cursor)
166 QTextCursor cursor = _cursor;
170 const QStringList reps = m_highlighter->suggestionsForWord(selectedWord, cursor);
176 for (QStringList::const_iterator it = reps.
constBegin(); it != end; ++it) {
186 const QAction *selectedAction = menu.
exec(pos);
188 if (selectedAction) {
192 if (selectedAction == ignoreAction) {
193 m_highlighter->ignoreWord(selectedWord);
194 m_highlighter->rehighlight();
195 }
else if (selectedAction == addToDictAction) {
196 m_highlighter->addWordToDictionary(selectedWord);
197 m_highlighter->rehighlight();
201 const QString replacement = selectedAction->
text();
202 Q_ASSERT(reps.
contains(replacement));
205 m_textEdit->setTextCursor(cursor);
207 m_plainTextEdit->setTextCursor(cursor);
213void SpellCheckDecoratorPrivate::createDefaultHighlighter()
216 m_highlighter =
new Highlighter(m_textEdit);
218 m_highlighter =
new Highlighter(m_plainTextEdit);
224 , d(std::make_unique<SpellCheckDecoratorPrivate>(this, textEdit))
230 , d(std::make_unique<SpellCheckDecoratorPrivate>(this, textEdit))
234SpellCheckDecorator::~SpellCheckDecorator() =
default;
243 if (!d->m_highlighter) {
244 d->createDefaultHighlighter();
246 return d->m_highlighter;
249bool SpellCheckDecorator::eventFilter(
QObject * ,
QEvent *event)
261 return d->m_textEdit->isEnabled();
263 return d->m_plainTextEdit->isEnabled();
268#include "moc_spellcheckdecorator.cpp"
The Sonnet Highlighter class, used for drawing pretty red lines in text fields.
virtual bool isSpellCheckingEnabledForBlock(const QString &textBlock) const
Returns true if the spell checking should be enabled for a given block of text The default implementa...
SpellCheckDecorator(QTextEdit *textEdit)
Creates a spell-check decorator.
Highlighter * highlighter() const
Returns the hightlighter used by the decorator.
void setHighlighter(Highlighter *highlighter)
Set a custom highlighter on the decorator.
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
const QList< QKeySequence > & end()
const_iterator constBegin() const const
const_iterator constEnd() const const
bool isEmpty() const const
virtual bool event(QEvent *e)
QString tr(const char *sourceText, const char *disambiguation, int n)
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype length() const const
QString right(qsizetype n) const const
qsizetype size() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QString text() const const
QTextBlock block() const const
bool hasSelection() const const
void insertText(const QString &text)
int position() const const
int selectionEnd() const const
int selectionStart() const const