Sonnet

spellcheckhighlighter.cpp
1// SPDX-FileCopyrightText: 2013 Aurélien Gâteau <agateau@kde.org>
2// SPDX-FileCopyrightText: 2020 Christian Mollekopf <mollekopf@kolabsystems.com>
3// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
4// SPDX-License-Identifier: LGPL-2.1-or-later
5
6#include "spellcheckhighlighter.h"
7#include "guesslanguage.h"
8#include "languagefilter_p.h"
9#include "loader_p.h"
10#include "settingsimpl_p.h"
11#include "speller.h"
12#include "tokenizer_p.h"
13
14#include "quick_debug.h"
15
16#include <QColor>
17#include <QHash>
18#include <QKeyEvent>
19#include <QMetaMethod>
20#include <QTextBoundaryFinder>
21#include <QTextCharFormat>
22#include <QTextCursor>
23#include <QTimer>
24#include <memory>
25
26using namespace Sonnet;
27
28// Cache of previously-determined languages (when using AutoDetectLanguage)
29// There is one such cache per block (paragraph)
30class LanguageCache : public QTextBlockUserData
31{
32public:
33 // Key: QPair<start, length>
34 // Value: language name
35 QMap<QPair<int, int>, QString> languages;
36
37 // Remove all cached language information after @p pos
38 void invalidate(int pos)
39 {
41 it.toBack();
42 while (it.hasPrevious()) {
43 it.previous();
44 if (it.key().first + it.key().second >= pos) {
45 it.remove();
46 } else {
47 break;
48 }
49 }
50 }
51
52 QString languageAtPos(int pos) const
53 {
54 // The data structure isn't really great for such lookups...
56 while (it.hasNext()) {
57 it.next();
58 if (it.key().first <= pos && it.key().first + it.key().second >= pos) {
59 return it.value();
60 }
61 }
62 return QString();
63 }
64};
65
66class HighlighterPrivate
67{
68public:
69 HighlighterPrivate(SpellcheckHighlighter *qq)
70 : q(qq)
71 {
72 tokenizer = std::make_unique<WordTokenizer>();
73 active = true;
74 automatic = false;
75 autoDetectLanguageDisabled = false;
76 connected = false;
77 wordCount = 0;
78 errorCount = 0;
79 intraWordEditing = false;
80 completeRehighlightRequired = false;
81 spellColor = spellColor.isValid() ? spellColor : Qt::red;
82 languageFilter = std::make_unique<LanguageFilter>(new SentenceTokenizer());
83
84 loader = Loader::openLoader();
85 loader->settings()->restore();
86
87 spellchecker = std::make_unique<Speller>();
88 spellCheckerFound = spellchecker->isValid();
89 rehighlightRequest = new QTimer(q);
91
92 if (!spellCheckerFound) {
93 return;
94 }
95
96 disablePercentage = loader->settings()->disablePercentageWordError();
97 disableWordCount = loader->settings()->disableWordErrorCount();
98
99 completeRehighlightRequired = true;
100 rehighlightRequest->setInterval(0);
101 rehighlightRequest->setSingleShot(true);
102 rehighlightRequest->start();
103
104 // Danger red from our color scheme
105 errorFormat.setForeground(spellColor);
106 errorFormat.setUnderlineColor(spellColor);
108
109 selectedErrorFormat.setForeground(spellColor);
110 auto bg = spellColor;
111 bg.setAlphaF(0.1);
112 selectedErrorFormat.setBackground(bg);
113 selectedErrorFormat.setUnderlineColor(spellColor);
115
116 quoteFormat.setForeground(QColor{"#7f8c8d"});
117 }
118
119 ~HighlighterPrivate();
120 std::unique_ptr<WordTokenizer> tokenizer;
121 std::unique_ptr<LanguageFilter> languageFilter;
122 Loader *loader = nullptr;
123 std::unique_ptr<Speller> spellchecker;
124
125 QTextCharFormat errorFormat;
126 QTextCharFormat selectedErrorFormat;
127 QTextCharFormat quoteFormat;
128 std::unique_ptr<Sonnet::GuessLanguage> languageGuesser;
129 QString selectedWord;
130 QQuickTextDocument *document = nullptr;
131 int cursorPosition;
132 int selectionStart;
133 int selectionEnd;
134
135 int autoCompleteBeginPosition = -1;
136 int autoCompleteEndPosition = -1;
137 int wordIsMisspelled = false;
138 bool active;
139 bool automatic;
140 bool autoDetectLanguageDisabled;
141 bool completeRehighlightRequired;
142 bool intraWordEditing;
143 bool spellCheckerFound; // cached d->dict->isValid() value
144 bool connected;
145 int disablePercentage = 0;
146 int disableWordCount = 0;
147 int wordCount, errorCount;
148 QTimer *rehighlightRequest = nullptr;
149 QColor spellColor;
150 SpellcheckHighlighter *const q;
151};
152
153HighlighterPrivate::~HighlighterPrivate()
154{
155}
156
157SpellcheckHighlighter::SpellcheckHighlighter(QObject *parent)
158 : QSyntaxHighlighter(parent)
159 , d(new HighlighterPrivate(this))
160{
161}
162
163SpellcheckHighlighter::~SpellcheckHighlighter()
164{
165 if (document()) {
166 disconnect(document(), nullptr, this, nullptr);
167 }
168}
169
171{
172 return d->spellCheckerFound;
173}
174
176{
177 if (d->completeRehighlightRequired) {
178 d->wordCount = 0;
179 d->errorCount = 0;
180 rehighlight();
181 } else {
182 // rehighlight the current para only (undo/redo safe)
183 QTextCursor cursor = textCursor();
184 if (cursor.hasSelection()) {
185 cursor.clearSelection();
186 }
187 cursor.insertText(QString());
188 }
189 // if (d->checksDone == d->checksRequested)
190 // d->completeRehighlightRequired = false;
192}
193
195{
196 return d->automatic;
197}
198
200{
201 return d->autoDetectLanguageDisabled;
202}
203
204bool SpellcheckHighlighter::intraWordEditing() const
205{
206 return d->intraWordEditing;
207}
208
209void SpellcheckHighlighter::setIntraWordEditing(bool editing)
210{
211 d->intraWordEditing = editing;
212}
213
214void SpellcheckHighlighter::setAutomatic(bool automatic)
215{
216 if (automatic == d->automatic) {
217 return;
218 }
219
220 d->automatic = automatic;
221 if (d->automatic) {
223 }
224}
225
226void SpellcheckHighlighter::setAutoDetectLanguageDisabled(bool autoDetectDisabled)
227{
228 d->autoDetectLanguageDisabled = autoDetectDisabled;
229}
230
232{
233 bool savedActive = d->active;
234
235 // don't disable just because 1 of 4 is misspelled.
236 if (d->automatic && d->wordCount >= 10) {
237 // tme = Too many errors
238 /* clang-format off */
239 bool tme = (d->errorCount >= d->disableWordCount)
240 && (d->errorCount * 100 >= d->disablePercentage * d->wordCount);
241 /* clang-format on */
242
243 if (d->active && tme) {
244 d->active = false;
245 } else if (!d->active && !tme) {
246 d->active = true;
247 }
248 }
249
250 if (d->active != savedActive) {
251 if (d->active) {
252 Q_EMIT activeChanged(tr("As-you-type spell checking enabled."));
253 } else {
254 qCDebug(SONNET_LOG_QUICK) << "Sonnet: Disabling spell checking, too many errors";
255 Q_EMIT activeChanged(
256 tr("Too many misspelled words. "
257 "As-you-type spell checking disabled."));
258 }
259
260 d->completeRehighlightRequired = true;
261 d->rehighlightRequest->setInterval(100);
262 d->rehighlightRequest->setSingleShot(true);
263 }
264}
265
266void SpellcheckHighlighter::setActive(bool active)
267{
268 if (active == d->active) {
269 return;
270 }
271 d->active = active;
272 Q_EMIT activeChanged();
273 rehighlight();
274
275 if (d->active) {
276 Q_EMIT activeChanged(tr("As-you-type spell checking enabled."));
277 } else {
278 Q_EMIT activeChanged(tr("As-you-type spell checking disabled."));
279 }
280}
281
283{
284 return d->active;
285}
286
287static bool hasNotEmptyText(const QString &text)
288{
289 for (int i = 0; i < text.length(); ++i) {
290 if (!text.at(i).isSpace()) {
291 return true;
292 }
293 }
294 return false;
295}
296
297void SpellcheckHighlighter::contentsChange(int pos, int add, int rem)
298{
299 // Invalidate the cache where the text has changed
300 const QTextBlock &lastBlock = document()->findBlock(pos + add - rem);
301 QTextBlock block = document()->findBlock(pos);
302 do {
303 LanguageCache *cache = dynamic_cast<LanguageCache *>(block.userData());
304 if (cache) {
305 cache->invalidate(pos - block.position());
306 }
307 block = block.next();
308 } while (block.isValid() && block < lastBlock);
309}
310
311void SpellcheckHighlighter::highlightBlock(const QString &text)
312{
313 if (!hasNotEmptyText(text) || !d->active || !d->spellCheckerFound) {
314 return;
315 }
316
317 // Avoid spellchecking quotes
318 if (text.isEmpty() || text.at(0) == QLatin1Char('>')) {
319 setFormat(0, text.length(), d->quoteFormat);
320 return;
321 }
322
323 if (!d->connected) {
324 connect(textDocument(), &QTextDocument::contentsChange, this, &SpellcheckHighlighter::contentsChange);
325 d->connected = true;
326 }
327 QTextCursor cursor = textCursor();
328 const int index = cursor.position() + 1;
329
330 const int lengthPosition = text.length() - 1;
331
332 if (index != lengthPosition //
333 || (lengthPosition > 0 && !text[lengthPosition - 1].isLetter())) {
334 d->languageFilter->setBuffer(text);
335
336 LanguageCache *cache = dynamic_cast<LanguageCache *>(currentBlockUserData());
337 if (!cache) {
338 cache = new LanguageCache;
340 }
341
342 const bool autodetectLanguage = d->spellchecker->testAttribute(Speller::AutoDetectLanguage);
343 while (d->languageFilter->hasNext()) {
344 Sonnet::Token sentence = d->languageFilter->next();
345 if (autodetectLanguage && !d->autoDetectLanguageDisabled) {
347 QPair<int, int> spos = QPair<int, int>(sentence.position(), sentence.length());
348 // try cache first
349 if (cache->languages.contains(spos)) {
350 lang = cache->languages.value(spos);
351 } else {
352 lang = d->languageFilter->language();
353 if (!d->languageFilter->isSpellcheckable()) {
354 lang.clear();
355 }
356 cache->languages[spos] = lang;
357 }
358 if (lang.isEmpty()) {
359 continue;
360 }
361 d->spellchecker->setLanguage(lang);
362 }
363
364 d->tokenizer->setBuffer(sentence.toString());
365 int offset = sentence.position();
366 while (d->tokenizer->hasNext()) {
367 Sonnet::Token word = d->tokenizer->next();
368 if (!d->tokenizer->isSpellcheckable()) {
369 continue;
370 }
371 ++d->wordCount;
372 if (d->spellchecker->isMisspelled(word.toString())) {
373 ++d->errorCount;
374 if (word.position() + offset <= cursor.position() && cursor.position() <= word.position() + offset + word.length()) {
375 setMisspelledSelected(word.position() + offset, word.length());
376 } else {
377 setMisspelled(word.position() + offset, word.length());
378 }
379 } else {
380 unsetMisspelled(word.position() + offset, word.length());
381 }
382 }
383 }
384 }
385 // QTimer::singleShot( 0, this, SLOT(checkWords()) );
387}
388
390{
391 if (!textDocument()) {
392 return {};
393 }
394
395 Q_EMIT changeCursorPosition(mousePosition, mousePosition);
396
397 QTextCursor cursor = textCursor();
398
399 QTextCursor cursorAtMouse(textDocument());
400 cursorAtMouse.setPosition(mousePosition);
401
402 // Check if the user clicked a selected word
403 const bool selectedWordClicked = cursor.hasSelection() && mousePosition >= cursor.selectionStart() && mousePosition <= cursor.selectionEnd();
404
405 // Get the word under the (mouse-)cursor and see if it is misspelled.
406 // Don't include apostrophes at the start/end of the word in the selection.
408 wordSelectCursor.clearSelection();
410 d->selectedWord = wordSelectCursor.selectedText();
411
412 // Clear the selection again, we re-select it below (without the apostrophes).
413 wordSelectCursor.setPosition(wordSelectCursor.position() - d->selectedWord.size());
414 if (d->selectedWord.startsWith(QLatin1Char('\'')) || d->selectedWord.startsWith(QLatin1Char('\"'))) {
415 d->selectedWord = d->selectedWord.right(d->selectedWord.size() - 1);
417 }
418 if (d->selectedWord.endsWith(QLatin1Char('\'')) || d->selectedWord.endsWith(QLatin1Char('\"'))) {
419 d->selectedWord.chop(1);
420 }
421
422 wordSelectCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, d->selectedWord.size());
423
424 int endSelection = wordSelectCursor.selectionEnd();
425 Q_EMIT wordUnderMouseChanged();
426
427 bool isMouseCursorInsideWord = true;
428 if ((mousePosition < wordSelectCursor.selectionStart() || mousePosition >= wordSelectCursor.selectionEnd()) //
429 && (d->selectedWord.length() > 1)) {
431 }
432
433 wordSelectCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, d->selectedWord.size());
434
435 d->wordIsMisspelled = isMouseCursorInsideWord && !d->selectedWord.isEmpty() && d->spellchecker->isMisspelled(d->selectedWord);
436 Q_EMIT wordIsMisspelledChanged();
437
438 if (!d->wordIsMisspelled || selectedWordClicked) {
439 return QStringList{};
440 }
441
442 LanguageCache *cache = dynamic_cast<LanguageCache *>(cursor.block().userData());
443 if (cache) {
444 const QString cachedLanguage = cache->languageAtPos(cursor.positionInBlock());
445 if (!cachedLanguage.isEmpty()) {
446 d->spellchecker->setLanguage(cachedLanguage);
447 }
448 }
449 QStringList suggestions = d->spellchecker->suggest(d->selectedWord);
450 if (max >= 0 && suggestions.count() > max) {
451 suggestions = suggestions.mid(0, max);
452 }
453
454 return suggestions;
455}
456
458{
459 return d->spellchecker->language();
460}
461
463{
464 QString prevLang = d->spellchecker->language();
465 d->spellchecker->setLanguage(lang);
466 d->spellCheckerFound = d->spellchecker->isValid();
467 if (!d->spellCheckerFound) {
468 qCDebug(SONNET_LOG_QUICK) << "No dictionary for \"" << lang << "\" staying with the current language.";
469 d->spellchecker->setLanguage(prevLang);
470 return;
471 }
472 d->wordCount = 0;
473 d->errorCount = 0;
474 if (d->automatic || d->active) {
475 d->rehighlightRequest->start(0);
476 }
477}
478
479void SpellcheckHighlighter::setMisspelled(int start, int count)
480{
481 setFormat(start, count, d->errorFormat);
482}
483
484void SpellcheckHighlighter::setMisspelledSelected(int start, int count)
485{
486 setFormat(start, count, d->selectedErrorFormat);
487}
488
489void SpellcheckHighlighter::unsetMisspelled(int start, int count)
490{
492}
493
495{
496 d->spellchecker->addToPersonal(word);
497 rehighlight();
498}
499
501{
502 d->spellchecker->addToSession(word);
503 rehighlight();
504}
505
506void SpellcheckHighlighter::replaceWord(const QString &replacement, int at)
507{
509 textCursorUnderUserCursor.setPosition(at == -1 ? d->cursorPosition : at);
510
511 // Get the word under the cursor
513 wordSelectCursor.clearSelection();
515
516 auto selectedWord = wordSelectCursor.selectedText();
517
518 // Trim leading and trailing apostrophes
519 wordSelectCursor.setPosition(wordSelectCursor.position() - selectedWord.size());
520 if (selectedWord.startsWith(QLatin1Char('\'')) || selectedWord.startsWith(QLatin1Char('\"'))) {
521 selectedWord = selectedWord.right(selectedWord.size() - 1);
523 }
524 if (selectedWord.endsWith(QLatin1Char('\'')) || d->selectedWord.endsWith(QLatin1Char('\"'))) {
525 selectedWord.chop(1);
526 }
527
528 wordSelectCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, d->selectedWord.size());
529
530 wordSelectCursor.insertText(replacement);
531}
532
533QQuickTextDocument *SpellcheckHighlighter::quickDocument() const
534{
535 return d->document;
536}
537
538void SpellcheckHighlighter::setQuickDocument(QQuickTextDocument *document)
539{
540 if (document == d->document) {
541 return;
542 }
543
544 if (d->document) {
545 d->document->parent()->removeEventFilter(this);
546 d->document->textDocument()->disconnect(this);
547 }
548 d->document = document;
549 document->parent()->installEventFilter(this);
550 setDocument(document->textDocument());
551 Q_EMIT documentChanged();
552}
553
555{
556 d->connected = false;
558}
559
561{
562 return d->cursorPosition;
563}
564
565void SpellcheckHighlighter::setCursorPosition(int position)
566{
567 if (position == d->cursorPosition) {
568 return;
569 }
570
571 d->cursorPosition = position;
572 d->rehighlightRequest->start(0);
573 Q_EMIT cursorPositionChanged();
574}
575
577{
578 return d->selectionStart;
579}
580
581void SpellcheckHighlighter::setSelectionStart(int position)
582{
583 if (position == d->selectionStart) {
584 return;
585 }
586
587 d->selectionStart = position;
588 Q_EMIT selectionStartChanged();
589}
590
592{
593 return d->selectionEnd;
594}
595
596void SpellcheckHighlighter::setSelectionEnd(int position)
597{
598 if (position == d->selectionEnd) {
599 return;
600 }
601
602 d->selectionEnd = position;
603 Q_EMIT selectionEndChanged();
604}
605
606QTextCursor SpellcheckHighlighter::textCursor() const
607{
608 QTextDocument *doc = textDocument();
609 if (!doc) {
610 return QTextCursor();
611 }
612
613 QTextCursor cursor(doc);
614 if (d->selectionStart != d->selectionEnd) {
615 cursor.setPosition(d->selectionStart);
616 cursor.setPosition(d->selectionEnd, QTextCursor::KeepAnchor);
617 } else {
618 cursor.setPosition(d->cursorPosition);
619 }
620 return cursor;
621}
622
623QTextDocument *SpellcheckHighlighter::textDocument() const
624{
625 if (!d->document) {
626 return nullptr;
627 }
628
629 return d->document->textDocument();
630}
631
633{
634 return d->wordIsMisspelled;
635}
636
638{
639 return d->selectedWord;
640}
641
643{
644 return d->spellColor;
645}
646
647void SpellcheckHighlighter::setMisspelledColor(const QColor &color)
648{
649 if (color == d->spellColor) {
650 return;
651 }
652 d->spellColor = color;
653 Q_EMIT misspelledColorChanged();
654}
655
657{
658 return d->spellchecker->isMisspelled(word);
659}
660
661bool SpellcheckHighlighter::eventFilter(QObject *o, QEvent *e)
662{
663 if (!d->spellCheckerFound) {
664 return false;
665 }
666 if (o == d->document->parent() && (e->type() == QEvent::KeyPress)) {
667 QKeyEvent *k = static_cast<QKeyEvent *>(e);
668
669 if (k->key() == Qt::Key_Enter || k->key() == Qt::Key_Return || k->key() == Qt::Key_Up || k->key() == Qt::Key_Down || k->key() == Qt::Key_Left
670 || k->key() == Qt::Key_Right || k->key() == Qt::Key_PageUp || k->key() == Qt::Key_PageDown || k->key() == Qt::Key_Home || k->key() == Qt::Key_End
671 || (k->modifiers() == Qt::ControlModifier
672 && (k->key() == Qt::Key_A || k->key() == Qt::Key_B || k->key() == Qt::Key_E || k->key() == Qt::Key_N
673 || k->key() == Qt::Key_P))) { /* clang-format on */
674 if (intraWordEditing()) {
675 setIntraWordEditing(false);
676 d->completeRehighlightRequired = true;
677 d->rehighlightRequest->setInterval(500);
678 d->rehighlightRequest->setSingleShot(true);
679 d->rehighlightRequest->start();
680 }
681 } else {
682 setIntraWordEditing(true);
683 }
684 if (k->key() == Qt::Key_Space //
685 || k->key() == Qt::Key_Enter //
686 || k->key() == Qt::Key_Return) {
688 }
689 } else if (d->document && e->type() == QEvent::MouseButtonPress) {
690 if (intraWordEditing()) {
691 setIntraWordEditing(false);
692 d->completeRehighlightRequired = true;
693 d->rehighlightRequest->setInterval(0);
694 d->rehighlightRequest->setSingleShot(true);
695 d->rehighlightRequest->start();
696 }
697 }
698 return false;
699}
700
701#include "moc_spellcheckhighlighter.cpp"
bool addToSession(const QString &word)
Adds word to the words recognizable in the current session.
Definition speller.cpp:136
bool isMisspelled(const QString &word) const
Checks the given word.
Definition speller.cpp:96
QStringList suggest(const QString &word) const
Fetches suggestions for the word.
Definition speller.cpp:104
QString language() const
Definition speller.cpp:144
bool addToPersonal(const QString &word)
Adds word to the list of of personal words.
Definition speller.cpp:128
bool isValid() const
Definition speller.cpp:238
void setLanguage(const QString &lang)
Sets the language supported by this speller.
Definition speller.cpp:243
The Sonnet Highlighter class, used for drawing red lines in text fields when detecting spelling mista...
void slotRehighlight()
Force a new highlighting.
bool wordIsMisspelled
This property holds whether the current word under the mouse is misspelled.
Q_INVOKABLE void ignoreWord(const QString &word)
Ignores the given word.
int selectionStart
This property holds the start of the selection.
void setCurrentLanguage(const QString &language)
Set language to use for spell checking.
QString currentLanguage
This property holds the current language used for spell checking.
QString wordUnderMouse
This property holds the current word under the mouse.
QML_ELEMENTQQuickTextDocument * document
This property holds the underneath document from a QML TextEdit.
void setDocument(QTextDocument *document)
Set a new QTextDocument for this highlighter to operate on.
Q_INVOKABLE void replaceWord(const QString &word, int at=-1)
Replace word at the current cursor position, or.
int selectionEnd
This property holds the end of the selection.
int cursorPosition
This property holds the current cursor position.
bool autoDetectLanguageDisabled
This property holds whether the automatic language detection is disabled overriding the Sonnet global...
bool active
This property holds whether spell checking is enabled.
Q_INVOKABLE QStringList suggestions(int position, int max=5)
Returns a list of suggested replacements for the given misspelled word.
void slotAutoDetection()
Run auto detection, disabling spell checking if too many errors are found.
QColor misspelledColor
This property holds the spell color.
Q_INVOKABLE bool isWordMisspelled(const QString &word)
Checks if a given word is marked as misspelled by the highlighter.
bool automatic
This property holds whether spell checking is automatically disabled if there's too many errors.
bool spellCheckerFound
This property holds whether a spell checking backend with support for the currentLanguage was found.
Q_INVOKABLE void addWordToDictionary(const QString &word)
Adds the given word permanently to the dictionary.
Q_SCRIPTABLE Q_NOREPLY void start()
The sonnet namespace.
bool isSpace(char32_t ucs4)
bool isValid() const const
void setAlphaF(float alpha)
Type type() const const
qsizetype count() const const
QList< T > mid(qsizetype pos, qsizetype length) const const
bool contains(const Key &key) const const
T value(const Key &key, const T &defaultValue) const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
T qobject_cast(QObject *object)
QString tr(const char *sourceText, const char *disambiguation, int n)
const QChar at(qsizetype position) const const
bool isEmpty() const const
qsizetype length() const const
QTextBlockUserData * currentBlockUserData() const const
void setCurrentBlockState(int newState)
void setCurrentBlockUserData(QTextBlockUserData *data)
void setDocument(QTextDocument *doc)
void setFormat(int start, int count, const QColor &color)
Key_Enter
ControlModifier
bool isValid() const const
QTextBlock next() const const
int position() const const
QTextBlockUserData * userData() const const
void setUnderlineColor(const QColor &color)
void setUnderlineStyle(UnderlineStyle style)
QTextBlock block() const const
void clearSelection()
bool hasSelection() const const
void insertText(const QString &text)
int position() const const
int positionInBlock() const const
int selectionEnd() const const
int selectionStart() const const
void setPosition(int pos, MoveMode m)
void contentsChange(int position, int charsRemoved, int charsAdded)
void setBackground(const QBrush &brush)
void setForeground(const QBrush &brush)
void setInterval(int msec)
void setSingleShot(bool singleShot)
void start()
void timeout()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:15:10 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.