ksyntaxhighlighter.cpp
00001 /* 00002 ksyntaxhighlighter.cpp 00003 00004 Copyright (c) 2003 Trolltech AS 00005 Copyright (c) 2003 Scott Wheeler <wheeler@kde.org> 00006 00007 This file is part of the KDE libraries 00008 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Library General Public 00011 License version 2 as published by the Free Software Foundation. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 Boston, MA 02110-1301, USA. 00022 */ 00023 00024 #include <tqcolor.h> 00025 #include <tqregexp.h> 00026 #include <tqsyntaxhighlighter.h> 00027 #include <tqtimer.h> 00028 00029 #include <klocale.h> 00030 #include <kconfig.h> 00031 #include <kdebug.h> 00032 #include <kglobal.h> 00033 #include <kspell.h> 00034 #include <kapplication.h> 00035 00036 #include "ksyntaxhighlighter.h" 00037 00038 static int dummy, dummy2, dummy3, dummy4; 00039 static int *Okay = &dummy; 00040 static int *NotOkay = &dummy2; 00041 static int *Ignore = &dummy3; 00042 static int *Unknown = &dummy4; 00043 static const int tenSeconds = 10*1000; 00044 00045 class KSyntaxHighlighter::KSyntaxHighlighterPrivate 00046 { 00047 public: 00048 TQColor col1, col2, col3, col4, col5; 00049 SyntaxMode mode; 00050 bool enabled; 00051 }; 00052 00053 class KSpellingHighlighter::KSpellingHighlighterPrivate 00054 { 00055 public: 00056 00057 KSpellingHighlighterPrivate() : 00058 alwaysEndsWithSpace( true ), 00059 intraWordEditing( false ) {} 00060 00061 TQString currentWord; 00062 int currentPos; 00063 bool alwaysEndsWithSpace; 00064 TQColor color; 00065 bool intraWordEditing; 00066 }; 00067 00068 class KDictSpellingHighlighter::KDictSpellingHighlighterPrivate 00069 { 00070 public: 00071 KDictSpellingHighlighterPrivate() : 00072 mDict( 0 ), 00073 spell( 0 ), 00074 mSpellConfig( 0 ), 00075 rehighlightRequest( 0 ), 00076 wordCount( 0 ), 00077 errorCount( 0 ), 00078 autoReady( false ), 00079 globalConfig( true ), 00080 spellReady( false ) {} 00081 00082 ~KDictSpellingHighlighterPrivate() { 00083 delete rehighlightRequest; 00084 delete spell; 00085 } 00086 00087 static TQDict<int>* sDict() 00088 { 00089 if (!statDict) 00090 statDict = new TQDict<int>(50021); 00091 return statDict; 00092 } 00093 00094 TQDict<int>* mDict; 00095 TQDict<int> autoDict; 00096 TQDict<int> autoIgnoreDict; 00097 static TQObject *sDictionaryMonitor; 00098 KSpell *spell; 00099 KSpellConfig *mSpellConfig; 00100 TQTimer *rehighlightRequest, *spellTimeout; 00101 TQString spellKey; 00102 int wordCount, errorCount; 00103 int checksRequested, checksDone; 00104 int disablePercentage; 00105 int disableWordCount; 00106 bool completeRehighlightRequired; 00107 bool active, automatic, autoReady; 00108 bool globalConfig, spellReady; 00109 private: 00110 static TQDict<int>* statDict; 00111 00112 }; 00113 00114 TQDict<int>* KDictSpellingHighlighter::KDictSpellingHighlighterPrivate::statDict = 0; 00115 00116 00117 KSyntaxHighlighter::KSyntaxHighlighter( TQTextEdit *textEdit, 00118 bool colorQuoting, 00119 const TQColor& depth0, 00120 const TQColor& depth1, 00121 const TQColor& depth2, 00122 const TQColor& depth3, 00123 SyntaxMode mode ) 00124 : TQSyntaxHighlighter( textEdit ) 00125 { 00126 d = new KSyntaxHighlighterPrivate(); 00127 00128 d->enabled = colorQuoting; 00129 d->col1 = depth0; 00130 d->col2 = depth1; 00131 d->col3 = depth2; 00132 d->col4 = depth3; 00133 d->col5 = depth0; 00134 00135 d->mode = mode; 00136 } 00137 00138 KSyntaxHighlighter::~KSyntaxHighlighter() 00139 { 00140 delete d; 00141 } 00142 00143 int KSyntaxHighlighter::highlightParagraph( const TQString &text, int ) 00144 { 00145 if (!d->enabled) { 00146 setFormat( 0, text.length(), textEdit()->viewport()->paletteForegroundColor() ); 00147 return 0; 00148 } 00149 00150 TQString simplified = text; 00151 simplified = TQString(simplified.replace( TQRegExp( "\\s" ), TQString() )).replace( '|', TQString::fromLatin1(">") ); 00152 while ( simplified.startsWith( TQString::fromLatin1(">>>>") ) ) 00153 simplified = simplified.mid(3); 00154 if ( simplified.startsWith( TQString::fromLatin1(">>>") ) || simplified.startsWith( TQString::fromLatin1("> > >") ) ) 00155 setFormat( 0, text.length(), d->col2 ); 00156 else if ( simplified.startsWith( TQString::fromLatin1(">>") ) || simplified.startsWith( TQString::fromLatin1("> >") ) ) 00157 setFormat( 0, text.length(), d->col3 ); 00158 else if ( simplified.startsWith( TQString::fromLatin1(">") ) ) 00159 setFormat( 0, text.length(), d->col4 ); 00160 else 00161 setFormat( 0, text.length(), d->col5 ); 00162 return 0; 00163 } 00164 00165 KSpellingHighlighter::KSpellingHighlighter( TQTextEdit *textEdit, 00166 const TQColor& spellColor, 00167 bool colorQuoting, 00168 const TQColor& depth0, 00169 const TQColor& depth1, 00170 const TQColor& depth2, 00171 const TQColor& depth3 ) 00172 : KSyntaxHighlighter( textEdit, colorQuoting, depth0, depth1, depth2, depth3 ) 00173 { 00174 d = new KSpellingHighlighterPrivate(); 00175 00176 d->color = spellColor; 00177 } 00178 00179 KSpellingHighlighter::~KSpellingHighlighter() 00180 { 00181 delete d; 00182 } 00183 00184 int KSpellingHighlighter::highlightParagraph( const TQString &text, 00185 int paraNo ) 00186 { 00187 if ( paraNo == -2 ) 00188 paraNo = 0; 00189 // leave #includes, diffs, and quoted replies alone 00190 TQString diffAndCo( ">|" ); 00191 00192 bool isCode = diffAndCo.find(text[0]) != -1; 00193 00194 if ( !text.endsWith(" ") ) 00195 d->alwaysEndsWithSpace = false; 00196 00197 KSyntaxHighlighter::highlightParagraph( text, -2 ); 00198 00199 if ( !isCode ) { 00200 int para, index; 00201 textEdit()->getCursorPosition( ¶, &index ); 00202 int len = text.length(); 00203 if ( d->alwaysEndsWithSpace ) 00204 len--; 00205 00206 d->currentPos = 0; 00207 d->currentWord = ""; 00208 for ( int i = 0; i < len; i++ ) { 00209 if ( !text[i].isLetter() && (!(text[i] == '\'')) ) { 00210 if ( ( para != paraNo ) || 00211 !intraWordEditing() || 00212 ( i - d->currentWord.length() > (uint)index ) || 00213 ( i < index ) ) { 00214 flushCurrentWord(); 00215 } else { 00216 d->currentWord = ""; 00217 } 00218 d->currentPos = i + 1; 00219 } else { 00220 d->currentWord += text[i]; 00221 } 00222 } 00223 if ( !text[len - 1].isLetter() || 00224 (uint)( index + 1 ) != text.length() || 00225 para != paraNo ) 00226 flushCurrentWord(); 00227 } 00228 return ++paraNo; 00229 } 00230 00231 TQStringList KSpellingHighlighter::personalWords() 00232 { 00233 TQStringList l; 00234 l.append( "KMail" ); 00235 l.append( "KOrganizer" ); 00236 l.append( "KAddressBook" ); 00237 l.append( "KHTML" ); 00238 l.append( "KIO" ); 00239 l.append( "KJS" ); 00240 l.append( "Konqueror" ); 00241 l.append( "KSpell" ); 00242 l.append( "Kontact" ); 00243 l.append( "Qt" ); 00244 return l; 00245 } 00246 00247 void KSpellingHighlighter::flushCurrentWord() 00248 { 00249 while ( d->currentWord[0].isPunct() ) { 00250 d->currentWord = d->currentWord.mid( 1 ); 00251 d->currentPos++; 00252 } 00253 00254 TQChar ch; 00255 while ( ( ch = d->currentWord[(int) d->currentWord.length() - 1] ).isPunct() && 00256 ch != '(' && ch != '@' ) 00257 d->currentWord.truncate( d->currentWord.length() - 1 ); 00258 00259 if ( !d->currentWord.isEmpty() ) { 00260 if ( isMisspelled( d->currentWord ) ) { 00261 setFormat( d->currentPos, d->currentWord.length(), d->color ); 00262 // setMisspelled( d->currentPos, d->currentWord.length(), true ); 00263 } 00264 } 00265 d->currentWord = ""; 00266 } 00267 00268 TQObject *KDictSpellingHighlighter::KDictSpellingHighlighterPrivate::sDictionaryMonitor = 0; 00269 00270 KDictSpellingHighlighter::KDictSpellingHighlighter( TQTextEdit *textEdit, 00271 bool spellCheckingActive , 00272 bool autoEnable, 00273 const TQColor& spellColor, 00274 bool colorQuoting, 00275 const TQColor& depth0, 00276 const TQColor& depth1, 00277 const TQColor& depth2, 00278 const TQColor& depth3, 00279 KSpellConfig *spellConfig ) 00280 : KSpellingHighlighter( textEdit, spellColor, 00281 colorQuoting, depth0, depth1, depth2, depth3 ) 00282 { 00283 d = new KDictSpellingHighlighterPrivate(); 00284 00285 d->mSpellConfig = spellConfig; 00286 d->globalConfig = ( !spellConfig ); 00287 d->automatic = autoEnable; 00288 d->active = spellCheckingActive; 00289 d->checksRequested = 0; 00290 d->checksDone = 0; 00291 d->completeRehighlightRequired = false; 00292 00293 KConfig *config = KGlobal::config(); 00294 KConfigGroupSaver cs( config, "KSpell" ); 00295 d->disablePercentage = config->readNumEntry( "KSpell_AsYouTypeDisablePercentage", 42 ); 00296 d->disablePercentage = QMIN( d->disablePercentage, 101 ); 00297 d->disableWordCount = config->readNumEntry( "KSpell_AsYouTypeDisableWordCount", 100 ); 00298 00299 textEdit->installEventFilter( this ); 00300 textEdit->viewport()->installEventFilter( this ); 00301 00302 d->rehighlightRequest = new TQTimer(this); 00303 connect( d->rehighlightRequest, TQT_SIGNAL( timeout() ), 00304 this, TQT_SLOT( slotRehighlight() )); 00305 d->spellTimeout = new TQTimer(this); 00306 connect( d->spellTimeout, TQT_SIGNAL( timeout() ), 00307 this, TQT_SLOT( slotKSpellNotResponding() )); 00308 00309 if ( d->globalConfig ) { 00310 d->spellKey = spellKey(); 00311 00312 if ( !d->sDictionaryMonitor ) 00313 d->sDictionaryMonitor = new TQObject(); 00314 } 00315 else { 00316 d->mDict = new TQDict<int>(4001); 00317 connect( d->mSpellConfig, TQT_SIGNAL( configChanged() ), 00318 this, TQT_SLOT( slotLocalSpellConfigChanged() ) ); 00319 } 00320 00321 slotDictionaryChanged(); 00322 // whats this good for? 00323 //startTimer( 2 * 1000 ); 00324 } 00325 00326 KDictSpellingHighlighter::~KDictSpellingHighlighter() 00327 { 00328 delete d->spell; 00329 d->spell = 0; 00330 delete d->mDict; 00331 d->mDict = 0; 00332 delete d; 00333 } 00334 00335 void KDictSpellingHighlighter::slotSpellReady( KSpell *spell ) 00336 { 00337 kdDebug(0) << "KDictSpellingHighlighter::slotSpellReady( " << spell << " )" << endl; 00338 KConfigGroup cg( KGlobal::config(),"KSpell" ); 00339 if ( cg.readEntry("KSpell_DoSpellChecking") != "0" ) 00340 { 00341 if ( d->globalConfig ) { 00342 connect( d->sDictionaryMonitor, TQT_SIGNAL( destroyed()), 00343 this, TQT_SLOT( slotDictionaryChanged() )); 00344 } 00345 if ( spell != d->spell ) 00346 { 00347 delete d->spell; 00348 d->spell = spell; 00349 } 00350 d->spellReady = true; 00351 const TQStringList l = KSpellingHighlighter::personalWords(); 00352 for ( TQStringList::ConstIterator it = l.begin(); it != l.end(); ++it ) { 00353 d->spell->addPersonal( *it ); 00354 } 00355 connect( spell, TQT_SIGNAL( misspelling( const TQString &, const TQStringList &, unsigned int )), 00356 this, TQT_SLOT( slotMisspelling( const TQString &, const TQStringList &, unsigned int ))); 00357 connect( spell, TQT_SIGNAL( corrected( const TQString &, const TQString &, unsigned int )), 00358 this, TQT_SLOT( slotCorrected( const TQString &, const TQString &, unsigned int ))); 00359 d->checksRequested = 0; 00360 d->checksDone = 0; 00361 d->completeRehighlightRequired = true; 00362 d->rehighlightRequest->start( 0, true ); 00363 } 00364 } 00365 00366 bool KDictSpellingHighlighter::isMisspelled( const TQString &word ) 00367 { 00368 if (!d->spellReady) 00369 return false; 00370 00371 // This debug is expensive, only enable it locally 00372 //kdDebug(0) << "KDictSpellingHighlighter::isMisspelled( \"" << word << "\" )" << endl; 00373 // Normally isMisspelled would look up a dictionary and return 00374 // true or false, but kspell is asynchronous and slow so things 00375 // get tricky... 00376 // For auto detection ignore signature and reply prefix 00377 if ( !d->autoReady ) 00378 d->autoIgnoreDict.replace( word, Ignore ); 00379 00380 // "dict" is used as a cache to store the results of KSpell 00381 TQDict<int>* dict = ( d->globalConfig ? d->sDict() : d->mDict ); 00382 if ( !dict->isEmpty() && (*dict)[word] == NotOkay ) { 00383 if ( d->autoReady && ( d->autoDict[word] != NotOkay )) { 00384 if ( !d->autoIgnoreDict[word] ) 00385 ++d->errorCount; 00386 d->autoDict.replace( word, NotOkay ); 00387 } 00388 00389 return d->active; 00390 } 00391 if ( !dict->isEmpty() && (*dict)[word] == Okay ) { 00392 if ( d->autoReady && !d->autoDict[word] ) { 00393 d->autoDict.replace( word, Okay ); 00394 } 00395 return false; 00396 } 00397 00398 if ((dict->isEmpty() || !((*dict)[word])) && d->spell ) { 00399 int para, index; 00400 textEdit()->getCursorPosition( ¶, &index ); 00401 ++d->wordCount; 00402 dict->replace( word, Unknown ); 00403 ++d->checksRequested; 00404 if (currentParagraph() != para) 00405 d->completeRehighlightRequired = true; 00406 d->spellTimeout->start( tenSeconds, true ); 00407 d->spell->checkWord( word, false ); 00408 } 00409 return false; 00410 } 00411 00412 bool KSpellingHighlighter::intraWordEditing() const 00413 { 00414 return d->intraWordEditing; 00415 } 00416 00417 void KSpellingHighlighter::setIntraWordEditing( bool editing ) 00418 { 00419 d->intraWordEditing = editing; 00420 } 00421 00422 void KDictSpellingHighlighter::slotMisspelling (const TQString &originalWord, const TQStringList &suggestions, 00423 unsigned int pos) 00424 { 00425 Q_UNUSED( suggestions ); 00426 // kdDebug() << suggestions.join( " " ).latin1() << endl; 00427 if ( d->globalConfig ) 00428 d->sDict()->replace( originalWord, NotOkay ); 00429 else 00430 d->mDict->replace( originalWord, NotOkay ); 00431 00432 //Emit this baby so that apps that want to have suggestions in a popup over 00433 //the misspelled word can catch them. 00434 emit newSuggestions( originalWord, suggestions, pos ); 00435 } 00436 00437 void KDictSpellingHighlighter::slotCorrected(const TQString &word, 00438 const TQString &, 00439 unsigned int) 00440 00441 { 00442 TQDict<int>* dict = ( d->globalConfig ? d->sDict() : d->mDict ); 00443 if ( !dict->isEmpty() && (*dict)[word] == Unknown ) { 00444 dict->replace( word, Okay ); 00445 } 00446 ++d->checksDone; 00447 if (d->checksDone == d->checksRequested) { 00448 d->spellTimeout->stop(); 00449 slotRehighlight(); 00450 } else { 00451 d->spellTimeout->start( tenSeconds, true ); 00452 } 00453 } 00454 00455 void KDictSpellingHighlighter::dictionaryChanged() 00456 { 00457 TQObject *oldMonitor = KDictSpellingHighlighterPrivate::sDictionaryMonitor; 00458 KDictSpellingHighlighterPrivate::sDictionaryMonitor = new TQObject(); 00459 KDictSpellingHighlighterPrivate::sDict()->clear(); 00460 delete oldMonitor; 00461 } 00462 00463 void KDictSpellingHighlighter::restartBackgroundSpellCheck() 00464 { 00465 kdDebug(0) << "KDictSpellingHighlighter::restartBackgroundSpellCheck()" << endl; 00466 slotDictionaryChanged(); 00467 } 00468 00469 void KDictSpellingHighlighter::setActive( bool active ) 00470 { 00471 if ( active == d->active ) 00472 return; 00473 00474 d->active = active; 00475 rehighlight(); 00476 if ( d->active ) 00477 emit activeChanged( i18n("As-you-type spell checking enabled.") ); 00478 else 00479 emit activeChanged( i18n("As-you-type spell checking disabled.") ); 00480 } 00481 00482 bool KDictSpellingHighlighter::isActive() const 00483 { 00484 return d->active; 00485 } 00486 00487 void KDictSpellingHighlighter::setAutomatic( bool automatic ) 00488 { 00489 if ( automatic == d->automatic ) 00490 return; 00491 00492 d->automatic = automatic; 00493 if ( d->automatic ) 00494 slotAutoDetection(); 00495 } 00496 00497 bool KDictSpellingHighlighter::automatic() const 00498 { 00499 return d->automatic; 00500 } 00501 00502 void KDictSpellingHighlighter::slotRehighlight() 00503 { 00504 kdDebug(0) << "KDictSpellingHighlighter::slotRehighlight()" << endl; 00505 if (d->completeRehighlightRequired) { 00506 rehighlight(); 00507 } else { 00508 int para, index; 00509 textEdit()->getCursorPosition( ¶, &index ); 00510 //rehighlight the current para only (undo/redo safe) 00511 bool modified = textEdit()->isModified(); 00512 textEdit()->insertAt( "", para, index ); 00513 textEdit()->setModified( modified ); 00514 } 00515 if (d->checksDone == d->checksRequested) 00516 d->completeRehighlightRequired = false; 00517 TQTimer::singleShot( 0, this, TQT_SLOT( slotAutoDetection() )); 00518 } 00519 00520 void KDictSpellingHighlighter::slotDictionaryChanged() 00521 { 00522 delete d->spell; 00523 d->spellReady = false; 00524 d->wordCount = 0; 00525 d->errorCount = 0; 00526 d->autoDict.clear(); 00527 00528 d->spell = new KSpell( 0, i18n( "Incremental Spellcheck" ), this, 00529 TQT_SLOT( slotSpellReady( KSpell * ) ), d->mSpellConfig ); 00530 } 00531 00532 void KDictSpellingHighlighter::slotLocalSpellConfigChanged() 00533 { 00534 kdDebug(0) << "KDictSpellingHighlighter::slotSpellConfigChanged()" << endl; 00535 // the spell config has been changed, so we have to restart from scratch 00536 d->mDict->clear(); 00537 slotDictionaryChanged(); 00538 } 00539 00540 TQString KDictSpellingHighlighter::spellKey() 00541 { 00542 KConfig *config = KGlobal::config(); 00543 KConfigGroupSaver cs( config, "KSpell" ); 00544 config->reparseConfiguration(); 00545 TQString key; 00546 key += TQString::number( config->readNumEntry( "KSpell_NoRootAffix", 0 )); 00547 key += '/'; 00548 key += TQString::number( config->readNumEntry( "KSpell_RunTogether", 0 )); 00549 key += '/'; 00550 key += config->readEntry( "KSpell_Dictionary", "" ); 00551 key += '/'; 00552 key += TQString::number( config->readNumEntry( "KSpell_DictFromList", false )); 00553 key += '/'; 00554 key += TQString::number( config->readNumEntry( "KSpell_Encoding", KS_E_UTF8 )); 00555 key += '/'; 00556 key += TQString::number( config->readNumEntry( "KSpell_Client", KS_CLIENT_ISPELL )); 00557 return key; 00558 } 00559 00560 00561 // Automatic spell checking support 00562 // In auto spell checking mode disable as-you-type spell checking 00563 // iff more than one third of words are spelt incorrectly. 00564 // 00565 // Words in the signature and reply prefix are ignored. 00566 // Only unique words are counted. 00567 00568 void KDictSpellingHighlighter::slotAutoDetection() 00569 { 00570 if ( !d->autoReady ) 00571 return; 00572 00573 bool savedActive = d->active; 00574 00575 if ( d->automatic ) { 00576 // tme = Too many errors 00577 bool tme = d->wordCount >= d->disableWordCount && d->errorCount * 100 >= d->disablePercentage * d->wordCount; 00578 if ( d->active && tme ) 00579 d->active = false; 00580 else if ( !d->active && !tme ) 00581 d->active = true; 00582 } 00583 if ( d->active != savedActive ) { 00584 if ( d->wordCount > 1 ) 00585 if ( d->active ) 00586 emit activeChanged( i18n("As-you-type spell checking enabled.") ); 00587 else 00588 emit activeChanged( i18n( "Too many misspelled words. " 00589 "As-you-type spell checking disabled." ) ); 00590 d->completeRehighlightRequired = true; 00591 d->rehighlightRequest->start( 100, true ); 00592 } 00593 } 00594 00595 void KDictSpellingHighlighter::slotKSpellNotResponding() 00596 { 00597 static int retries = 0; 00598 if (retries < 10) { 00599 if ( d->globalConfig ) 00600 KDictSpellingHighlighter::dictionaryChanged(); 00601 else 00602 slotLocalSpellConfigChanged(); 00603 } else { 00604 setAutomatic( false ); 00605 setActive( false ); 00606 } 00607 ++retries; 00608 } 00609 00610 bool KDictSpellingHighlighter::eventFilter( TQObject *o, TQEvent *e) 00611 { 00612 if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(textEdit()) && (e->type() == TQEvent::FocusIn)) { 00613 if ( d->globalConfig ) { 00614 TQString skey = spellKey(); 00615 if ( d->spell && d->spellKey != skey ) { 00616 d->spellKey = skey; 00617 KDictSpellingHighlighter::dictionaryChanged(); 00618 } 00619 } 00620 } 00621 00622 if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(textEdit()) && (e->type() == TQEvent::KeyPress)) { 00623 TQKeyEvent *k = TQT_TQKEYEVENT(e); 00624 d->autoReady = true; 00625 if (d->rehighlightRequest->isActive()) // try to stay out of the users way 00626 d->rehighlightRequest->changeInterval( 500 ); 00627 if ( k->key() == Key_Enter || 00628 k->key() == Key_Return || 00629 k->key() == Key_Up || 00630 k->key() == Key_Down || 00631 k->key() == Key_Left || 00632 k->key() == Key_Right || 00633 k->key() == Key_PageUp || 00634 k->key() == Key_PageDown || 00635 k->key() == Key_Home || 00636 k->key() == Key_End || 00637 (( k->state() & ControlButton ) && 00638 ((k->key() == Key_A) || 00639 (k->key() == Key_B) || 00640 (k->key() == Key_E) || 00641 (k->key() == Key_N) || 00642 (k->key() == Key_P))) ) { 00643 if ( intraWordEditing() ) { 00644 setIntraWordEditing( false ); 00645 d->completeRehighlightRequired = true; 00646 d->rehighlightRequest->start( 500, true ); 00647 } 00648 if (d->checksDone != d->checksRequested) { 00649 // Handle possible change of paragraph while 00650 // words are pending spell checking 00651 d->completeRehighlightRequired = true; 00652 d->rehighlightRequest->start( 500, true ); 00653 } 00654 } else { 00655 setIntraWordEditing( true ); 00656 } 00657 if ( k->key() == Key_Space || 00658 k->key() == Key_Enter || 00659 k->key() == Key_Return ) { 00660 TQTimer::singleShot( 0, this, TQT_SLOT( slotAutoDetection() )); 00661 } 00662 } 00663 00664 else if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(textEdit()->viewport()) && 00665 ( e->type() == TQEvent::MouseButtonPress )) { 00666 d->autoReady = true; 00667 if ( intraWordEditing() ) { 00668 setIntraWordEditing( false ); 00669 d->completeRehighlightRequired = true; 00670 d->rehighlightRequest->start( 0, true ); 00671 } 00672 } 00673 00674 return false; 00675 } 00676 00677 #include "ksyntaxhighlighter.moc"