00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
#ifdef HAVE_CONFIG_H
00021
#include <config.h>
00022
#endif
00023
00024
#ifdef HAVE_LIBASPELL
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 "koaspell.h"
00043
#include "koaspell.moc"
00044
#include "koSpell.h"
00045
#include "koSpelldlg.h"
00046
#include <kwin.h>
00047
#include <kprocio.h>
00048
00049
#include <qtimer.h>
00050
00051
#include <aspell.h>
00052
00053
00054 KOASpell::KOASpell(
KOSpellConfig *_ksc )
00055 :KOSpell(_ksc)
00056 {
00057 initSpell(_ksc);
00058 initConfig();
00059 QTimer::singleShot( 0,
this, SLOT( slotEmitCheckerReady() ) );
00060 }
00061
00062
00063
void KOASpell::initSpell(
KOSpellConfig *_ksc)
00064 {
00065 Q_UNUSED( _ksc );
00066 m_bIgnoreUpperWords=
false;
00067 m_bIgnoreTitleCase=
false;
00068 autocorrect =
false;
00069 autoDelete =
false;
00070 modaldlg =
false;
00071 speller = 0L;
00072 config = 0L;
00073 offset = 0;
00074 ksdlg=0;
00075 lastpos = -1;
00076
00077 personaldict=FALSE;
00078 dlgresult=-1;
00079
00080 caption=QString::null;
00081
00082 parent=0L;
00083 }
00084
00085 KOASpell::KOASpell (
QWidget *_parent,
const QString &_caption,
00086
KOSpellConfig *_ksc,
00087
bool _modal,
bool _autocorrect, KOSpellerType _type)
00088 :KOSpell(_parent,_caption,_ksc,_modal,_autocorrect, _type )
00089 {
00090 initSpell(_ksc);
00091 autocorrect = _autocorrect;
00092 modaldlg = _modal;
00093 caption=_caption;
00094 parent=_parent;
00095
00096 setUpDialog();
00097 QTimer::singleShot( 0,
this, SLOT( slotEmitCheckerReady() ) );
00098 }
00099
00100
void KOASpell::slotEmitCheckerReady()
00101 {
00102 emit ready(
this );
00103 emit spellCheckerReady();
00104 }
00105
00106
bool KOASpell::initConfig(
const QString & language)
00107 {
00108 config = new_aspell_config();
00109 kdDebug(30006)<<
" ksconfig->dictionary() :"<<ksconfig->dictionary()<<endl;
00110 Q_ASSERT( ksconfig->client() == KOS_CLIENT_ASPELL );
00111 aspell_config_replace(config,
"lang", language.isEmpty() ? (ksconfig->dictionary().isEmpty() ?
"en": ksconfig->dictionary().latin1()) : language.latin1() );
00112
00113 kdDebug(30006)<<
" ksconfig->dictionary() :"<<ksconfig->dictionary()<<endl;
00114
00115 AspellCanHaveError * ret;
00116 ret = new_aspell_speller(config);
00117
if (aspell_error(ret) != 0) {
00118 kdDebug(30006)<<
"Error :"<<aspell_error_message(ret)<<endl;
00119 delete_aspell_can_have_error(ret);
00120
return false;
00121 }
00154 aspell_config_replace(config,
"ignore-case", ksconfig->ignoreCase()?
"true" :
"false" );
00155 aspell_config_replace(config,
"ignore-accents", ksconfig->ignoreAccent()?
"true" :
"false" );
00156
00157 ret = new_aspell_speller(config);
00158
00159 delete_aspell_config(config);
00160
00161
if (aspell_error(ret) != 0) {
00162 printf(
"Error: %s\n",aspell_error_message(ret));
00163 delete_aspell_can_have_error(ret);
00164
return false;
00165 }
00166 speller = to_aspell_speller(ret);
00167 config = aspell_speller_config(speller);
00168
return true;
00169 }
00170
00171
void
00172 KOASpell::setUpDialog ()
00173 {
00174
if (ksdlg)
00175
return;
00176
bool ret = initConfig();
00177
if ( !ret )
00178
return;
00179
00180
00181 ksdlg=
new KOSpellDlg (parent, ksconfig,
"dialog", KOSpellConfig::indexFromLanguageFileName( ksconfig->dictionary()), modaldlg, autocorrect );
00182 ksdlg->setCaption (caption);
00183
#ifdef Q_WS_X11 // FIXME(E): Implement for Qt/Embedded
00184
KWin::setIcons (ksdlg->winId(), kapp->icon(), kapp->miniIcon());
00185
#endif
00186
if ( modaldlg )
00187 ksdlg->setFocus();
00188 }
00189
00190
bool KOASpell::addPersonal (
const QString & word)
00191 {
00192
if( !speller)
00193
return false;
00194
00195 aspell_speller_add_to_personal(speller, word.latin1(), word.length());
00196
00197 writePersonalDictionary();
00198
return true;
00199 }
00200
00201
bool KOASpell::writePersonalDictionary ()
00202 {
00203
if( !speller)
00204
return false;
00205 aspell_speller_save_all_word_lists(speller);
00206 kdDebug(30006)<<
"aspell_speller_error_message(speller) :"<<aspell_speller_error_message(speller)<<endl;
00207
return true;
00208 }
00209
00210
bool KOASpell::ignore (
const QString & )
00211 {
00212
00213
return true;
00214 }
00215
00216
00217
QStringList KOASpell::resultCheckWord(
const QString &_word )
00218 {
00219
if (_word.isEmpty() || !speller)
00220
return QStringList();
00221 kdDebug(30006)<<
" aspell_config_retrieve(config, lang) :"<<aspell_config_retrieve(config,
"lang")<<endl;
00222
QStringList result;
00223
const AspellWordList *wl = aspell_speller_suggest(speller, _word.latin1(), -1);
00224
if (wl == 0) {
00225 kdDebug(30006)<<
"Error: "<< aspell_speller_error_message(speller)<<endl;
00226 }
else {
00227 AspellStringEnumeration * els = aspell_word_list_elements(wl);
00228
const char * word2;
00229
while ( (word2 = aspell_string_enumeration_next(els)) != 0) {
00230 result.append( word2 );
00231 kdDebug(30006)<<
" word2 :"<<word2<<endl;
00232 }
00233 }
00234
return result;
00235 }
00236
00237
bool KOASpell::spellWord(
const QString &_word )
00238 {
00239
QStringList lst =resultCheckWord( _word );
00240
if ( lst.isEmpty() && ((lastpos >= (
int)origbuffer.length()-1)|| lastpos<0) )
00241 {
00242
00243
00244 m_status = Finished;
00245 emit done( origbuffer );
00246
return false;
00247 }
00248
if ( lst.contains( _word ))
00249
return false;
00250
00251 dialog( _word, lst);
00252
return true;
00253 }
00254
00255
void KOASpell::nextWord()
00256 {
00257
QString word;
00258 lastpos++;
00259
bool haveAnNumber =
false;
00260
do
00261 {
00262
int i =0;
00263
for ( i = lastpos; i<(
int)origbuffer.length();i++)
00264 {
00265
QChar ch = origbuffer[i];
00266
if ( ch.isSpace() || ch.isPunct() )
00267
break;
00268
if ( ch.isNumber() )
00269 haveAnNumber =
true;
00270 word.append(ch);
00271 }
00272 lastpos = i;
00273
if ( !word.isEmpty() )
00274 testIgnoreWord( word, haveAnNumber );
00275
else
00276 lastpos++;
00277 }
00278
while ( word.isEmpty() && (lastpos < (
int)origbuffer.length()-1));
00279
if ( m_status != Finished && !spellWord( word ))
00280 {
00281 checkNextWord();
00282 }
00283 }
00284
00285
void KOASpell::testIgnoreWord(
QString & word,
bool haveAnNumber )
00286 {
00287
if ( !ksconfig->spellWordWithNumber() && haveAnNumber )
00288 {
00289 word =
"";
00290
return;
00291 }
00292
00293
if(m_bIgnoreTitleCase && word==word.upper())
00294 {
00295 word =
"";
00296
return;
00297 }
00298
00299
if(m_bIgnoreUpperWords && word[0]==word[0].upper())
00300 {
00301
QString text=word[0]+word.right(word.length()-1).lower();
00302
if(text==word)
00303 {
00304 word =
"";
00305
return;
00306 }
00307 }
00308
00309
00310
00311
00312
if (!word.isEmpty() &&ignorelist.findIndex(word.lower())!=-1)
00313 {
00314 word =
"";
00315
return;
00316 }
00317
00318 QStringList::Iterator it = replacelist.begin();
00319
for(;it != replacelist.end(); ++it, ++it)
00320 {
00321
if (word == *it)
00322 {
00323
QString origWord = *it;
00324 ++it;
00325 word = *it;
00326 correctWord( origWord , word);
00327 word =
"";
00328 }
00329 }
00330 }
00331
00332
void KOASpell::correctWord(
const QString & originalword,
const QString & newword )
00333 {
00334 emit corrected (originalword , newword, lastpos+offset-originalword.length());
00335 offset+=newword.length()-originalword.length();
00336 newbuffer.replace (lastpos+offset, newword.length(), newword );
00337 }
00338
00339
void KOASpell::previousWord()
00340 {
00341
QString word;
00342 lastpos--;
00343
bool haveAnNumber =
false;
00344
do
00345 {
00346
int i =0;
00347
for ( i = lastpos; i>=0;--i)
00348 {
00349
QChar ch = origbuffer[i];
00350
if ( ch.isSpace() || ch.isPunct() )
00351 {
00352 lastpos--;
00353
break;
00354 }
00355
if ( ch.isNumber() )
00356 haveAnNumber =
true;
00357 word.prepend(ch);
00358 }
00359 lastpos = i;
00360
if ( !word.isEmpty() )
00361 testIgnoreWord( word, haveAnNumber );
00362
else
00363 lastpos--;
00364 }
00365
while ( word.isEmpty() && (lastpos >= 0));
00366
00367
if ( m_status != Finished && !spellWord( word ))
00368 {
00369 checkNextWord();
00370 }
00371
00372 }
00373
00374
bool KOASpell::check(
const QString &_buffer,
bool _usedialog )
00375 {
00376
if( !ksdlg )
00377
return false;
00378 lastpos = -1;
00379 usedialog = _usedialog;
00380 origbuffer = _buffer;
00381 m_status = Starting;
00382
if ( ( totalpos = origbuffer.length() ) == 0 )
00383 {
00384 emit done(origbuffer);
00385
return FALSE;
00386 }
00387
00388
00389
00390
if ( origbuffer.right(2) !=
"\n\n" )
00391 {
00392
if (origbuffer.at(origbuffer.length()-1)!=
'\n')
00393 {
00394 origbuffer+=
'\n';
00395 origbuffer+=
'\n';
00396 }
00397
else
00398 origbuffer+=
'\n';
00399 }
00400
00401 newbuffer=origbuffer;
00402
00403 offset=lastlastline=lastline=0;
00404 lastpos = -1;
00405
00406
00407
00408
int i = origbuffer.find(
'\n', 0)+1;
00409
QString qs;
00410 qs=origbuffer.mid (0,i);
00411 lastline=i;
00412
if (_usedialog)
00413 ksdlg->show();
00414
else
00415 ksdlg->hide();
00416
00417
00418 checkNextWord();
00419
return TRUE;
00420 }
00421
00422
void KOASpell::checkNextWord()
00423 {
00424
if ( !ksdlg)
00425
return;
00426
00427
if ( !ksdlg->previousWord() )
00428 nextWord();
00429
else
00430 previousWord();
00431 }
00432
00433
void KOASpell::dialog(
const QString & word,
QStringList & sugg )
00434 {
00435
if ( !ksdlg )
00436
return;
00437 dlgorigword=word;
00438
00439 connect (ksdlg, SIGNAL (command (
int)),
this, SLOT (dialog2(
int)));
00440 ksdlg->init (word, &sugg);
00441
if (!ksdlg->previousWord())
00442 misspellingWord (word, sugg, lastpos+offset-word.length());
00443
else
00444 misspellingWord (word, sugg, lastpos+offset+1);
00445
00446 ksdlg->show();
00447 }
00448
00449
void KOASpell::dialog2 (
int result)
00450 {
00451
if ( !ksdlg )
00452
return;
00453
QString qs;
00454 disconnect (ksdlg, SIGNAL (command (
int)),
this, SLOT (dialog2(
int)));
00455 dlgresult=result;
00456 ksdlg->standby();
00457
00458 dlgreplacement=ksdlg->replacement();
00459
bool testNextWord =
true;
00460
QString _replacement;
00461
switch (dlgresult)
00462 {
00463
case KOS_IGNORE:
00464 emit ignoreword(dlgorigword);
00465
break;
00466
case KOS_IGNOREALL:
00467
00468 ignorelist.prepend(dlgorigword.lower());
00469 emit ignoreall (dlgorigword);
00470
break;
00471
case KOS_ADD:
00472 addPersonal (dlgorigword);
00473 personaldict=TRUE;
00474 emit addword (dlgorigword);
00475
00476 ignorelist.prepend(dlgorigword.lower());
00477
break;
00478
case KOS_REPLACEALL:
00479 replacelist.append (dlgorigword);
00480 _replacement = replacement();
00481 replacelist.append (_replacement);
00482
00483 emit replaceall( dlgorigword , _replacement );
00484 correctWord( dlgorigword , _replacement );
00485
break;
00486
case KOS_ADDAUTOCORRECT:
00487
00488 emit addAutoCorrect (dlgorigword , replacement());
00489
case KOS_REPLACE:
00490 correctWord( dlgorigword , replacement() );
00491
break;
00492
case KOS_CHECKAGAINWITHNEWLANGUAGE:
00493 changeSpellLanguage( ksdlg->languageIndex());
00494 spellCheckReplaceWord( dlgreplacement);
00495 testNextWord =
false;
00496
break;
00497
case KOS_CHECKAGAIN:
00498 spellCheckReplaceWord( dlgreplacement);
00499 testNextWord =
false;
00500
break;
00501
case KOS_STOP:
00502 testNextWord =
false;
00503 ksdlg->hide();
00504
00505 emit done (newbuffer);
00506 emit death();
00507
break;
00508
case KOS_CANCEL:
00509 testNextWord =
false;
00510
00511 ksdlg->hide();
00512 emit done (origbuffer);
00513 emit death();
00514
break;
00515 }
00516
if ( testNextWord)
00517 checkNextWord();
00518 }
00519
00520
void KOASpell::spellCheckReplaceWord(
const QString & _word)
00521 {
00522
if ( !ksdlg )
00523
return;
00524 connect (ksdlg, SIGNAL (command (
int)),
this, SLOT (dialog2(
int)));
00525
QStringList lst;
00526 lst=resultCheckWord( _word );
00527 ksdlg->changeSuggList( &lst);
00528 ksdlg->show();
00529 }
00530
00531
void KOASpell::deleteSpellChecker()
00532 {
00533
if( speller )
00534 {
00535 delete_aspell_speller(speller);
00536 speller = 0;
00537 }
00538 }
00539
00540 KOASpell::~KOASpell ()
00541 {
00542 deleteSpellChecker();
00543 }
00544
00545
00546
void KOASpell::changeSpellLanguage(
int index )
00547 {
00548 deleteSpellChecker();
00549 initConfig( KOSpellConfig::listOfLanguageFileName()[index].latin1());
00550
#if 0
00551
kdDebug(30006)<<
"Before KOSpellConfig::listOfLanguageFileName()[index].latin1() :"<<KOSpellConfig::listOfLanguageFileName()[index].latin1()<<endl;
00552 aspell_config_replace(config,
"lang",KOSpellConfig::listOfLanguageFileName()[index].latin1());
00553 kdDebug(30006)<<
" After aspell_config_retrieve(config, lang) :"<<aspell_config_retrieve(config,
"lang")<<endl;
00554
#endif
00555
}
00556
00557
00558
int KOASpell::modalCheck(
QString& text,
KOSpellConfig* _kcs )
00559 {
00560 modalreturn = 0;
00561 modaltext = text;
00562
00563 KOASpell* m_spell =
new KOASpell(0L, i18n(
"Spell Checker"), 0 ,_kcs,
true );
00564 QObject::connect( m_spell, SIGNAL( death() ),
00565 m_spell, SLOT( slotModalSpellCheckerFinished() ) );
00566 QObject::connect( m_spell, SIGNAL( corrected(
const QString &,
const QString &,
unsigned int ) ),
00567 m_spell, SLOT( slotSpellCheckerCorrected(
const QString &,
const QString &,
unsigned int ) ) );
00568 QObject::connect( m_spell, SIGNAL( done(
const QString & ) ),
00569 m_spell, SLOT( slotModalDone(
const QString & ) ) );
00570
00571
bool result = m_spell->check( text );
00572
if ( !result)
00573 {
00574
delete m_spell;
00575 m_spell=0L;
00576
return modalreturn;
00577 }
00578
00579
while (m_spell->status()!=Finished)
00580 kapp->processEvents();
00581
00582 text = modaltext;
00583
delete m_spell;
00584
return modalreturn;
00585 }
00586
00587
void KOASpell::slotSpellCheckerCorrected(
const QString & oldText,
const QString & newText,
unsigned int pos )
00588 {
00589 modaltext=modaltext.replace(pos,oldText.length(),newText);
00590 }
00591
00592
00593
void KOASpell::slotModalDone(
const QString & )
00594 {
00595 slotModalSpellCheckerFinished();
00596 }
00597
00598
void KOASpell::slotModalSpellCheckerFinished()
00599 {
00600 modalreturn=(
int)this->status();
00601 }
00602
00603
00604
#endif
00605
00606