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