1 | /* |
2 | Copyright (c) 2003 Trolltech AS |
3 | Copyright (c) 2003 Scott Wheeler <wheeler@kde.org> |
4 | |
5 | This file is part of the KDE libraries |
6 | |
7 | This library is free software; you can redistribute it and/or |
8 | modify it under the terms of the GNU Library General Public |
9 | License version 2 as published by the Free Software Foundation. |
10 | |
11 | This library is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | Library General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU Library General Public License |
17 | along with this library; see the file COPYING.LIB. If not, write to |
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | Boston, MA 02110-1301, USA. |
20 | */ |
21 | |
22 | #include "k3syntaxhighlighter.h" |
23 | |
24 | #include <QtGui/QColor> |
25 | #include <QtCore/QRegExp> |
26 | #include <Qt3Support/Q3SyntaxHighlighter> |
27 | #include <QtCore/QTimer> |
28 | |
29 | #include <klocale.h> |
30 | #include <kconfig.h> |
31 | #include <kdebug.h> |
32 | #include <kglobal.h> |
33 | #include <k3sconfig.h> |
34 | #include <k3spell.h> |
35 | #include <Qt3Support/Q3Dict> |
36 | #include <QKeyEvent> |
37 | |
38 | #include <kconfiggroup.h> |
39 | #include <fixx11h.h> |
40 | |
41 | static int dummy, dummy2, dummy3, dummy4; |
42 | static int *Okay = &dummy; |
43 | static int *NotOkay = &dummy2; |
44 | static int *Ignore = &dummy3; |
45 | static int *Unknown = &dummy4; |
46 | static const int tenSeconds = 10*1000; |
47 | |
48 | class K3SyntaxHighlighter::K3SyntaxHighlighterPrivate |
49 | { |
50 | public: |
51 | QColor col1, col2, col3, col4, col5; |
52 | SyntaxMode mode; |
53 | bool enabled; |
54 | }; |
55 | |
56 | class K3SpellingHighlighter::K3SpellingHighlighterPrivate |
57 | { |
58 | public: |
59 | |
60 | K3SpellingHighlighterPrivate() : |
61 | alwaysEndsWithSpace( true ), |
62 | intraWordEditing( false ) {} |
63 | |
64 | QString currentWord; |
65 | int currentPos; |
66 | bool alwaysEndsWithSpace; |
67 | QColor color; |
68 | bool intraWordEditing; |
69 | }; |
70 | |
71 | class K3DictSpellingHighlighter::K3DictSpellingHighlighterPrivate |
72 | { |
73 | public: |
74 | K3DictSpellingHighlighterPrivate() : |
75 | mDict( 0 ), |
76 | spell( 0 ), |
77 | mSpellConfig( 0 ), |
78 | rehighlightRequest( 0 ), |
79 | wordCount( 0 ), |
80 | errorCount( 0 ), |
81 | autoReady( false ), |
82 | globalConfig( true ), |
83 | spellReady( false ) {} |
84 | |
85 | ~K3DictSpellingHighlighterPrivate() { |
86 | delete rehighlightRequest; |
87 | delete spell; |
88 | } |
89 | |
90 | static Q3Dict<int>* sDict() |
91 | { |
92 | if (!statDict) |
93 | statDict = new Q3Dict<int>(50021); |
94 | return statDict; |
95 | } |
96 | |
97 | Q3Dict<int>* mDict; |
98 | Q3Dict<int> autoDict; |
99 | Q3Dict<int> autoIgnoreDict; |
100 | static QObject *sDictionaryMonitor; |
101 | K3Spell *spell; |
102 | K3SpellConfig *mSpellConfig; |
103 | QTimer *rehighlightRequest, *spellTimeout; |
104 | QString spellKey; |
105 | int wordCount, errorCount; |
106 | int checksRequested, checksDone; |
107 | int disablePercentage; |
108 | int disableWordCount; |
109 | bool completeRehighlightRequired; |
110 | bool active, automatic, autoReady; |
111 | bool globalConfig, spellReady; |
112 | private: |
113 | static Q3Dict<int>* statDict; |
114 | |
115 | }; |
116 | |
117 | Q3Dict<int>* K3DictSpellingHighlighter::K3DictSpellingHighlighterPrivate::statDict = 0; |
118 | |
119 | |
120 | K3SyntaxHighlighter::K3SyntaxHighlighter( Q3TextEdit *textEdit, |
121 | bool colorQuoting, |
122 | const QColor& depth0, |
123 | const QColor& depth1, |
124 | const QColor& depth2, |
125 | const QColor& depth3, |
126 | SyntaxMode mode ) |
127 | : Q3SyntaxHighlighter( textEdit ),d(new K3SyntaxHighlighterPrivate()) |
128 | { |
129 | |
130 | d->enabled = colorQuoting; |
131 | d->col1 = depth0; |
132 | d->col2 = depth1; |
133 | d->col3 = depth2; |
134 | d->col4 = depth3; |
135 | d->col5 = depth0; |
136 | |
137 | d->mode = mode; |
138 | } |
139 | |
140 | K3SyntaxHighlighter::~K3SyntaxHighlighter() |
141 | { |
142 | delete d; |
143 | } |
144 | |
145 | int K3SyntaxHighlighter::highlightParagraph( const QString &text, int ) |
146 | { |
147 | if (!d->enabled) { |
148 | setFormat( 0, text.length(), textEdit()->viewport()->paletteForegroundColor() ); |
149 | return 0; |
150 | } |
151 | |
152 | QString simplified = text; |
153 | simplified = simplified.replace( QRegExp( "\\s" ), QString() ).replace( '|', QLatin1String(">" ) ); |
154 | while ( simplified.startsWith( QLatin1String(">>>>" ) ) ) |
155 | simplified = simplified.mid(3); |
156 | if ( simplified.startsWith( QLatin1String(">>>" ) ) || simplified.startsWith( QString::fromLatin1("> > >" ) ) ) |
157 | setFormat( 0, text.length(), d->col2 ); |
158 | else if ( simplified.startsWith( QLatin1String(">>" ) ) || simplified.startsWith( QString::fromLatin1("> >" ) ) ) |
159 | setFormat( 0, text.length(), d->col3 ); |
160 | else if ( simplified.startsWith( QLatin1String(">" ) ) ) |
161 | setFormat( 0, text.length(), d->col4 ); |
162 | else |
163 | setFormat( 0, text.length(), d->col5 ); |
164 | return 0; |
165 | } |
166 | |
167 | K3SpellingHighlighter::K3SpellingHighlighter( Q3TextEdit *textEdit, |
168 | const QColor& spellColor, |
169 | bool colorQuoting, |
170 | const QColor& depth0, |
171 | const QColor& depth1, |
172 | const QColor& depth2, |
173 | const QColor& depth3 ) |
174 | : K3SyntaxHighlighter( textEdit, colorQuoting, depth0, depth1, depth2, depth3 ),d(new K3SpellingHighlighterPrivate()) |
175 | { |
176 | |
177 | d->color = spellColor; |
178 | } |
179 | |
180 | K3SpellingHighlighter::~K3SpellingHighlighter() |
181 | { |
182 | delete d; |
183 | } |
184 | |
185 | int K3SpellingHighlighter::highlightParagraph( const QString &text, |
186 | int paraNo ) |
187 | { |
188 | if ( paraNo == -2 ) |
189 | paraNo = 0; |
190 | // leave #includes, diffs, and quoted replies alone |
191 | QString diffAndCo( ">|" ); |
192 | |
193 | bool isCode = diffAndCo.contains(text[0]); |
194 | |
195 | if ( !text.endsWith(' ') ) |
196 | d->alwaysEndsWithSpace = false; |
197 | |
198 | K3SyntaxHighlighter::highlightParagraph( text, -2 ); |
199 | |
200 | if ( !isCode ) { |
201 | int para, index; |
202 | textEdit()->getCursorPosition( ¶, &index ); |
203 | int len = text.length(); |
204 | if ( d->alwaysEndsWithSpace ) |
205 | len--; |
206 | |
207 | d->currentPos = 0; |
208 | d->currentWord = "" ; |
209 | for ( int i = 0; i < len; i++ ) { |
210 | if ( !text[i].isLetter() && (!(text[i] == '\'')) ) { |
211 | if ( ( para != paraNo ) || |
212 | !intraWordEditing() || |
213 | ( i - d->currentWord.length() > index ) || |
214 | ( i < index ) ) { |
215 | flushCurrentWord(); |
216 | } else { |
217 | d->currentWord = "" ; |
218 | } |
219 | d->currentPos = i + 1; |
220 | } else { |
221 | d->currentWord += text[i]; |
222 | } |
223 | } |
224 | if ( ( len > 0 && !text[len - 1].isLetter() ) || |
225 | ( index + 1 ) != text.length() || |
226 | para != paraNo ) |
227 | flushCurrentWord(); |
228 | } |
229 | return ++paraNo; |
230 | } |
231 | |
232 | QStringList K3SpellingHighlighter::personalWords() |
233 | { |
234 | QStringList l; |
235 | l.append( "KMail" ); |
236 | l.append( "KOrganizer" ); |
237 | l.append( "KAddressBook" ); |
238 | l.append( "KHTML" ); |
239 | l.append( "KIO" ); |
240 | l.append( "KJS" ); |
241 | l.append( "Konqueror" ); |
242 | l.append( "K3Spell" ); |
243 | l.append( "Kontact" ); |
244 | l.append( "Qt" ); |
245 | return l; |
246 | } |
247 | |
248 | void K3SpellingHighlighter::flushCurrentWord() |
249 | { |
250 | while ( d->currentWord[0].isPunct() ) { |
251 | d->currentWord = d->currentWord.mid( 1 ); |
252 | d->currentPos++; |
253 | } |
254 | |
255 | QChar ch; |
256 | while ( !d->currentWord.isEmpty() && ( ch = d->currentWord[(int) d->currentWord.length() - 1] ).isPunct() && |
257 | ch != '(' && ch != '@' ) |
258 | d->currentWord.truncate( d->currentWord.length() - 1 ); |
259 | |
260 | if ( !d->currentWord.isEmpty() ) { |
261 | if ( isMisspelled( d->currentWord ) ) { |
262 | setFormat( d->currentPos, d->currentWord.length(), d->color ); |
263 | // setMisspelled( d->currentPos, d->currentWord.length(), true ); |
264 | } |
265 | } |
266 | d->currentWord = "" ; |
267 | } |
268 | |
269 | QObject *K3DictSpellingHighlighter::K3DictSpellingHighlighterPrivate::sDictionaryMonitor = 0; |
270 | |
271 | K3DictSpellingHighlighter::K3DictSpellingHighlighter( Q3TextEdit *textEdit, |
272 | bool spellCheckingActive , |
273 | bool autoEnable, |
274 | const QColor& spellColor, |
275 | bool colorQuoting, |
276 | const QColor& depth0, |
277 | const QColor& depth1, |
278 | const QColor& depth2, |
279 | const QColor& depth3, |
280 | K3SpellConfig *spellConfig ) |
281 | : K3SpellingHighlighter( textEdit, spellColor, |
282 | colorQuoting, depth0, depth1, depth2, depth3 ),d(new K3DictSpellingHighlighterPrivate()) |
283 | { |
284 | |
285 | d->mSpellConfig = spellConfig; |
286 | d->globalConfig = ( !spellConfig ); |
287 | d->automatic = autoEnable; |
288 | d->active = spellCheckingActive; |
289 | d->checksRequested = 0; |
290 | d->checksDone = 0; |
291 | d->completeRehighlightRequired = false; |
292 | |
293 | KConfigGroup cg( KGlobal::config(), "K3Spell" ); |
294 | d->disablePercentage = cg.readEntry( "K3Spell_AsYouTypeDisablePercentage" , QVariant(42 )).toInt(); |
295 | d->disablePercentage = qMin( d->disablePercentage, 101 ); |
296 | d->disableWordCount = cg.readEntry( "K3Spell_AsYouTypeDisableWordCount" , QVariant(100 )).toInt(); |
297 | |
298 | textEdit->installEventFilter( this ); |
299 | textEdit->viewport()->installEventFilter( this ); |
300 | |
301 | d->rehighlightRequest = new QTimer(this); |
302 | connect( d->rehighlightRequest, SIGNAL(timeout()), |
303 | this, SLOT(slotRehighlight())); |
304 | d->spellTimeout = new QTimer(this); |
305 | connect( d->spellTimeout, SIGNAL(timeout()), |
306 | this, SLOT(slotK3SpellNotResponding())); |
307 | |
308 | if ( d->globalConfig ) { |
309 | d->spellKey = spellKey(); |
310 | |
311 | if ( !d->sDictionaryMonitor ) |
312 | d->sDictionaryMonitor = new QObject(); |
313 | } |
314 | else { |
315 | d->mDict = new Q3Dict<int>(4001); |
316 | connect( d->mSpellConfig, SIGNAL(configChanged()), |
317 | this, SLOT(slotLocalSpellConfigChanged()) ); |
318 | } |
319 | |
320 | slotDictionaryChanged(); |
321 | } |
322 | |
323 | K3DictSpellingHighlighter::~K3DictSpellingHighlighter() |
324 | { |
325 | delete d->spell; |
326 | d->spell = 0; |
327 | delete d->mDict; |
328 | d->mDict = 0; |
329 | delete d; |
330 | } |
331 | |
332 | void K3DictSpellingHighlighter::slotSpellReady( K3Spell *spell ) |
333 | { |
334 | kDebug(0) << "KDictSpellingHighlighter::slotSpellReady( " << spell << " )" ; |
335 | if ( d->globalConfig ) { |
336 | connect( d->sDictionaryMonitor, SIGNAL(destroyed()), |
337 | this, SLOT(slotDictionaryChanged())); |
338 | } |
339 | if ( spell != d->spell ) |
340 | { |
341 | delete d->spell; |
342 | d->spell = spell; |
343 | } |
344 | d->spellReady = true; |
345 | const QStringList l = K3SpellingHighlighter::personalWords(); |
346 | for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it ) { |
347 | d->spell->addPersonal( *it ); |
348 | } |
349 | connect( spell, SIGNAL(misspelling(QString,QStringList,uint)), |
350 | this, SLOT(slotMisspelling(QString,QStringList,uint))); |
351 | connect( spell, SIGNAL(corrected(QString,QString,uint)), |
352 | this, SLOT(slotCorrected(QString,QString,uint))); |
353 | d->checksRequested = 0; |
354 | d->checksDone = 0; |
355 | d->completeRehighlightRequired = true; |
356 | d->rehighlightRequest->start( 0, true ); |
357 | } |
358 | |
359 | bool K3DictSpellingHighlighter::isMisspelled( const QString &word ) |
360 | { |
361 | if (!d->spellReady) |
362 | return false; |
363 | |
364 | // This debug is expensive, only enable it locally |
365 | //kDebug(0) << "KDictSpellingHighlighter::isMisspelled( \"" << word << "\" )"; |
366 | // Normally isMisspelled would look up a dictionary and return |
367 | // true or false, but kspell is asynchronous and slow so things |
368 | // get tricky... |
369 | // For auto detection ignore signature and reply prefix |
370 | if ( !d->autoReady ) |
371 | d->autoIgnoreDict.replace( word, Ignore ); |
372 | |
373 | // "dict" is used as a cache to store the results of K3Spell |
374 | Q3Dict<int>* dict = ( d->globalConfig ? d->sDict() : d->mDict ); |
375 | if ( !dict->isEmpty() && (*dict)[word] == NotOkay ) { |
376 | if ( d->autoReady && ( d->autoDict[word] != NotOkay )) { |
377 | if ( !d->autoIgnoreDict[word] ) |
378 | ++d->errorCount; |
379 | d->autoDict.replace( word, NotOkay ); |
380 | } |
381 | |
382 | return d->active; |
383 | } |
384 | if ( !dict->isEmpty() && (*dict)[word] == Okay ) { |
385 | if ( d->autoReady && !d->autoDict[word] ) { |
386 | d->autoDict.replace( word, Okay ); |
387 | } |
388 | return false; |
389 | } |
390 | |
391 | if ((dict->isEmpty() || !((*dict)[word])) && d->spell ) { |
392 | int para, index; |
393 | textEdit()->getCursorPosition( ¶, &index ); |
394 | ++d->wordCount; |
395 | dict->replace( word, Unknown ); |
396 | ++d->checksRequested; |
397 | if (currentParagraph() != para) |
398 | d->completeRehighlightRequired = true; |
399 | d->spellTimeout->start( tenSeconds, true ); |
400 | d->spell->checkWord( word, false ); |
401 | } |
402 | return false; |
403 | } |
404 | |
405 | bool K3SpellingHighlighter::intraWordEditing() const |
406 | { |
407 | return d->intraWordEditing; |
408 | } |
409 | |
410 | void K3SpellingHighlighter::setIntraWordEditing( bool editing ) |
411 | { |
412 | d->intraWordEditing = editing; |
413 | } |
414 | |
415 | void K3DictSpellingHighlighter::slotMisspelling (const QString &originalWord, const QStringList &suggestions, |
416 | unsigned int pos) |
417 | { |
418 | Q_UNUSED( suggestions ); |
419 | // kDebug() << suggestions.join( " " ).toLatin1(); |
420 | if ( d->globalConfig ) |
421 | d->sDict()->replace( originalWord, NotOkay ); |
422 | else |
423 | d->mDict->replace( originalWord, NotOkay ); |
424 | |
425 | //Emit this baby so that apps that want to have suggestions in a popup over |
426 | //the misspelled word can catch them. |
427 | emit newSuggestions( originalWord, suggestions, pos ); |
428 | } |
429 | |
430 | void K3DictSpellingHighlighter::slotCorrected(const QString &word, |
431 | const QString &, |
432 | unsigned int) |
433 | |
434 | { |
435 | Q3Dict<int>* dict = ( d->globalConfig ? d->sDict() : d->mDict ); |
436 | if ( !dict->isEmpty() && (*dict)[word] == Unknown ) { |
437 | dict->replace( word, Okay ); |
438 | } |
439 | ++d->checksDone; |
440 | if (d->checksDone == d->checksRequested) { |
441 | d->spellTimeout->stop(); |
442 | slotRehighlight(); |
443 | } else { |
444 | d->spellTimeout->start( tenSeconds, true ); |
445 | } |
446 | } |
447 | |
448 | void K3DictSpellingHighlighter::dictionaryChanged() |
449 | { |
450 | QObject *oldMonitor = K3DictSpellingHighlighterPrivate::sDictionaryMonitor; |
451 | K3DictSpellingHighlighterPrivate::sDictionaryMonitor = new QObject(); |
452 | K3DictSpellingHighlighterPrivate::sDict()->clear(); |
453 | delete oldMonitor; |
454 | } |
455 | |
456 | void K3DictSpellingHighlighter::restartBackgroundSpellCheck() |
457 | { |
458 | kDebug(0) << "KDictSpellingHighlighter::restartBackgroundSpellCheck()" ; |
459 | slotDictionaryChanged(); |
460 | } |
461 | |
462 | void K3DictSpellingHighlighter::setActive( bool active ) |
463 | { |
464 | if ( active == d->active ) |
465 | return; |
466 | |
467 | d->active = active; |
468 | rehighlight(); |
469 | if ( d->active ) |
470 | emit activeChanged( i18n("As-you-type spell checking enabled." ) ); |
471 | else |
472 | emit activeChanged( i18n("As-you-type spell checking disabled." ) ); |
473 | } |
474 | |
475 | bool K3DictSpellingHighlighter::isActive() const |
476 | { |
477 | return d->active; |
478 | } |
479 | |
480 | void K3DictSpellingHighlighter::setAutomatic( bool automatic ) |
481 | { |
482 | if ( automatic == d->automatic ) |
483 | return; |
484 | |
485 | d->automatic = automatic; |
486 | if ( d->automatic ) |
487 | slotAutoDetection(); |
488 | } |
489 | |
490 | bool K3DictSpellingHighlighter::automatic() const |
491 | { |
492 | return d->automatic; |
493 | } |
494 | |
495 | void K3DictSpellingHighlighter::slotRehighlight() |
496 | { |
497 | kDebug(0) << "KDictSpellingHighlighter::slotRehighlight()" ; |
498 | if (d->completeRehighlightRequired) { |
499 | rehighlight(); |
500 | } else { |
501 | int para, index; |
502 | textEdit()->getCursorPosition( ¶, &index ); |
503 | //rehighlight the current para only (undo/redo safe) |
504 | textEdit()->insertAt( "" , para, index ); |
505 | } |
506 | if (d->checksDone == d->checksRequested) |
507 | d->completeRehighlightRequired = false; |
508 | QTimer::singleShot( 0, this, SLOT(slotAutoDetection())); |
509 | } |
510 | |
511 | void K3DictSpellingHighlighter::slotDictionaryChanged() |
512 | { |
513 | delete d->spell; |
514 | d->spellReady = false; |
515 | d->wordCount = 0; |
516 | d->errorCount = 0; |
517 | d->autoDict.clear(); |
518 | |
519 | d->spell = new K3Spell( 0, i18n( "Incremental Spellcheck" ), this, |
520 | SLOT(slotSpellReady(K3Spell*)), d->mSpellConfig ); |
521 | } |
522 | |
523 | void K3DictSpellingHighlighter::slotLocalSpellConfigChanged() |
524 | { |
525 | kDebug(0) << "KDictSpellingHighlighter::slotSpellConfigChanged()" ; |
526 | // the spell config has been changed, so we have to restart from scratch |
527 | d->mDict->clear(); |
528 | slotDictionaryChanged(); |
529 | } |
530 | |
531 | QString K3DictSpellingHighlighter::spellKey() |
532 | { |
533 | KGlobal::config()->reparseConfiguration(); |
534 | KConfigGroup cg( KGlobal::config(), "K3Spell" ); |
535 | QString key; |
536 | key += QString::number( cg.readEntry( "K3Spell_NoRootAffix" , QVariant(0 )).toInt()); |
537 | key += '/'; |
538 | key += QString::number( cg.readEntry( "K3Spell_RunTogether" , QVariant(0 )).toInt()); |
539 | key += '/'; |
540 | key += cg.readEntry( "K3Spell_Dictionary" , "" ); |
541 | key += '/'; |
542 | key += QString::number( cg.readEntry( "K3Spell_DictFromList" , QVariant(false )).toInt()); |
543 | key += '/'; |
544 | key += QString::number( cg.readEntry( "K3Spell_Encoding" , QVariant(KS_E_ASCII )).toInt()); |
545 | key += '/'; |
546 | key += QString::number( cg.readEntry( "K3Spell_Client" , QVariant(KS_CLIENT_ISPELL )).toInt()); |
547 | return key; |
548 | } |
549 | |
550 | |
551 | // Automatic spell checking support |
552 | // In auto spell checking mode disable as-you-type spell checking |
553 | // iff more than one third of words are spelt incorrectly. |
554 | // |
555 | // Words in the signature and reply prefix are ignored. |
556 | // Only unique words are counted. |
557 | |
558 | void K3DictSpellingHighlighter::slotAutoDetection() |
559 | { |
560 | if ( !d->autoReady ) |
561 | return; |
562 | |
563 | bool savedActive = d->active; |
564 | |
565 | if ( d->automatic ) { |
566 | // tme = Too many errors |
567 | bool tme = ( d->wordCount >= d->disableWordCount ) && ( d->errorCount * 100 >= d->disablePercentage * d->wordCount ); |
568 | if ( d->active && tme ) |
569 | d->active = false; |
570 | else if ( !d->active && !tme ) |
571 | d->active = true; |
572 | } |
573 | if ( d->active != savedActive ) { |
574 | if ( d->wordCount > 1 ) { |
575 | if ( d->active ) |
576 | emit activeChanged( i18n("As-you-type spell checking enabled." ) ); |
577 | else |
578 | emit activeChanged( i18n( "Too many misspelled words. " |
579 | "As-you-type spell checking disabled." ) ); |
580 | } |
581 | d->completeRehighlightRequired = true; |
582 | d->rehighlightRequest->start( 100, true ); |
583 | } |
584 | } |
585 | |
586 | void K3DictSpellingHighlighter::slotK3SpellNotResponding() |
587 | { |
588 | static int retries = 0; |
589 | if (retries < 10) { |
590 | if ( d->globalConfig ) |
591 | K3DictSpellingHighlighter::dictionaryChanged(); |
592 | else |
593 | slotLocalSpellConfigChanged(); |
594 | } else { |
595 | setAutomatic( false ); |
596 | setActive( false ); |
597 | } |
598 | ++retries; |
599 | } |
600 | |
601 | bool K3DictSpellingHighlighter::eventFilter( QObject *o, QEvent *e) |
602 | { |
603 | if (o == textEdit() && (e->type() == QEvent::FocusIn)) { |
604 | if ( d->globalConfig ) { |
605 | QString skey = spellKey(); |
606 | if ( d->spell && d->spellKey != skey ) { |
607 | d->spellKey = skey; |
608 | K3DictSpellingHighlighter::dictionaryChanged(); |
609 | } |
610 | } |
611 | } |
612 | |
613 | if (o == textEdit() && (e->type() == QEvent::KeyPress)) { |
614 | QKeyEvent *k = static_cast<QKeyEvent *>(e); |
615 | d->autoReady = true; |
616 | if (d->rehighlightRequest->isActive()) // try to stay out of the users way |
617 | d->rehighlightRequest->start( 500 ); |
618 | if ( k->key() == Qt::Key_Enter || |
619 | k->key() == Qt::Key_Return || |
620 | k->key() == Qt::Key_Up || |
621 | k->key() == Qt::Key_Down || |
622 | k->key() == Qt::Key_Left || |
623 | k->key() == Qt::Key_Right || |
624 | k->key() == Qt::Key_PageUp || |
625 | k->key() == Qt::Key_PageDown || |
626 | k->key() == Qt::Key_Home || |
627 | k->key() == Qt::Key_End || |
628 | (( k->state() & Qt::ControlModifier ) && |
629 | ((k->key() == Qt::Key_A) || |
630 | (k->key() == Qt::Key_B) || |
631 | (k->key() == Qt::Key_E) || |
632 | (k->key() == Qt::Key_N) || |
633 | (k->key() == Qt::Key_P))) ) { |
634 | if ( intraWordEditing() ) { |
635 | setIntraWordEditing( false ); |
636 | d->completeRehighlightRequired = true; |
637 | d->rehighlightRequest->start( 500, true ); |
638 | } |
639 | if (d->checksDone != d->checksRequested) { |
640 | // Handle possible change of paragraph while |
641 | // words are pending spell checking |
642 | d->completeRehighlightRequired = true; |
643 | d->rehighlightRequest->start( 500, true ); |
644 | } |
645 | } else { |
646 | setIntraWordEditing( true ); |
647 | } |
648 | if ( k->key() == Qt::Key_Space || |
649 | k->key() == Qt::Key_Enter || |
650 | k->key() == Qt::Key_Return ) { |
651 | QTimer::singleShot( 0, this, SLOT(slotAutoDetection())); |
652 | } |
653 | } |
654 | |
655 | else if ( o == textEdit()->viewport() && |
656 | ( e->type() == QEvent::MouseButtonPress )) { |
657 | d->autoReady = true; |
658 | if ( intraWordEditing() ) { |
659 | setIntraWordEditing( false ); |
660 | d->completeRehighlightRequired = true; |
661 | d->rehighlightRequest->start( 0, true ); |
662 | } |
663 | } |
664 | |
665 | return false; |
666 | } |
667 | |
668 | #include "k3syntaxhighlighter.moc" |
669 | |