kdeui Library API Documentation

kspell.cpp

00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1997 David Sweet <dsweet@kde.org> 00003 Copyright (C) 2000-2001 Wolfram Diestel <wolfram@steloj.de> 00004 Copyright (C) 2003 Zack Rusin <zack@kde.org> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License version 2 as published by the Free Software Foundation. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, USA. 00019 */ 00020 00021 #ifdef HAVE_CONFIG_H 00022 #include <config.h> 00023 #endif 00024 00025 #include <stdio.h> 00026 #include <sys/time.h> 00027 #include <sys/types.h> 00028 #include <unistd.h> 00029 #include <ctype.h> 00030 #include <stdlib.h> // atoi 00031 00032 #ifdef HAVE_STRINGS_H 00033 #include <strings.h> 00034 #endif 00035 00036 #include <qtextcodec.h> 00037 #include <qtimer.h> 00038 #include <kapplication.h> 00039 #include <kmessagebox.h> 00040 #include <kdebug.h> 00041 #include <klocale.h> 00042 #include "kspell.h" 00043 #include "kspelldlg.h" 00044 #include <kwin.h> 00045 #include <kprocio.h> 00046 00047 #define MAXLINELENGTH 10000 00048 00049 enum { 00050 GOOD= 0, 00051 IGNORE= 1, 00052 REPLACE= 2, 00053 MISTAKE= 3 00054 }; 00055 00056 enum checkMethod { Method1 = 0, Method2 }; 00057 00058 struct BufferedWord 00059 { 00060 checkMethod method; 00061 QString word; 00062 bool useDialog; 00063 bool suggest; 00064 }; 00065 00066 class KSpell::KSpellPrivate 00067 { 00068 public: 00069 bool endOfResponse; 00070 bool m_bIgnoreUpperWords; 00071 bool m_bIgnoreTitleCase; 00072 bool m_bNoMisspellingsEncountered; 00073 SpellerType type; 00074 KSpell* suggestSpell; 00075 bool checking; 00076 QValueList<BufferedWord> unchecked; 00077 }; 00078 00079 //TODO 00080 //Parse stderr output 00081 //e.g. -- invalid dictionary name 00082 00083 /* 00084 Things to put in KSpellConfigDlg: 00085 make root/affix combinations that aren't in the dictionary (-m) 00086 don't generate any affix/root combinations (-P) 00087 Report run-together words with missing blanks as spelling errors. (-B) 00088 default dictionary (-d [dictionary]) 00089 personal dictionary (-p [dictionary]) 00090 path to ispell -- NO: ispell should be in $PATH 00091 */ 00092 00093 00094 // Connects a slot to KProcIO's output signal 00095 #define OUTPUT(x) (connect (proc, SIGNAL (readReady(KProcIO *)), this, SLOT (x(KProcIO *)))) 00096 00097 // Disconnect a slot from... 00098 #define NOOUTPUT(x) (disconnect (proc, SIGNAL (readReady(KProcIO *)), this, SLOT (x(KProcIO *)))) 00099 00100 00101 00102 KSpell::KSpell( QWidget *_parent, const QString &_caption, 00103 QObject *obj, const char *slot, KSpellConfig *_ksc, 00104 bool _progressbar, bool _modal ) 00105 { 00106 initialize( _parent, _caption, obj, slot, _ksc, 00107 _progressbar, _modal, Text ); 00108 } 00109 00110 KSpell::KSpell( QWidget *_parent, const QString &_caption, 00111 QObject *obj, const char *slot, KSpellConfig *_ksc, 00112 bool _progressbar, bool _modal, SpellerType type ) 00113 { 00114 initialize( _parent, _caption, obj, slot, _ksc, 00115 _progressbar, _modal, type ); 00116 } 00117 00118 void KSpell::hide() { ksdlg->hide(); } 00119 00120 int KSpell::heightDlg() const { return ksdlg->height(); } 00121 int KSpell::widthDlg() const { return ksdlg->width(); } 00122 00123 00124 void 00125 KSpell::startIspell() 00126 //trystart = {0,1,2} 00127 { 00128 00129 kdDebug(750) << "Try #" << trystart << endl; 00130 00131 if ( trystart > 0 ) { 00132 proc->resetAll(); 00133 } 00134 00135 switch ( ksconfig->client() ) 00136 { 00137 case KS_CLIENT_ISPELL: 00138 *proc << "ispell"; 00139 kdDebug(750) << "Using ispell" << endl; 00140 break; 00141 case KS_CLIENT_ASPELL: 00142 *proc << "aspell"; 00143 kdDebug(750) << "Using aspell" << endl; 00144 break; 00145 case KS_CLIENT_HSPELL: 00146 *proc << "hspell"; 00147 kdDebug(750) << "Using hspell" << endl; 00148 break; 00149 } 00150 00151 if ( ksconfig->client() == KS_CLIENT_ISPELL || ksconfig->client() == KS_CLIENT_ASPELL ) 00152 { 00153 *proc << "-a" << "-S"; 00154 00155 switch ( d->type ) 00156 { 00157 case HTML: 00158 //Debian uses an ispell version that has the -h option instead. 00159 //Not sure what they did, but the preferred spell checker 00160 //on that platform is aspell anyway, so use -H untill I'll come 00161 //up with something better. 00162 *proc << "-H"; 00163 break; 00164 case TeX: 00165 //same for aspell and ispell 00166 *proc << "-t"; 00167 break; 00168 case Nroff: 00169 //only ispell supports 00170 if ( ksconfig->client() == KS_CLIENT_ISPELL ) 00171 *proc << "-n"; 00172 break; 00173 case Text: 00174 default: 00175 //nothing 00176 break; 00177 } 00178 if (ksconfig->noRootAffix()) 00179 { 00180 *proc<<"-m"; 00181 } 00182 if (ksconfig->runTogether()) 00183 { 00184 *proc << "-B"; 00185 } 00186 else 00187 { 00188 *proc << "-C"; 00189 } 00190 00191 00192 if (trystart<2) 00193 { 00194 if (! ksconfig->dictionary().isEmpty()) 00195 { 00196 kdDebug(750) << "using dictionary [" << ksconfig->dictionary() << "]" << endl; 00197 *proc << "-d"; 00198 *proc << ksconfig->dictionary(); 00199 } 00200 } 00201 00202 //Note to potential debuggers: -Tlatin2 _is_ being added on the 00203 // _first_ try. But, some versions of ispell will fail with this 00204 // option, so kspell tries again without it. That's why as 'ps -ax' 00205 // shows "ispell -a -S ..." withou the "-Tlatin2" option. 00206 00207 if ( trystart<1 ) { 00208 switch ( ksconfig->encoding() ) 00209 { 00210 case KS_E_LATIN1: 00211 *proc << "-Tlatin1"; 00212 break; 00213 case KS_E_LATIN2: 00214 *proc << "-Tlatin2"; 00215 break; 00216 case KS_E_LATIN3: 00217 *proc << "-Tlatin3"; 00218 break; 00219 00220 // add the other charsets here 00221 case KS_E_LATIN4: 00222 case KS_E_LATIN5: 00223 case KS_E_LATIN7: 00224 case KS_E_LATIN8: 00225 case KS_E_LATIN9: 00226 case KS_E_LATIN13: 00227 case KS_E_LATIN15: 00228 // will work, if this is the default charset in the dictionary 00229 kdError(750) << "charsets iso-8859-4 .. iso-8859-15 not supported yet" << endl; 00230 break; 00231 case KS_E_UTF8: 00232 *proc << "-Tutf8"; 00233 break; 00234 case KS_E_KOI8U: 00235 *proc << "-w'"; // add ' as a word char 00236 break; 00237 } 00238 } 00239 00240 // -a : pipe mode 00241 // -S : sort suggestions by probable correctness 00242 } 00243 else // hspell doesn't need all the rest of the options 00244 *proc << "-a"; 00245 00246 if (trystart==0) //don't connect these multiple times 00247 { 00248 connect( proc, SIGNAL(receivedStderr(KProcess *, char *, int)), 00249 this, SLOT(ispellErrors(KProcess *, char *, int)) ); 00250 00251 connect( proc, SIGNAL(processExited(KProcess *)), 00252 this, SLOT(ispellExit (KProcess *)) ); 00253 00254 OUTPUT(KSpell2); 00255 } 00256 00257 if ( proc->start() == false ) 00258 { 00259 m_status = Error; 00260 QTimer::singleShot( 0, this, SLOT(emitDeath())); 00261 } 00262 } 00263 00264 void 00265 KSpell::ispellErrors( KProcess *, char *buffer, int buflen ) 00266 { 00267 buffer[buflen-1] = '\0'; 00268 // kdDebug(750) << "ispellErrors [" << buffer << "]\n" << endl; 00269 } 00270 00271 void KSpell::KSpell2( KProcIO * ) 00272 00273 { 00274 QString line; 00275 00276 kdDebug(750) << "KSpell::KSpell2" << endl; 00277 00278 trystart = maxtrystart; //We've officially started ispell and don't want 00279 //to try again if it dies. 00280 00281 if ( proc->readln( line, true ) == -1 ) 00282 { 00283 QTimer::singleShot( 0, this, SLOT(emitDeath()) ); 00284 return; 00285 } 00286 00287 00288 if ( line[0] != '@' ) //@ indicates that ispell is working fine 00289 { 00290 QTimer::singleShot( 0, this, SLOT(emitDeath()) ); 00291 return; 00292 } 00293 00294 //We want to recognize KDE in any text! 00295 if ( ignore("kde") == false) 00296 { 00297 kdDebug(750) << "@KDE was false" << endl; 00298 QTimer::singleShot( 0, this, SLOT(emitDeath()) ); 00299 return; 00300 } 00301 00302 //We want to recognize linux in any text! 00303 if ( ignore("linux") == false ) 00304 { 00305 kdDebug(750) << "@Linux was false" << endl; 00306 QTimer::singleShot( 0, this, SLOT(emitDeath()) ); 00307 return; 00308 } 00309 00310 NOOUTPUT( KSpell2 ); 00311 00312 m_status = Running; 00313 emit ready( this ); 00314 } 00315 00316 void 00317 KSpell::setUpDialog( bool reallyuseprogressbar ) 00318 { 00319 if ( dialogsetup ) 00320 return; 00321 00322 //Set up the dialog box 00323 ksdlg = new KSpellDlg( parent, "dialog", 00324 progressbar && reallyuseprogressbar, modaldlg ); 00325 ksdlg->setCaption( caption ); 00326 00327 connect( ksdlg, SIGNAL(command(int)), 00328 this, SLOT(slotStopCancel(int)) ); 00329 connect( this, SIGNAL(progress(unsigned int)), 00330 ksdlg, SLOT(slotProgress(unsigned int)) ); 00331 00332 #ifdef Q_WS_X11 // FIXME(E): Implement for Qt/Embedded 00333 KWin::setIcons( ksdlg->winId(), kapp->icon(), kapp->miniIcon() ); 00334 #endif 00335 if ( modaldlg ) 00336 ksdlg->setFocus(); 00337 dialogsetup = true; 00338 } 00339 00340 bool KSpell::addPersonal( const QString & word ) 00341 { 00342 QString qs = word.simplifyWhiteSpace(); 00343 00344 //we'll let ispell do the work here b/c we can 00345 if ( qs.find(' ') != -1 || qs.isEmpty() ) // make sure it's a _word_ 00346 return false; 00347 00348 qs.prepend( "*" ); 00349 personaldict = true; 00350 00351 return proc->writeStdin( qs ); 00352 } 00353 00354 bool KSpell::writePersonalDictionary() 00355 { 00356 return proc->writeStdin("#"); 00357 } 00358 00359 bool KSpell::ignore( const QString & word ) 00360 { 00361 QString qs = word.simplifyWhiteSpace(); 00362 00363 //we'll let ispell do the work here b/c we can 00364 if ( qs.find (' ') != -1 || qs.isEmpty() ) // make sure it's a _word_ 00365 return false; 00366 00367 qs.prepend( "@" ); 00368 00369 return proc->writeStdin( qs ); 00370 } 00371 00372 bool 00373 KSpell::cleanFputsWord( const QString & s, bool appendCR ) 00374 { 00375 QString qs(s); 00376 bool empty = true; 00377 00378 for( unsigned int i = 0; i < qs.length(); i++ ) 00379 { 00380 //we need some punctuation for ornaments 00381 if ( qs[i] != '\'' && qs[i] != '\"' && qs[i] != '-' 00382 && qs[i].isPunct() || qs[i].isSpace() ) 00383 { 00384 qs.remove(i,1); 00385 i--; 00386 } else { 00387 if ( qs[i].isLetter() ) 00388 empty=false; 00389 } 00390 } 00391 00392 // don't check empty words, otherwise synchronization will lost 00393 if (empty) 00394 return false; 00395 00396 return proc->writeStdin( "^"+qs, appendCR ); 00397 } 00398 00399 bool 00400 KSpell::cleanFputs( const QString & s, bool appendCR ) 00401 { 00402 QString qs(s); 00403 unsigned l = qs.length(); 00404 00405 // some uses of '$' (e.g. "$0") cause ispell to skip all following text 00406 for( unsigned int i = 0; i < l; ++i ) 00407 { 00408 if( qs[i] == '$' ) 00409 qs[i] = ' '; 00410 } 00411 00412 if ( l<MAXLINELENGTH ) 00413 { 00414 if ( qs.isEmpty() ) 00415 qs=""; 00416 return proc->writeStdin( "^"+qs, appendCR ); 00417 } 00418 else 00419 return proc->writeStdin( QString::fromAscii( "^\n" ),appendCR ); 00420 } 00421 00422 bool KSpell::checkWord( const QString & buffer, bool _usedialog ) 00423 { 00424 if (d->checking) { // don't check multiple words simultaneously 00425 BufferedWord bufferedWord; 00426 bufferedWord.method = Method1; 00427 bufferedWord.word = buffer; 00428 bufferedWord.useDialog = _usedialog; 00429 d->unchecked.append( bufferedWord ); 00430 return true; 00431 } 00432 d->checking = true; 00433 QString qs = buffer.simplifyWhiteSpace(); 00434 00435 if ( qs.find (' ') != -1 || qs.isEmpty() ) { // make sure it's a _word_ 00436 QTimer::singleShot( 0, this, SLOT(checkNext()) ); 00437 return false; 00438 } 00440 dialog3slot = SLOT(checkWord3()); 00441 00442 usedialog = _usedialog; 00443 setUpDialog( false ); 00444 if ( _usedialog ) 00445 { 00446 emitProgress(); 00447 } 00448 else 00449 ksdlg->hide(); 00450 00451 OUTPUT(checkWord2); 00452 // connect (this, SIGNAL (dialog3()), this, SLOT (checkWord3())); 00453 00454 proc->writeStdin( "%" ); // turn off terse mode 00455 proc->writeStdin( buffer ); // send the word to ispell 00456 00457 return true; 00458 } 00459 00460 bool KSpell::checkWord( const QString & buffer, bool _usedialog, bool suggest ) 00461 { 00462 if (d->checking) { // don't check multiple words simultaneously 00463 BufferedWord bufferedWord; 00464 bufferedWord.method = Method2; 00465 bufferedWord.word = buffer; 00466 bufferedWord.useDialog = _usedialog; 00467 bufferedWord.suggest = suggest; 00468 d->unchecked.append( bufferedWord ); 00469 return true; 00470 } 00471 d->checking = true; 00472 QString qs = buffer.simplifyWhiteSpace(); 00473 00474 if ( qs.find (' ') != -1 || qs.isEmpty() ) { // make sure it's a _word_ 00475 QTimer::singleShot( 0, this, SLOT(checkNext()) ); 00476 return false; 00477 } 00478 00480 if ( !suggest ) { 00481 dialog3slot = SLOT(checkWord3()); 00482 usedialog = _usedialog; 00483 setUpDialog( false ); 00484 if ( _usedialog ) 00485 { 00486 emitProgress(); 00487 } 00488 else 00489 ksdlg->hide(); 00490 } 00491 OUTPUT(checkWord2); 00492 // connect (this, SIGNAL (dialog3()), this, SLOT (checkWord3())); 00493 00494 proc->writeStdin( "%" ); // turn off terse mode 00495 proc->writeStdin( buffer ); // send the word to ispell 00496 00497 return true; 00498 } 00499 00500 void KSpell::checkWord2( KProcIO* ) 00501 { 00502 QString word; 00503 QString line; 00504 proc->readln( line, true ); //get ispell's response 00505 00506 /* ispell man page: "Each sentence of text input is terminated with an 00507 additional blank line, indicating that ispell has completed processing 00508 the input line." 00509 <sanders> 00510 But there can be multiple lines returned in the case of an error, 00511 in this case we should consume all the output given otherwise spell checking 00512 can get out of sync. 00513 </sanders> 00514 */ 00515 QString blank_line; 00516 while (proc->readln( blank_line, true ) != -1); // eat the blank line 00517 NOOUTPUT(checkWord2); 00518 00519 bool mistake = ( parseOneResponse(line, word, sugg) == MISTAKE ); 00520 if ( mistake && usedialog ) 00521 { 00522 cwword = word; 00523 dialog( word, sugg, SLOT(checkWord3()) ); 00524 QTimer::singleShot( 0, this, SLOT(checkNext()) ); 00525 return; 00526 } 00527 else if( mistake ) 00528 { 00529 emit misspelling( word, sugg, lastpos ); 00530 } 00531 00532 //emits a "corrected" signal _even_ if no change was made 00533 //so that the calling program knows when the check is complete 00534 emit corrected( word, word, 0L ); 00535 QTimer::singleShot( 0, this, SLOT(checkNext()) ); 00536 } 00537 00538 void KSpell::checkNext() 00539 { 00540 // Queue words to prevent kspell from turning into a fork bomb 00541 d->checking = false; 00542 if (!d->unchecked.empty()) { 00543 BufferedWord buf = d->unchecked.front(); 00544 d->unchecked.pop_front(); 00545 if (buf.method == Method1) 00546 checkWord( buf.word, buf.useDialog ); 00547 else 00548 checkWord( buf.word, buf.useDialog, buf.suggest ); 00549 } 00550 } 00551 00552 void KSpell::suggestWord( KProcIO * ) 00553 { 00554 QString word; 00555 QString line; 00556 proc->readln( line, true ); //get ispell's response 00557 00558 /* ispell man page: "Each sentence of text input is terminated with an 00559 additional blank line, indicating that ispell has completed processing 00560 the input line." */ 00561 QString blank_line; 00562 proc->readln( blank_line, true ); // eat the blank line 00563 00564 NOOUTPUT(checkWord2); 00565 00566 bool mistake = ( parseOneResponse(line, word, sugg) == MISTAKE ); 00567 if ( mistake && usedialog ) 00568 { 00569 cwword=word; 00570 dialog( word, sugg, SLOT(checkWord3()) ); 00571 return; 00572 } 00573 } 00574 00575 void KSpell::checkWord3() 00576 { 00577 disconnect( this, SIGNAL(dialog3()), this, SLOT(checkWord3()) ); 00578 00579 emit corrected( cwword, replacement(), 0L ); 00580 } 00581 00582 QString KSpell::funnyWord( const QString & word ) 00583 // composes a guess from ispell to a readable word 00584 // e.g. "re+fry-y+ies" -> "refries" 00585 { 00586 QString qs; 00587 unsigned int i=0; 00588 00589 for( i=0; word [i]!='\0';i++ ) 00590 { 00591 if (word [i]=='+') 00592 continue; 00593 if (word [i]=='-') 00594 { 00595 QString shorty; 00596 unsigned int j; 00597 int k; 00598 00599 for( j = i+1; word[j] != '\0' && word[j] != '+' && word[j] != '-'; j++ ) 00600 shorty += word[j]; 00601 00602 i = j-1; 00603 00604 if ( ( k = qs.findRev(shorty) ) == 0 || k != -1 ) 00605 qs.remove( k, shorty.length() ); 00606 else 00607 { 00608 qs += '-'; 00609 qs += shorty; //it was a hyphen, not a '-' from ispell 00610 } 00611 } 00612 else 00613 qs += word[i]; 00614 } 00615 00616 return qs; 00617 } 00618 00619 00620 int KSpell::parseOneResponse( const QString &buffer, QString &word, QStringList & sugg ) 00621 // buffer is checked, word and sugg are filled in 00622 // returns 00623 // GOOD if word is fine 00624 // IGNORE if word is in ignorelist 00625 // REPLACE if word is in replacelist 00626 // MISTAKE if word is misspelled 00627 { 00628 word = ""; 00629 posinline=0; 00630 00631 sugg.clear(); 00632 00633 if ( buffer[0] == '*' || buffer[0] == '+' || buffer[0] == '-' ) 00634 { 00635 return GOOD; 00636 } 00637 00638 if ( buffer[0] == '&' || buffer[0] == '?' || buffer[0] == '#' ) 00639 { 00640 int i,j; 00641 00642 00643 word = buffer.mid( 2, buffer.find( ' ', 3 ) -2 ); 00644 //check() needs this 00645 orig=word; 00646 00647 if( d->m_bIgnoreTitleCase && word == word.upper() ) 00648 return IGNORE; 00649 00650 if( d->m_bIgnoreUpperWords && word[0] == word[0].upper() ) 00651 { 00652 QString text = word[0] + word.right( word.length()-1 ).lower(); 00653 if( text == word ) 00654 return IGNORE; 00655 } 00656 00658 //We don't take advantage of ispell's ignore function because 00659 //we can't interrupt ispell's output (when checking a large 00660 //buffer) to add a word to _it's_ ignore-list. 00661 if ( ignorelist.findIndex( word.lower() ) != -1 ) 00662 return IGNORE; 00663 00665 QString qs2; 00666 00667 if ( buffer.find( ':' ) != -1 ) 00668 qs2 = buffer.left( buffer.find(':') ); 00669 else 00670 qs2 = buffer; 00671 00672 posinline = qs2.right( qs2.length()-qs2.findRev(' ') ).toInt()-1; 00673 00675 QStringList::Iterator it = replacelist.begin(); 00676 for( ;it != replacelist.end(); ++it, ++it ) // Skip two entries at a time. 00677 { 00678 if ( word == *it ) // Word matches 00679 { 00680 ++it; 00681 word = *it; // Replace it with the next entry 00682 return REPLACE; 00683 } 00684 } 00685 00687 if ( buffer[0] != '#' ) 00688 { 00689 QString qs = buffer.mid( buffer.find(':')+2, buffer.length() ); 00690 qs += ','; 00691 sugg.clear(); 00692 i = j = 0; 00693 00694 while( (unsigned int)i < qs.length() ) 00695 { 00696 QString temp = qs.mid( i, (j=qs.find (',',i)) - i ); 00697 sugg.append( funnyWord(temp) ); 00698 00699 i=j+2; 00700 } 00701 } 00702 00703 if ( (sugg.count()==1) && (sugg.first() == word) ) 00704 return GOOD; 00705 00706 return MISTAKE; 00707 } 00708 00709 if ( buffer.isEmpty() ) { 00710 kdDebug(750) << "Got an empty response: ignoring"<<endl; 00711 return GOOD; 00712 } 00713 00714 kdError(750) << "HERE?: [" << buffer << "]" << endl; 00715 kdError(750) << "Please report this to zack@kde.org" << endl; 00716 kdError(750) << "Thank you!" << endl; 00717 00718 emit done( false ); 00719 emit done( KSpell::origbuffer ); 00720 return MISTAKE; 00721 } 00722 00723 bool KSpell::checkList (QStringList *_wordlist, bool _usedialog) 00724 // prepare check of string list 00725 { 00726 wordlist=_wordlist; 00727 if ((totalpos=wordlist->count())==0) 00728 return false; 00729 wlIt = wordlist->begin(); 00730 usedialog=_usedialog; 00731 00732 // prepare the dialog 00733 setUpDialog(); 00734 00735 //set the dialog signal handler 00736 dialog3slot = SLOT (checkList4 ()); 00737 00738 proc->writeStdin ("%"); // turn off terse mode & check one word at a time 00739 00740 //lastpos now counts which *word number* we are at in checkListReplaceCurrent() 00741 lastpos = -1; 00742 checkList2(); 00743 00744 // when checked, KProcIO calls checkList3a 00745 OUTPUT(checkList3a); 00746 00747 return true; 00748 } 00749 00750 void KSpell::checkList2 () 00751 // send one word from the list to KProcIO 00752 // invoked first time by checkList, later by checkListReplaceCurrent and checkList4 00753 { 00754 // send next word 00755 if (wlIt != wordlist->end()) 00756 { 00757 kdDebug(750) << "KS::cklist2 " << lastpos << ": " << *wlIt << endl; 00758 00759 d->endOfResponse = false; 00760 bool put; 00761 lastpos++; offset=0; 00762 put = cleanFputsWord (*wlIt); 00763 ++wlIt; 00764 00765 // when cleanFPutsWord failed (e.g. on empty word) 00766 // try next word; may be this is not good for other 00767 // problems, because this will make read the list up to the end 00768 if (!put) { 00769 checkList2(); 00770 } 00771 } 00772 else 00773 // end of word list 00774 { 00775 NOOUTPUT(checkList3a); 00776 ksdlg->hide(); 00777 emit done(true); 00778 } 00779 } 00780 00781 void KSpell::checkList3a (KProcIO *) 00782 // invoked by KProcIO, when data from ispell are read 00783 { 00784 //kdDebug(750) << "start of checkList3a" << endl; 00785 00786 // don't read more data, when dialog is waiting 00787 // for user interaction 00788 if ( dlgon ) { 00789 //kdDebug(750) << "dlgon: don't read more data" << endl; 00790 return; 00791 } 00792 00793 int e, tempe; 00794 00795 QString word; 00796 QString line; 00797 00798 do 00799 { 00800 tempe=proc->readln( line, true ); //get ispell's response 00801 00802 //kdDebug(750) << "checkList3a: read bytes [" << tempe << "]" << endl; 00803 00804 00805 if ( tempe == 0 ) { 00806 d->endOfResponse = true; 00807 //kdDebug(750) << "checkList3a: end of resp" << endl; 00808 } else if ( tempe>0 ) { 00809 if ( (e=parseOneResponse( line, word, sugg ) ) == MISTAKE || 00810 e==REPLACE ) 00811 { 00812 dlgresult=-1; 00813 00814 if ( e == REPLACE ) 00815 { 00816 QString old = *(--wlIt); ++wlIt; 00817 dlgreplacement = word; 00818 checkListReplaceCurrent(); 00819 // inform application 00820 emit corrected( old, *(--wlIt), lastpos ); ++wlIt; 00821 } 00822 else if( usedialog ) 00823 { 00824 cwword = word; 00825 dlgon = true; 00826 // show the dialog 00827 dialog( word, sugg, SLOT(checkList4()) ); 00828 return; 00829 } 00830 else 00831 { 00832 d->m_bNoMisspellingsEncountered = false; 00833 emit misspelling( word, sugg, lastpos ); 00834 } 00835 } 00836 00837 } 00838 emitProgress (); //maybe 00839 00840 // stop when empty line or no more data 00841 } while (tempe > 0); 00842 00843 //kdDebug(750) << "checkList3a: exit loop with [" << tempe << "]" << endl; 00844 00845 // if we got an empty line, t.e. end of ispell/aspell response 00846 // and the dialog isn't waiting for user interaction, send next word 00847 if (d->endOfResponse && !dlgon) { 00848 //kdDebug(750) << "checkList3a: send next word" << endl; 00849 checkList2(); 00850 } 00851 } 00852 00853 void KSpell::checkListReplaceCurrent() 00854 { 00855 00856 // go back to misspelled word 00857 wlIt--; 00858 00859 QString s = *wlIt; 00860 s.replace(posinline+offset,orig.length(),replacement()); 00861 offset += replacement().length()-orig.length(); 00862 wordlist->insert (wlIt, s); 00863 wlIt = wordlist->remove (wlIt); 00864 // wlIt now points to the word after the repalced one 00865 00866 } 00867 00868 void KSpell::checkList4 () 00869 // evaluate dialog return, when a button was pressed there 00870 { 00871 dlgon=false; 00872 QString old; 00873 00874 disconnect (this, SIGNAL (dialog3()), this, SLOT (checkList4())); 00875 00876 //others should have been processed by dialog() already 00877 switch (dlgresult) 00878 { 00879 case KS_REPLACE: 00880 case KS_REPLACEALL: 00881 kdDebug(750) << "KS: cklist4: lastpos: " << lastpos << endl; 00882 old = *(--wlIt); 00883 ++wlIt; 00884 // replace word 00885 checkListReplaceCurrent(); 00886 emit corrected( old, *(--wlIt), lastpos ); 00887 ++wlIt; 00888 break; 00889 case KS_CANCEL: 00890 ksdlg->hide(); 00891 emit done( false ); 00892 return; 00893 case KS_STOP: 00894 ksdlg->hide(); 00895 emit done( true ); 00896 return; 00897 case KS_CONFIG: 00898 ksdlg->hide(); 00899 emit done( false ); 00900 //check( origbuffer.mid( lastpos ), true ); 00901 //trystart = 0; 00902 //proc->disconnect(); 00903 //proc->kill(); 00904 //delete proc; 00905 //proc = new KProcIO( codec ); 00906 //startIspell(); 00907 return; 00908 }; 00909 00910 // read more if there is more, otherwise send next word 00911 if (!d->endOfResponse) { 00912 //kdDebug(750) << "checkList4: read more from response" << endl; 00913 checkList3a(NULL); 00914 } 00915 } 00916 00917 bool KSpell::check( const QString &_buffer, bool _usedialog ) 00918 { 00919 QString qs; 00920 00921 usedialog = _usedialog; 00922 setUpDialog(); 00923 //set the dialog signal handler 00924 dialog3slot = SLOT(check3()); 00925 00926 kdDebug(750) << "KS: check" << endl; 00927 origbuffer = _buffer; 00928 if ( ( totalpos = origbuffer.length() ) == 0 ) 00929 { 00930 emit done( origbuffer ); 00931 return false; 00932 } 00933 00934 00935 // Torben: I corrected the \n\n problem directly in the 00936 // origbuffer since I got errors otherwise 00937 if ( !origbuffer.endsWith("\n\n" ) ) 00938 { 00939 if (origbuffer.at(origbuffer.length()-1)!='\n') 00940 { 00941 origbuffer+='\n'; 00942 origbuffer+='\n'; //shouldn't these be removed at some point? 00943 } 00944 else 00945 origbuffer+='\n'; 00946 } 00947 00948 newbuffer = origbuffer; 00949 00950 // KProcIO calls check2 when read from ispell 00951 OUTPUT( check2 ); 00952 proc->writeStdin( "!" ); 00953 00954 //lastpos is a position in newbuffer (it has offset in it) 00955 offset = lastlastline = lastpos = lastline = 0; 00956 00957 emitProgress(); 00958 00959 // send first buffer line 00960 int i = origbuffer.find( '\n', 0 ) + 1; 00961 qs = origbuffer.mid( 0, i ); 00962 cleanFputs( qs, false ); 00963 00964 lastline=i; //the character position, not a line number 00965 00966 if ( usedialog ) 00967 { 00968 emitProgress(); 00969 } 00970 else 00971 ksdlg->hide(); 00972 00973 return true; 00974 } 00975 00976 00977 void KSpell::check2( KProcIO * ) 00978 // invoked by KProcIO when read from ispell 00979 { 00980 int e, tempe; 00981 QString word; 00982 QString line; 00983 static bool recursive = false; 00984 if (recursive && 00985 !ksdlg ) 00986 { 00987 return; 00988 } 00989 recursive = true; 00990 00991 do 00992 { 00993 tempe = proc->readln( line, false ); //get ispell's response 00994 //kdDebug(750) << "KSpell::check2 (" << tempe << "b)" << endl; 00995 00996 if ( tempe>0 ) 00997 { 00998 if ( ( e=parseOneResponse (line, word, sugg) )==MISTAKE || 00999 e==REPLACE) 01000 { 01001 dlgresult=-1; 01002 01003 // for multibyte encoding posinline needs correction 01004 if (ksconfig->encoding() == KS_E_UTF8) { 01005 // kdDebug(750) << "line: " << origbuffer.mid(lastlastline, 01006 // lastline-lastlastline) << endl; 01007 // kdDebug(750) << "posinline uncorr: " << posinline << endl; 01008 01009 // convert line to UTF-8, cut at pos, convert back to UCS-2 01010 // and get string length 01011 posinline = (QString::fromUtf8( 01012 origbuffer.mid(lastlastline,lastline-lastlastline).utf8(), 01013 posinline)).length(); 01014 // kdDebug(750) << "posinline corr: " << posinline << endl; 01015 } 01016 01017 lastpos = posinline+lastlastline+offset; 01018 01019 //orig is set by parseOneResponse() 01020 01021 if (e==REPLACE) 01022 { 01023 dlgreplacement=word; 01024 emit corrected( orig, replacement(), lastpos ); 01025 offset += replacement().length()-orig.length(); 01026 newbuffer.replace( lastpos, orig.length(), word ); 01027 } 01028 else //MISTAKE 01029 { 01030 cwword = word; 01031 //kdDebug(750) << "(Before dialog) word=[" << word << "] cwword =[" << cwword << "]\n" << endl; 01032 if ( usedialog ) { 01033 // show the word in the dialog 01034 dialog( word, sugg, SLOT(check3()) ); 01035 } else { 01036 // No dialog, just emit misspelling and continue 01037 d->m_bNoMisspellingsEncountered = false; 01038 emit misspelling( word, sugg, lastpos ); 01039 dlgresult = KS_IGNORE; 01040 check3(); 01041 } 01042 recursive = false; 01043 return; 01044 } 01045 } 01046 01047 } 01048 01049 emitProgress(); //maybe 01050 01051 } while( tempe>0 ); 01052 01053 proc->ackRead(); 01054 01055 01056 if ( tempe == -1 ) { //we were called, but no data seems to be ready... 01057 recursive = false; 01058 return; 01059 } 01060 01061 //If there is more to check, then send another line to ISpell. 01062 if ( (unsigned int)lastline < origbuffer.length() ) 01063 { 01064 int i; 01065 QString qs; 01066 01067 //kdDebug(750) << "[EOL](" << tempe << ")[" << temp << "]" << endl; 01068 01069 lastpos = (lastlastline=lastline) + offset; //do we really want this? 01070 i = origbuffer.find('\n', lastline) + 1; 01071 qs = origbuffer.mid( lastline, i-lastline ); 01072 cleanFputs( qs, false ); 01073 lastline = i; 01074 recursive = false; 01075 return; 01076 } 01077 else 01078 //This is the end of it all 01079 { 01080 ksdlg->hide(); 01081 // kdDebug(750) << "check2() done" << endl; 01082 newbuffer.truncate( newbuffer.length()-2 ); 01083 emitProgress(); 01084 emit done( newbuffer ); 01085 } 01086 recursive = false; 01087 } 01088 01089 void KSpell::check3 () 01090 // evaluates the return value of the dialog 01091 { 01092 disconnect (this, SIGNAL (dialog3()), this, SLOT (check3())); 01093 kdDebug(750) << "check3 [" << cwword << "] [" << replacement() << "] " << dlgresult << endl; 01094 01095 //others should have been processed by dialog() already 01096 switch (dlgresult) 01097 { 01098 case KS_REPLACE: 01099 case KS_REPLACEALL: 01100 offset+=replacement().length()-cwword.length(); 01101 newbuffer.replace (lastpos, cwword.length(), 01102 replacement()); 01103 emit corrected (dlgorigword, replacement(), lastpos); 01104 break; 01105 case KS_CANCEL: 01106 // kdDebug(750) << "canceled\n" << endl; 01107 ksdlg->hide(); 01108 emit done( origbuffer ); 01109 return; 01110 case KS_CONFIG: 01111 ksdlg->hide(); 01112 emit done( origbuffer ); 01113 KMessageBox::information( 0, i18n("You have to restart the dialog for changes to take effect") ); 01114 //check( origbuffer.mid( lastpos ), true ); 01115 return; 01116 case KS_STOP: 01117 ksdlg->hide(); 01118 //buffer=newbuffer); 01119 emitProgress(); 01120 emit done (newbuffer); 01121 return; 01122 }; 01123 01124 proc->ackRead(); 01125 } 01126 01127 void 01128 KSpell::slotStopCancel (int result) 01129 { 01130 if (dialogwillprocess) 01131 return; 01132 01133 kdDebug(750) << "KSpell::slotStopCancel [" << result << "]" << endl; 01134 01135 if (result==KS_STOP || result==KS_CANCEL) 01136 if (!dialog3slot.isEmpty()) 01137 { 01138 dlgresult=result; 01139 connect (this, SIGNAL (dialog3()), this, dialog3slot.ascii()); 01140 emit dialog3(); 01141 } 01142 } 01143 01144 01145 void KSpell::dialog( const QString & word, QStringList & sugg, const char *_slot ) 01146 { 01147 dlgorigword = word; 01148 01149 dialog3slot = _slot; 01150 dialogwillprocess = true; 01151 connect( ksdlg, SIGNAL(command(int)), this, SLOT(dialog2(int)) ); 01152 QString tmpBuf = newbuffer; 01153 kdDebug(750)<<" position = "<<lastpos<<endl; 01154 01155 // extract a context string, replace all characters which might confuse 01156 // the RichText display and highlight the possibly wrong word 01157 QString marker( "_MARKER_" ); 01158 tmpBuf.replace( lastpos, word.length(), marker ); 01159 QString context = tmpBuf.mid(QMAX(lastpos-18,0), 2*18+marker.length()); 01160 context.replace( '\n',QString::fromLatin1(" ")); 01161 context.replace( '<', QString::fromLatin1("&lt;") ); 01162 context.replace( '>', QString::fromLatin1("&gt;") ); 01163 context.replace( marker, QString::fromLatin1("<b>%1</b>").arg( word ) ); 01164 context = "<qt>" + context + "</qt>"; 01165 01166 ksdlg->init( word, &sugg, context ); 01167 d->m_bNoMisspellingsEncountered = false; 01168 emit misspelling( word, sugg, lastpos ); 01169 01170 emitProgress(); 01171 ksdlg->show(); 01172 } 01173 01174 void KSpell::dialog2( int result ) 01175 { 01176 QString qs; 01177 01178 disconnect( ksdlg, SIGNAL(command(int)), this, SLOT(dialog2(int)) ); 01179 dialogwillprocess = false; 01180 dlgresult = result; 01181 ksdlg->standby(); 01182 01183 dlgreplacement = ksdlg->replacement(); 01184 01185 //process result here 01186 switch ( dlgresult ) 01187 { 01188 case KS_IGNORE: 01189 emit ignoreword( dlgorigword ); 01190 break; 01191 case KS_IGNOREALL: 01192 // would be better to lower case only words with beginning cap 01193 ignorelist.prepend( dlgorigword.lower() ); 01194 emit ignoreall( dlgorigword ); 01195 break; 01196 case KS_ADD: 01197 addPersonal( dlgorigword ); 01198 personaldict = true; 01199 emit addword( dlgorigword ); 01200 // adding to pesonal dict takes effect at the next line, not the current 01201 ignorelist.prepend( dlgorigword.lower() ); 01202 break; 01203 case KS_REPLACEALL: 01204 { 01205 replacelist.append( dlgorigword ); 01206 QString _replacement = replacement(); 01207 replacelist.append( _replacement ); 01208 emit replaceall( dlgorigword , _replacement ); 01209 } 01210 break; 01211 case KS_SUGGEST: 01212 checkWord( ksdlg->replacement(), false, true ); 01213 return; 01214 break; 01215 } 01216 01217 connect( this, SIGNAL(dialog3()), this, dialog3slot.ascii() ); 01218 emit dialog3(); 01219 } 01220 01221 01222 KSpell::~KSpell() 01223 { 01224 delete proc; 01225 delete ksconfig; 01226 delete ksdlg; 01227 delete d; 01228 } 01229 01230 01231 KSpellConfig KSpell::ksConfig() const 01232 { 01233 ksconfig->setIgnoreList(ignorelist); 01234 ksconfig->setReplaceAllList(replacelist); 01235 return *ksconfig; 01236 } 01237 01238 void KSpell::cleanUp() 01239 { 01240 if ( m_status == Cleaning ) 01241 return; // Ignore 01242 01243 if ( m_status == Running ) 01244 { 01245 if ( personaldict ) 01246 writePersonalDictionary(); 01247 m_status = Cleaning; 01248 } 01249 proc->closeStdin(); 01250 } 01251 01252 void KSpell::ispellExit( KProcess* ) 01253 { 01254 kdDebug() << "KSpell::ispellExit() " << m_status << endl; 01255 01256 if ( (m_status == Starting) && (trystart < maxtrystart) ) 01257 { 01258 trystart++; 01259 startIspell(); 01260 return; 01261 } 01262 01263 if ( m_status == Starting ) 01264 m_status = Error; 01265 else if (m_status == Cleaning) 01266 m_status = d->m_bNoMisspellingsEncountered ? FinishedNoMisspellingsEncountered : Finished; 01267 else if ( m_status == Running ) 01268 m_status = Crashed; 01269 else // Error, Finished, Crashed 01270 return; // Dead already 01271 01272 kdDebug(750) << "Death" << endl; 01273 QTimer::singleShot( 0, this, SLOT(emitDeath()) ); 01274 } 01275 01276 // This is always called from the event loop to make 01277 // sure that the receiver can safely delete the 01278 // KSpell object. 01279 void KSpell::emitDeath() 01280 { 01281 bool deleteMe = autoDelete; // Can't access object after next call! 01282 emit death(); 01283 if ( deleteMe ) 01284 deleteLater(); 01285 } 01286 01287 void KSpell::setProgressResolution (unsigned int res) 01288 { 01289 progres=res; 01290 } 01291 01292 void KSpell::emitProgress () 01293 { 01294 uint nextprog = (uint) (100.*lastpos/(double)totalpos); 01295 01296 if ( nextprog >= curprog ) 01297 { 01298 curprog = nextprog; 01299 emit progress( curprog ); 01300 } 01301 } 01302 01303 void KSpell::moveDlg( int x, int y ) 01304 { 01305 QPoint pt( x,y ), pt2; 01306 pt2 = parent->mapToGlobal( pt ); 01307 ksdlg->move( pt2.x(),pt2.y() ); 01308 } 01309 01310 void KSpell::setIgnoreUpperWords(bool _ignore) 01311 { 01312 d->m_bIgnoreUpperWords=_ignore; 01313 } 01314 01315 void KSpell::setIgnoreTitleCase(bool _ignore) 01316 { 01317 d->m_bIgnoreTitleCase=_ignore; 01318 } 01319 // -------------------------------------------------- 01320 // Stuff for modal (blocking) spell checking 01321 // 01322 // Written by Torben Weis <weis@kde.org>. So please 01323 // send bug reports regarding the modal stuff to me. 01324 // -------------------------------------------------- 01325 01326 int 01327 KSpell::modalCheck( QString& text ) 01328 { 01329 return modalCheck( text,0 ); 01330 } 01331 01332 int 01333 KSpell::modalCheck( QString& text, KSpellConfig* _kcs ) 01334 { 01335 modalreturn = 0; 01336 modaltext = text; 01337 01338 KSpell* spell = new KSpell( 0L, i18n("Spell Checker"), 0 , 01339 0, _kcs, true, true ); 01340 01341 while (spell->status()!=Finished) 01342 kapp->processEvents(); 01343 01344 text = modaltext; 01345 01346 delete spell; 01347 return modalreturn; 01348 } 01349 01350 void KSpell::slotSpellCheckerCorrected( const QString & oldText, const QString & newText, unsigned int pos ) 01351 { 01352 modaltext=modaltext.replace(pos,oldText.length(),newText); 01353 } 01354 01355 01356 void KSpell::slotModalReady() 01357 { 01358 //kdDebug() << qApp->loopLevel() << endl; 01359 //kdDebug(750) << "MODAL READY------------------" << endl; 01360 01361 Q_ASSERT( m_status == Running ); 01362 connect( this, SIGNAL( done( const QString & ) ), 01363 this, SLOT( slotModalDone( const QString & ) ) ); 01364 QObject::connect( this, SIGNAL( corrected( const QString&, const QString&, unsigned int ) ), 01365 this, SLOT( slotSpellCheckerCorrected( const QString&, const QString &, unsigned int ) ) ); 01366 QObject::connect( this, SIGNAL( death() ), 01367 this, SLOT( slotModalSpellCheckerFinished( ) ) ); 01368 check( modaltext ); 01369 } 01370 01371 void KSpell::slotModalDone( const QString &/*_buffer*/ ) 01372 { 01373 //kdDebug(750) << "MODAL DONE " << _buffer << endl; 01374 //modaltext = _buffer; 01375 cleanUp(); 01376 01377 //kdDebug() << "ABOUT TO EXIT LOOP" << endl; 01378 //qApp->exit_loop(); 01379 01380 //modalWidgetHack->close(true); 01381 slotModalSpellCheckerFinished(); 01382 } 01383 01384 void KSpell::slotModalSpellCheckerFinished( ) 01385 { 01386 modalreturn=(int)this->status(); 01387 } 01388 01389 void KSpell::initialize( QWidget *_parent, const QString &_caption, 01390 QObject *obj, const char *slot, KSpellConfig *_ksc, 01391 bool _progressbar, bool _modal, SpellerType type ) 01392 { 01393 d = new KSpellPrivate; 01394 01395 d->m_bIgnoreUpperWords =false; 01396 d->m_bIgnoreTitleCase =false; 01397 d->m_bNoMisspellingsEncountered = true; 01398 d->type = type; 01399 d->checking = false; 01400 autoDelete = false; 01401 modaldlg = _modal; 01402 progressbar = _progressbar; 01403 01404 proc = 0; 01405 ksconfig = 0; 01406 ksdlg = 0; 01407 lastpos = 0; 01408 01409 //won't be using the dialog in ksconfig, just the option values 01410 if ( _ksc != 0 ) 01411 ksconfig = new KSpellConfig( *_ksc ); 01412 else 01413 ksconfig = new KSpellConfig; 01414 01415 codec = 0; 01416 switch ( ksconfig->encoding() ) 01417 { 01418 case KS_E_LATIN1: 01419 codec = QTextCodec::codecForName("ISO 8859-1"); 01420 break; 01421 case KS_E_LATIN2: 01422 codec = QTextCodec::codecForName("ISO 8859-2"); 01423 break; 01424 case KS_E_LATIN3: 01425 codec = QTextCodec::codecForName("ISO 8859-3"); 01426 break; 01427 case KS_E_LATIN4: 01428 codec = QTextCodec::codecForName("ISO 8859-4"); 01429 break; 01430 case KS_E_LATIN5: 01431 codec = QTextCodec::codecForName("ISO 8859-5"); 01432 break; 01433 case KS_E_LATIN7: 01434 codec = QTextCodec::codecForName("ISO 8859-7"); 01435 break; 01436 case KS_E_LATIN8: 01437 codec = QTextCodec::codecForName("ISO 8859-8-i"); 01438 break; 01439 case KS_E_LATIN9: 01440 codec = QTextCodec::codecForName("ISO 8859-9"); 01441 break; 01442 case KS_E_LATIN13: 01443 codec = QTextCodec::codecForName("ISO 8859-13"); 01444 break; 01445 case KS_E_LATIN15: 01446 codec = QTextCodec::codecForName("ISO 8859-15"); 01447 break; 01448 case KS_E_UTF8: 01449 codec = QTextCodec::codecForName("UTF-8"); 01450 break; 01451 case KS_E_KOI8R: 01452 codec = QTextCodec::codecForName("KOI8-R"); 01453 break; 01454 case KS_E_KOI8U: 01455 codec = QTextCodec::codecForName("KOI8-U"); 01456 break; 01457 case KS_E_CP1251: 01458 codec = QTextCodec::codecForName("CP1251"); 01459 break; 01460 case KS_E_CP1255: 01461 codec = QTextCodec::codecForName("CP1255"); 01462 break; 01463 default: 01464 break; 01465 } 01466 01467 kdDebug(750) << __FILE__ << ":" << __LINE__ << " Codec = " << (codec ? codec->name() : "<default>") << endl; 01468 01469 // copy ignore list from ksconfig 01470 ignorelist += ksconfig->ignoreList(); 01471 01472 replacelist += ksconfig->replaceAllList(); 01473 texmode=dlgon=false; 01474 m_status = Starting; 01475 dialogsetup = false; 01476 progres=10; 01477 curprog=0; 01478 01479 dialogwillprocess = false; 01480 dialog3slot = QString::null; 01481 01482 personaldict = false; 01483 dlgresult = -1; 01484 01485 caption = _caption; 01486 01487 parent = _parent; 01488 01489 trystart = 0; 01490 maxtrystart = 2; 01491 01492 if ( obj && slot ) 01493 // caller wants to know when kspell is ready 01494 connect( this, SIGNAL(ready(KSpell *)), obj, slot); 01495 else 01496 // Hack for modal spell checking 01497 connect( this, SIGNAL(ready(KSpell *)), this, SLOT(slotModalReady()) ); 01498 01499 proc = new KProcIO( codec ); 01500 01501 startIspell(); 01502 } 01503 01504 QString KSpell::modaltext; 01505 int KSpell::modalreturn = 0; 01506 QWidget* KSpell::modalWidgetHack = 0; 01507 01508 #include "kspell.moc" 01509
KDE Logo
This file is part of the documentation for kdeui Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:43:29 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003