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