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