• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDE3Support

k3spell.cpp

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

KDE3Support

Skip menu "KDE3Support"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal