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 QTimer *checkNextTimer;
00078 };
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 #define OUTPUT(x) (connect (proc, SIGNAL (readReady(KProcIO *)), this, SLOT (x(KProcIO *))))
00097
00098
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
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
00160
00161
00162
00163 *proc << "-H";
00164 break;
00165 case TeX:
00166
00167 *proc << "-t";
00168 break;
00169 case Nroff:
00170
00171 if ( ksconfig->client() == KS_CLIENT_ISPELL )
00172 *proc << "-n";
00173 break;
00174 case Text:
00175 default:
00176
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
00204
00205
00206
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
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
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'";
00237 break;
00238 }
00239 }
00240
00241
00242
00243 }
00244 else
00245 *proc << "-a";
00246
00247 if (trystart==0)
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
00270 }
00271
00272 void KSpell::KSpell2( KProcIO * )
00273
00274 {
00275 QString line;
00276
00277 kdDebug(750) << "KSpell::KSpell2" << endl;
00278
00279 trystart = maxtrystart;
00280
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] != '@' )
00290 {
00291 QTimer::singleShot( 0, this, SLOT(emitDeath()) );
00292 return;
00293 }
00294
00295
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
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
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
00346 if ( qs.find(' ') != -1 || qs.isEmpty() )
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
00365 if ( qs.find (' ') != -1 || qs.isEmpty() )
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
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
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
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) {
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() ) {
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);
00454
00455 OUTPUT(checkWord2);
00456
00457
00458 proc->writeStdin( "%" );
00459 proc->writeStdin( buffer );
00460
00461 return true;
00462 }
00463
00464 bool KSpell::checkWord( const QString & buffer, bool _usedialog, bool suggest )
00465 {
00466 if (d->checking) {
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() ) {
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);
00498
00499 OUTPUT(checkWord2);
00500
00501
00502 proc->writeStdin( "%" );
00503 proc->writeStdin( buffer );
00504
00505 return true;
00506 }
00507
00508 void KSpell::checkWord2( KProcIO* )
00509 {
00510 QString word;
00511 QString line;
00512 proc->readln( line, true );
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523 QString blank_line;
00524 while (proc->readln( blank_line, true ) != -1);
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
00541
00542 emit corrected( word, word, 0L );
00543 d->checkNextTimer->start( 0, true );
00544 }
00545
00546 void KSpell::checkNext()
00547 {
00548
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 );
00566
00567
00568
00569
00570 QString blank_line;
00571 proc->readln( blank_line, true );
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
00593
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;
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
00631
00632
00633
00634
00635
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
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
00668
00669
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 )
00686 {
00687 if ( word == *it )
00688 {
00689 ++it;
00690 word = *it;
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
00734 {
00735 wordlist=_wordlist;
00736 if ((totalpos=wordlist->count())==0)
00737 return false;
00738 wlIt = wordlist->begin();
00739 usedialog=_usedialog;
00740
00741
00742 setUpDialog();
00743
00744
00745 dialog3slot = SLOT (checkList4 ());
00746
00747 proc->writeStdin ("%");
00748
00749
00750 lastpos = -1;
00751 checkList2();
00752
00753
00754 OUTPUT(checkList3a);
00755
00756 return true;
00757 }
00758
00759 void KSpell::checkList2 ()
00760
00761
00762 {
00763
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
00775
00776
00777 if (!put) {
00778 checkList2();
00779 }
00780 }
00781 else
00782
00783 {
00784 NOOUTPUT(checkList3a);
00785 ksdlg->hide();
00786 emit done(true);
00787 }
00788 }
00789
00790 void KSpell::checkList3a (KProcIO *)
00791
00792 {
00793
00794
00795
00796
00797 if ( dlgon ) {
00798
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 );
00810
00811
00812
00813
00814 if ( tempe == 0 ) {
00815 d->endOfResponse = true;
00816
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
00829 emit corrected( old, *(--wlIt), lastpos ); ++wlIt;
00830 }
00831 else if( usedialog )
00832 {
00833 cwword = word;
00834 dlgon = true;
00835
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 ();
00848
00849
00850 } while (tempe > 0);
00851
00852
00853
00854
00855
00856 if (d->endOfResponse && !dlgon) {
00857
00858 checkList2();
00859 }
00860 }
00861
00862 void KSpell::checkListReplaceCurrent()
00863 {
00864
00865
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
00874
00875 }
00876
00877 void KSpell::checkList4 ()
00878
00879 {
00880 dlgon=false;
00881 QString old;
00882
00883 disconnect (this, SIGNAL (dialog3()), this, SLOT (checkList4()));
00884
00885
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
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
00910
00911
00912
00913
00914
00915
00916 return;
00917 };
00918
00919
00920 if (!d->endOfResponse) {
00921
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
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
00945
00946 if ( !origbuffer.endsWith("\n\n" ) )
00947 {
00948 if (origbuffer.at(origbuffer.length()-1)!='\n')
00949 {
00950 origbuffer+='\n';
00951 origbuffer+='\n';
00952 }
00953 else
00954 origbuffer+='\n';
00955 }
00956
00957 newbuffer = origbuffer;
00958
00959
00960 OUTPUT( check2 );
00961 proc->writeStdin( "!" );
00962
00963
00964 offset = lastlastline = lastpos = lastline = 0;
00965
00966 emitProgress();
00967
00968
00969 int i = origbuffer.find( '\n', 0 ) + 1;
00970 qs = origbuffer.mid( 0, i );
00971 cleanFputs( qs, false );
00972
00973 lastline=i;
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
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 );
01003
01004
01005 if ( tempe>0 )
01006 {
01007 if ( ( e=parseOneResponse (line, word, sugg) )==MISTAKE ||
01008 e==REPLACE)
01009 {
01010 dlgresult=-1;
01011
01012
01013 if (ksconfig->encoding() == KS_E_UTF8) {
01014
01015
01016
01017
01018
01019
01020 posinline = (QString::fromUtf8(
01021 origbuffer.mid(lastlastline,lastline-lastlastline).utf8(),
01022 posinline)).length();
01023
01024 }
01025
01026 lastpos = posinline+lastlastline+offset;
01027
01028
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
01038 {
01039 cwword = word;
01040
01041 if ( usedialog ) {
01042
01043 dialog( word, sugg, SLOT(check3()) );
01044 } else {
01045
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();
01059
01060 } while( tempe>0 );
01061
01062 proc->ackRead();
01063
01064
01065 if ( tempe == -1 ) {
01066 recursive = false;
01067 return;
01068 }
01069
01070
01071 if ( (unsigned int)lastline < origbuffer.length() )
01072 {
01073 int i;
01074 QString qs;
01075
01076
01077
01078 lastpos = (lastlastline=lastline) + offset;
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
01088 {
01089 ksdlg->hide();
01090
01091 newbuffer.truncate( newbuffer.length()-2 );
01092 emitProgress();
01093 emit done( newbuffer );
01094 }
01095 recursive = false;
01096 }
01097
01098 void KSpell::check3 ()
01099
01100 {
01101 disconnect (this, SIGNAL (dialog3()), this, SLOT (check3()));
01102 kdDebug(750) << "check3 [" << cwword << "] [" << replacement() << "] " << dlgresult << endl;
01103
01104
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
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
01124 return;
01125 case KS_STOP:
01126 ksdlg->hide();
01127
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
01165
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("<") );
01171 context.replace( '>', QString::fromLatin1(">") );
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
01195 switch ( dlgresult )
01196 {
01197 case KS_IGNORE:
01198 emit ignoreword( dlgorigword );
01199 break;
01200 case KS_IGNOREALL:
01201
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
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;
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
01280 return;
01281
01282 kdDebug(750) << "Death" << endl;
01283 QTimer::singleShot( 0, this, SLOT(emitDeath()) );
01284 }
01285
01286
01287
01288
01289 void KSpell::emitDeath()
01290 {
01291 bool deleteMe = autoDelete;
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
01331
01332
01333
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
01369
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 & )
01382 {
01383
01384
01385 cleanUp();
01386
01387
01388
01389
01390
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
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
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
01507 connect( this, SIGNAL(ready(KSpell *)), obj, slot);
01508 else
01509
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