• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDEUI

  • kdeui
  • sonnet
highlighter.cpp
Go to the documentation of this file.
1
23#include "highlighter.h"
24#include "highlighter.moc"
25
26#include "speller.h"
27#include "loader_p.h"
28#include "filter_p.h"
29#include "settings_p.h"
30
31#include <kconfig.h>
32#include <kdebug.h>
33#include <klocale.h>
34#include <kmessagebox.h>
35
36#include <QTextEdit>
37#include <QTextCharFormat>
38#include <QTimer>
39#include <QColor>
40#include <QHash>
41#include <QTextCursor>
42#include <QEvent>
43#include <QKeyEvent>
44#include <QApplication>
45
46namespace Sonnet {
47
48class Highlighter::Private
49{
50public:
51 ~Private();
52 Filter *filter;
53 Loader *loader;
54 Speller *dict;
55 QHash<QString, Speller*> dictCache;
56 QTextEdit *edit;
57 bool active;
58 bool automatic;
59 bool completeRehighlightRequired;
60 bool intraWordEditing;
61 bool spellCheckerFound; //cached d->dict->isValid() value
62 int disablePercentage;
63 int disableWordCount;
64 int wordCount, errorCount;
65 QTimer *rehighlightRequest;
66 QColor spellColor;
67 int suggestionListeners; // #of connections for the newSuggestions signal
68};
69
70Highlighter::Private::~Private()
71{
72 qDeleteAll(dictCache);
73 delete filter;
74}
75
76Highlighter::Highlighter(QTextEdit *textEdit,
77 const QString& configFile,
78 const QColor& _col)
79 : QSyntaxHighlighter(textEdit),
80 d(new Private)
81{
82 d->filter = Filter::defaultFilter();
83 d->edit = textEdit;
84 d->active = true;
85 d->automatic = true;
86 d->wordCount = 0;
87 d->errorCount = 0;
88 d->intraWordEditing = false;
89 d->completeRehighlightRequired = false;
90 d->spellColor = _col.isValid() ? _col : Qt::red;
91 d->suggestionListeners = 0;
92
93 textEdit->installEventFilter( this );
94 textEdit->viewport()->installEventFilter( this );
95
96 d->loader = Loader::openLoader();
97
98 //Do not load an empty settings file as it will cause the spellchecker to fail
99 //if the KGlobal::locale()->language() (default value) spellchecker is not installed,
100 //and we have a global sonnetrc file with a spellcheck lang installed which could be used.
101 if (!configFile.isEmpty()) {
102 KConfig conf(configFile);
103 if (conf.hasGroup("Spelling")) {
104 d->loader->settings()->restore(&conf);
105 d->filter->setSettings(d->loader->settings());
106 }
107 }
108
109 d->dict = new Sonnet::Speller();
110 d->spellCheckerFound = d->dict->isValid();
111 d->rehighlightRequest = new QTimer(this);
112 connect( d->rehighlightRequest, SIGNAL(timeout()),
113 this, SLOT(slotRehighlight()));
114
115 if(!d->spellCheckerFound)
116 return;
117
118 d->dictCache.insert(d->dict->language(), d->dict);
119
120 d->disablePercentage = d->loader->settings()->disablePercentageWordError();
121 d->disableWordCount = d->loader->settings()->disableWordErrorCount();
122
123 //Add kde personal word
124 const QStringList l = Highlighter::personalWords();
125 for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it ) {
126 d->dict->addToSession( *it );
127 }
128 d->completeRehighlightRequired = true;
129 d->rehighlightRequest->setInterval(0);
130 d->rehighlightRequest->setSingleShot(true);
131 d->rehighlightRequest->start();
132}
133
134Highlighter::~Highlighter()
135{
136 delete d;
137}
138
139bool Highlighter::spellCheckerFound() const
140{
141 return d->spellCheckerFound;
142}
143
144// Since figuring out spell correction suggestions is extremely costly,
145// we keep track of whether the user actually wants some, and only offer them
146// in that case
147void Highlighter::connectNotify(const char* signal)
148{
149 if (QLatin1String(signal) == SIGNAL(newSuggestions(QString,QStringList)))
150 ++d->suggestionListeners;
151 QSyntaxHighlighter::connectNotify(signal);
152}
153
154void Highlighter::disconnectNotify(const char* signal)
155{
156 if (QLatin1String(signal) == SIGNAL(newSuggestions(QString,QStringList)))
157 --d->suggestionListeners;
158 QSyntaxHighlighter::disconnectNotify(signal);
159}
160
161void Highlighter::slotRehighlight()
162{
163 kDebug(0) << "Highlighter::slotRehighlight()";
164 if (d->completeRehighlightRequired) {
165 d->wordCount = 0;
166 d->errorCount = 0;
167 rehighlight();
168
169 } else {
170 //rehighlight the current para only (undo/redo safe)
171 QTextCursor cursor = d->edit->textCursor();
172 cursor.insertText( "" );
173 }
174 //if (d->checksDone == d->checksRequested)
175 //d->completeRehighlightRequired = false;
176 QTimer::singleShot( 0, this, SLOT(slotAutoDetection()));
177}
178
179
180QStringList Highlighter::personalWords()
181{
182 QStringList l;
183 l.append( "KMail" );
184 l.append( "KOrganizer" );
185 l.append( "KAddressBook" );
186 l.append( "KHTML" );
187 l.append( "KIO" );
188 l.append( "KJS" );
189 l.append( "Konqueror" );
190 l.append( "Sonnet" );
191 l.append( "Kontact" );
192 l.append( "Qt" );
193 return l;
194}
195
196bool Highlighter::automatic() const
197{
198 return d->automatic;
199}
200
201bool Highlighter::intraWordEditing() const
202{
203 return d->intraWordEditing;
204}
205
206void Highlighter::setIntraWordEditing( bool editing )
207{
208 d->intraWordEditing = editing;
209}
210
211
212void Highlighter::setAutomatic( bool automatic )
213{
214 if ( automatic == d->automatic )
215 return;
216
217 d->automatic = automatic;
218 if ( d->automatic )
219 slotAutoDetection();
220}
221
222void Highlighter::slotAutoDetection()
223{
224 bool savedActive = d->active;
225
226 //don't disable just because 1 of 4 is misspelled.
227 if (d->automatic && d->wordCount >= 10) {
228 // tme = Too many errors
229 bool tme = (d->errorCount >= d->disableWordCount) && (
230 d->errorCount * 100 >= d->disablePercentage * d->wordCount);
231 if (d->active && tme) {
232 d->active = false;
233 } else if (!d->active && !tme) {
234 d->active = true;
235 }
236 }
237
238 if (d->active != savedActive) {
239 if (d->active) {
240 emit activeChanged(i18n("As-you-type spell checking enabled."));
241 } else {
242 emit activeChanged(i18n( "Too many misspelled words. "
243 "As-you-type spell checking disabled."));
244 }
245
246 d->completeRehighlightRequired = true;
247 d->rehighlightRequest->setInterval(100);
248 d->rehighlightRequest->setSingleShot(true);
249 kDebug()<<" Highlighter::slotAutoDetection :"<<d->active;
250 }
251
252}
253
254void Highlighter::setActive( bool active )
255{
256 if ( active == d->active )
257 return;
258 d->active = active;
259 rehighlight();
260
261
262 if ( d->active )
263 emit activeChanged( i18n("As-you-type spell checking enabled.") );
264 else
265 emit activeChanged( i18n("As-you-type spell checking disabled.") );
266}
267
268bool Highlighter::isActive() const
269{
270 return d->active;
271}
272
273void Highlighter::highlightBlock(const QString &text)
274{
275 if (text.isEmpty() || !d->active || !d->spellCheckerFound)
276 return;
277
278 d->filter->setBuffer( text );
279 Word w = d->filter->nextWord();
280 while ( !w.end ) {
281 ++d->wordCount;
282 if (d->dict->isMisspelled(w.word)) {
283 ++d->errorCount;
284 setMisspelled(w.start, w.word.length());
285 if (d->suggestionListeners)
286 emit newSuggestions(w.word, d->dict->suggest(w.word));
287 } else
288 unsetMisspelled(w.start, w.word.length());
289 w = d->filter->nextWord();
290 }
291 //QTimer::singleShot( 0, this, SLOT(checkWords()) );
292 setCurrentBlockState(0);
293}
294
295QString Highlighter::currentLanguage() const
296{
297 return d->dict->language();
298}
299
300void Highlighter::setCurrentLanguage(const QString &lang)
301{
302 if (!d->dictCache.contains(lang)) {
303 d->dict = new Speller(*d->dict);
304 d->dict->setLanguage(lang);
305 if (d->dict->isValid()) {
306 d->dictCache.insert(lang, d->dict);
307 } else {
308 d->spellCheckerFound = false;
309 kDebug()<<"No dictionary for \""
310 <<lang
311 <<"\" staying with the current language."
312 <<endl;
313 return;
314 }
315 }
316 d->dict = d->dictCache[lang];
317 d->spellCheckerFound = d->dict->isValid();
318 d->wordCount = 0;
319 d->errorCount = 0;
320 if (d->automatic)
321 slotAutoDetection();
322}
323
324void Highlighter::setMisspelled(int start, int count)
325{
326 QTextCharFormat format;
327 format.setFontUnderline(true);
328 format.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
329 format.setUnderlineColor(d->spellColor);
330 setFormat(start, count, format);
331}
332
333void Highlighter::unsetMisspelled( int start, int count )
334{
335 setFormat(start, count, QTextCharFormat());
336}
337
338bool Highlighter::eventFilter( QObject *o, QEvent *e)
339{
340#if 0
341 if (o == textEdit() && (e->type() == QEvent::FocusIn)) {
342 if ( d->globalConfig ) {
343 QString skey = spellKey();
344 if ( d->spell && d->spellKey != skey ) {
345 d->spellKey = skey;
346 KDictSpellingHighlighter::dictionaryChanged();
347 }
348 }
349 }
350#endif
351 if (!d->spellCheckerFound)
352 return false;
353 if (o == d->edit && (e->type() == QEvent::KeyPress)) {
354 QKeyEvent *k = static_cast<QKeyEvent *>(e);
355 //d->autoReady = true;
356 if (d->rehighlightRequest->isActive()) // try to stay out of the users way
357 d->rehighlightRequest->start( 500 );
358 if ( k->key() == Qt::Key_Enter ||
359 k->key() == Qt::Key_Return ||
360 k->key() == Qt::Key_Up ||
361 k->key() == Qt::Key_Down ||
362 k->key() == Qt::Key_Left ||
363 k->key() == Qt::Key_Right ||
364 k->key() == Qt::Key_PageUp ||
365 k->key() == Qt::Key_PageDown ||
366 k->key() == Qt::Key_Home ||
367 k->key() == Qt::Key_End ||
368 (( k->modifiers()== Qt::ControlModifier ) &&
369 ((k->key() == Qt::Key_A) ||
370 (k->key() == Qt::Key_B) ||
371 (k->key() == Qt::Key_E) ||
372 (k->key() == Qt::Key_N) ||
373 (k->key() == Qt::Key_P))) ) {
374 if ( intraWordEditing() ) {
375 setIntraWordEditing( false );
376 d->completeRehighlightRequired = true;
377 d->rehighlightRequest->setInterval(500);
378 d->rehighlightRequest->setSingleShot(true);
379 d->rehighlightRequest->start();
380 }
381#if 0
382 if (d->checksDone != d->checksRequested) {
383 // Handle possible change of paragraph while
384 // words are pending spell checking
385 d->completeRehighlightRequired = true;
386 d->rehighlightRequest->start( 500, true );
387 }
388#endif
389 } else {
390 setIntraWordEditing( true );
391 }
392 if ( k->key() == Qt::Key_Space ||
393 k->key() == Qt::Key_Enter ||
394 k->key() == Qt::Key_Return ) {
395 QTimer::singleShot( 0, this, SLOT(slotAutoDetection()));
396 }
397 }
398
399 else if ( o == d->edit->viewport() &&
400 ( e->type() == QEvent::MouseButtonPress )) {
401 //d->autoReady = true;
402 if ( intraWordEditing() ) {
403 setIntraWordEditing( false );
404 d->completeRehighlightRequired = true;
405 d->rehighlightRequest->setInterval(0);
406 d->rehighlightRequest->setSingleShot(true);
407 d->rehighlightRequest->start();
408 }
409 }
410 return false;
411}
412
413void Highlighter::addWordToDictionary(const QString &word)
414{
415 d->dict->addToPersonal(word);
416}
417
418void Highlighter::ignoreWord(const QString &word)
419{
420 d->dict->addToSession(word);
421}
422
423QStringList Highlighter::suggestionsForWord(const QString &word, int max)
424{
425 QStringList suggestions = d->dict->suggest(word);
426 if ( max != -1 ) {
427 while ( suggestions.count() > max )
428 suggestions.removeLast();
429 }
430 return suggestions;
431}
432
433bool Highlighter::isWordMisspelled(const QString &word)
434{
435 return d->dict->isMisspelled(word);
436}
437
438void Highlighter::setMisspelledColor(const QColor &color)
439{
440 d->spellColor = color;
441}
442
443bool Highlighter::checkerEnabledByDefault() const
444{
445 return d->loader->settings()->checkerEnabledByDefault();
446}
447
448
449}
KConfigBase::hasGroup
bool hasGroup(const char *group) const
KConfig
QHash
QObject
QSyntaxHighlighter
QTextEdit
Sonnet::Filter::defaultFilter
static Filter * defaultFilter()
Sonnet::Highlighter::slotAutoDetection
void slotAutoDetection()
Definition: highlighter.cpp:222
Sonnet::Highlighter::~Highlighter
~Highlighter()
Definition: highlighter.cpp:134
Sonnet::Highlighter::addWordToDictionary
void addWordToDictionary(const QString &word)
Adds the given word permanently to the dictionary.
Definition: highlighter.cpp:413
Sonnet::Highlighter::slotRehighlight
void slotRehighlight()
Definition: highlighter.cpp:161
Sonnet::Highlighter::activeChanged
void activeChanged(const QString &description)
Emitted when as-you-type spell checking is enabled or disabled.
Sonnet::Highlighter::Highlighter
Highlighter(QTextEdit *textEdit, const QString &configFile=QString(), const QColor &col=QColor())
Definition: highlighter.cpp:76
Sonnet::Highlighter::personalWords
static QStringList personalWords()
Definition: highlighter.cpp:180
Sonnet::Highlighter::currentLanguage
QString currentLanguage() const
Definition: highlighter.cpp:295
Sonnet::Highlighter::ignoreWord
void ignoreWord(const QString &word)
Ignores the given word.
Definition: highlighter.cpp:418
Sonnet::Highlighter::isActive
bool isActive() const
Returns the state of spell checking.
Definition: highlighter.cpp:268
Sonnet::Highlighter::isWordMisspelled
bool isWordMisspelled(const QString &word)
Checks if a given word is marked as misspelled by the highlighter.
Definition: highlighter.cpp:433
Sonnet::Highlighter::suggestionsForWord
QStringList suggestionsForWord(const QString &word, int max=10)
Returns a list of suggested replacements for the given misspelled word.
Definition: highlighter.cpp:423
Sonnet::Highlighter::eventFilter
bool eventFilter(QObject *o, QEvent *e)
Definition: highlighter.cpp:338
Sonnet::Highlighter::newSuggestions
QT_MOC_COMPAT void newSuggestions(const QString &originalWord, const QStringList &suggestions)
Sonnet::Highlighter::setActive
void setActive(bool active)
Enable/Disable spell checking.
Definition: highlighter.cpp:254
Sonnet::Highlighter::automatic
bool automatic() const
Definition: highlighter.cpp:196
Sonnet::Highlighter::highlightBlock
virtual void highlightBlock(const QString &text)
Definition: highlighter.cpp:273
Sonnet::Highlighter::setIntraWordEditing
void setIntraWordEditing(bool editing)
Definition: highlighter.cpp:206
Sonnet::Highlighter::spellCheckerFound
bool spellCheckerFound() const
Definition: highlighter.cpp:139
Sonnet::Highlighter::setMisspelledColor
void setMisspelledColor(const QColor &color)
Sets the color in which the highlighter underlines misspelled words.
Definition: highlighter.cpp:438
Sonnet::Highlighter::setAutomatic
void setAutomatic(bool automatic)
Definition: highlighter.cpp:212
Sonnet::Highlighter::checkerEnabledByDefault
bool checkerEnabledByDefault() const
Return true if checker is enabled by default.
Definition: highlighter.cpp:443
Sonnet::Highlighter::setMisspelled
virtual void setMisspelled(int start, int count)
Definition: highlighter.cpp:324
Sonnet::Highlighter::unsetMisspelled
virtual void unsetMisspelled(int start, int count)
Definition: highlighter.cpp:333
Sonnet::Highlighter::intraWordEditing
bool intraWordEditing() const
Definition: highlighter.cpp:201
Sonnet::Highlighter::setCurrentLanguage
void setCurrentLanguage(const QString &lang)
Definition: highlighter.cpp:300
Sonnet::Loader::openLoader
static Loader * openLoader()
Sonnet::Speller
filter_p.h
kDebug
#define kDebug
highlighter.h
kconfig.h
kdebug.h
timeout
int timeout
klocale.h
i18n
QString i18n(const char *text)
kmessagebox.h
loader_p.h
Sonnet
dialog.cpp
settings_p.h
speller.h
Sonnet::Word
Sonnet::Word::word
QString word
Sonnet::Word::start
int start
Sonnet::Word::end
bool end
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal