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