lib Library API Documentation

koaspell.cpp

00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1997 David Sweet <dsweet@kde.org> 00003 Copyright (C) 2000-2001 Wolfram Diestel <wolfram@steloj.de> 00004 Copyright (C) 2002-2003 Laurent Montel <lmontel@mandrakesoft.com> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License version 2 as published by the Free Software Foundation. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, USA. 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> // atoi 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 //TODO FIXME !!!! KOSpellConfig not used. 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 //Set up the dialog box 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 //add to aspell internal. 00195 aspell_speller_add_to_personal(speller, word.latin1(), word.length()); 00196 //save directly into personnal dictionary. 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 & /*word*/) 00211 { 00212 //fixme !!!!!!!!!!!!!!!! 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 //change m_status before to emit signal otherwise 00243 //kword + multiframe doesn't work 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 //We don't take advantage of ispell's ignore function because 00310 //we can't interrupt ispell's output (when checking a large 00311 //buffer) to add a word to _it's_ ignore-list. 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) // Skip two entries at a time. 00320 { 00321 if (word == *it) // Word matches 00322 { 00323 QString origWord = *it; 00324 ++it; 00325 word = *it; // Replace it with the next entry 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 // Torben: I corrected the \n\n problem directly in the 00389 // origbuffer since I got errors otherwise 00390 if ( origbuffer.right(2) != "\n\n" ) 00391 { 00392 if (origbuffer.at(origbuffer.length()-1)!='\n') 00393 { 00394 origbuffer+='\n'; 00395 origbuffer+='\n'; //shouldn't these be removed at some point? 00396 } 00397 else 00398 origbuffer+='\n'; 00399 } 00400 00401 newbuffer=origbuffer; 00402 //lastpos is a position in newbuffer (it has offset in it) 00403 offset=lastlastline=lastline=0; 00404 lastpos = -1; 00405 00406 00407 // send first buffer line 00408 int i = origbuffer.find('\n', 0)+1; 00409 QString qs; 00410 qs=origbuffer.mid (0,i); 00411 lastline=i; //the character position, not a line number 00412 if (_usedialog) 00413 ksdlg->show(); 00414 else 00415 ksdlg->hide(); 00416 00417 //check new word. 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 // would be better to lower case only words with beginning cap 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 // adding to personal dict takes effect at the next line, not the current 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 //todo add new word ???? 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 //buffer=newbuffer); 00505 emit done (newbuffer); 00506 emit death(); 00507 break; 00508 case KOS_CANCEL: 00509 testNextWord = false; 00510 // kdDebug(30006) << "cancelled\n" << endl; 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 &/*_buffer*/ ) 00594 { 00595 slotModalSpellCheckerFinished(); 00596 } 00597 00598 void KOASpell::slotModalSpellCheckerFinished() 00599 { 00600 modalreturn=(int)this->status(); 00601 } 00602 00603 00604 #endif 00605 00606
KDE Logo
This file is part of the documentation for lib Library Version 1.3.5.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Nov 17 06:54:14 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003