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