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