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