1
/* This file is part of the KDE libraries
2
Copyright (C) 1997 David Sweet <dsweet@kde.org>
3
Copyright (C) 2000-2001 Wolfram Diestel <wolfram@steloj.de>
4
Copyright (C) 2002-2003 Laurent Montel <lmontel@mandrakesoft.com>
6
This library is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Library General Public
8
License version 2 as published by the Free Software Foundation.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public License
16
along with this library; see the file COPYING.LIB. If not, write to
17
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
Boston, MA 02111-1307, USA.
28
#include <sys/types.h>
31
#include <stdlib.h> // atoi
37
#include <qtextcodec.h>
39
#include <kapplication.h>
43
#include "koaspell.moc"
45
#include "koSpelldlg.h"
54
KOASpell::KOASpell( KOSpellConfig *_ksc )
59
QTimer::singleShot( 0, this, SLOT( slotEmitCheckerReady() ) );
62
//TODO FIXME !!!! KOSpellConfig not used.
63
void KOASpell::initSpell(KOSpellConfig *_ksc)
66
m_bIgnoreUpperWords=false;
67
m_bIgnoreTitleCase=false;
80
caption=QString::null;
85
KOASpell::KOASpell (QWidget *_parent, const QString &_caption,
87
bool _modal, bool _autocorrect, KOSpellerType _type)
88
:KOSpell(_parent,_caption,_ksc,_modal,_autocorrect, _type )
91
autocorrect = _autocorrect;
97
QTimer::singleShot( 0, this, SLOT( slotEmitCheckerReady() ) );
100
void KOASpell::slotEmitCheckerReady()
103
emit spellCheckerReady();
106
bool KOASpell::initConfig(const QString & language)
108
config = new_aspell_config();
109
kdDebug(30006)<<" ksconfig->dictionary() :"<<ksconfig->dictionary()<<endl;
110
Q_ASSERT( ksconfig->client() == KOS_CLIENT_ASPELL );
111
aspell_config_replace(config, "lang", language.isEmpty() ? (ksconfig->dictionary().isEmpty() ? "en": ksconfig->dictionary().latin1()) : language.latin1() );
113
kdDebug(30006)<<" ksconfig->dictionary() :"<<ksconfig->dictionary()<<endl;
115
AspellCanHaveError * ret;
116
ret = new_aspell_speller(config);
117
if (aspell_error(ret) != 0) {
118
kdDebug(30006)<<"Error :"<<aspell_error_message(ret)<<endl;
119
delete_aspell_can_have_error(ret);
123
My version of aspell uses the iso-8859-x syntax for those...
124
switch (ksconfig->encoding())
127
aspell_config_replace(config, "encoding", "latin1");
130
aspell_config_replace(config, "encoding", "latin2");
133
aspell_config_replace(config, "encoding", "latin3");
135
// add the other charsets here
143
// will work, if this is the default charset in the dictionary
144
kdError(750) << "charsets iso-8859-4 .. iso-8859-15 not supported yet" << endl;
147
aspell_config_replace(config, "encoding", "utf8");
154
aspell_config_replace(config, "ignore-case", ksconfig->ignoreCase()?"true" : "false" );
155
aspell_config_replace(config, "ignore-accents", ksconfig->ignoreAccent()?"true" : "false" );
157
ret = new_aspell_speller(config);
159
delete_aspell_config(config);
161
if (aspell_error(ret) != 0) {
162
printf("Error: %s\n",aspell_error_message(ret));
163
delete_aspell_can_have_error(ret);
166
speller = to_aspell_speller(ret);
167
config = aspell_speller_config(speller);
172
KOASpell::setUpDialog ()
176
bool ret = initConfig();
180
//Set up the dialog box
181
ksdlg=new KOSpellDlg (parent, ksconfig,"dialog", KOSpellConfig::indexFromLanguageFileName( ksconfig->dictionary()), modaldlg, autocorrect );
182
ksdlg->setCaption (caption);
183
#ifdef Q_WS_X11 // FIXME(E): Implement for Qt/Embedded
184
KWin::setIcons (ksdlg->winId(), kapp->icon(), kapp->miniIcon());
190
bool KOASpell::addPersonal (const QString & word)
194
//add to aspell internal.
195
aspell_speller_add_to_personal(speller, word.latin1(), word.length());
196
//save directly into personnal dictionary.
197
writePersonalDictionary();
201
bool KOASpell::writePersonalDictionary ()
205
aspell_speller_save_all_word_lists(speller);
206
kdDebug(30006)<<"aspell_speller_error_message(speller) :"<<aspell_speller_error_message(speller)<<endl;
210
bool KOASpell::ignore (const QString & /*word*/)
212
//fixme !!!!!!!!!!!!!!!!
217
QStringList KOASpell::resultCheckWord( const QString &_word )
219
if (_word.isEmpty() || !speller)
220
return QStringList();
221
kdDebug(30006)<<" aspell_config_retrieve(config, lang) :"<<aspell_config_retrieve(config, "lang")<<endl;
223
const AspellWordList *wl = aspell_speller_suggest(speller, _word.latin1(), -1);
225
kdDebug(30006)<<"Error: "<< aspell_speller_error_message(speller)<<endl;
227
AspellStringEnumeration * els = aspell_word_list_elements(wl);
229
while ( (word2 = aspell_string_enumeration_next(els)) != 0) {
230
result.append( word2 );
231
kdDebug(30006)<<" word2 :"<<word2<<endl;
237
bool KOASpell::spellWord( const QString &_word )
239
QStringList lst =resultCheckWord( _word );
240
if ( lst.isEmpty() && ((lastpos >= (int)origbuffer.length()-1)|| lastpos<0) )
242
//change m_status before to emit signal otherwise
243
//kword + multiframe doesn't work
245
emit done( origbuffer );
248
if ( lst.contains( _word ))
255
void KOASpell::nextWord()
259
bool haveAnNumber = false;
263
for ( i = lastpos; i<(int)origbuffer.length();i++)
265
QChar ch = origbuffer[i];
266
if ( ch.isSpace() || ch.isPunct() )
273
if ( !word.isEmpty() )
274
testIgnoreWord( word, haveAnNumber );
278
while ( word.isEmpty() && (lastpos < (int)origbuffer.length()-1));
279
if ( m_status != Finished && !spellWord( word ))
285
void KOASpell::testIgnoreWord( QString & word, bool haveAnNumber )
287
if ( !ksconfig->spellWordWithNumber() && haveAnNumber )
293
if(m_bIgnoreTitleCase && word==word.upper())
299
if(m_bIgnoreUpperWords && word[0]==word[0].upper())
301
QString text=word[0]+word.right(word.length()-1).lower();
309
//We don't take advantage of ispell's ignore function because
310
//we can't interrupt ispell's output (when checking a large
311
//buffer) to add a word to _it's_ ignore-list.
312
if (!word.isEmpty() &&ignorelist.findIndex(word.lower())!=-1)
318
QStringList::Iterator it = replacelist.begin();
319
for(;it != replacelist.end(); ++it, ++it) // Skip two entries at a time.
321
if (word == *it) // Word matches
323
QString origWord = *it;
325
word = *it; // Replace it with the next entry
326
correctWord( origWord , word);
332
void KOASpell::correctWord( const QString & originalword, const QString & newword )
334
emit corrected (originalword , newword, lastpos+offset-originalword.length());
335
offset+=newword.length()-originalword.length();
336
newbuffer.replace (lastpos+offset, newword.length(), newword );
339
void KOASpell::previousWord()
343
bool haveAnNumber = false;
347
for ( i = lastpos; i>=0;--i)
349
QChar ch = origbuffer[i];
350
if ( ch.isSpace() || ch.isPunct() )
360
if ( !word.isEmpty() )
361
testIgnoreWord( word, haveAnNumber );
365
while ( word.isEmpty() && (lastpos >= 0));
367
if ( m_status != Finished && !spellWord( word ))
374
bool KOASpell::check( const QString &_buffer, bool _usedialog )
379
usedialog = _usedialog;
380
origbuffer = _buffer;
382
if ( ( totalpos = origbuffer.length() ) == 0 )
384
emit done(origbuffer);
388
// Torben: I corrected the \n\n problem directly in the
389
// origbuffer since I got errors otherwise
390
if ( origbuffer.right(2) != "\n\n" )
392
if (origbuffer.at(origbuffer.length()-1)!='\n')
395
origbuffer+='\n'; //shouldn't these be removed at some point?
401
newbuffer=origbuffer;
402
//lastpos is a position in newbuffer (it has offset in it)
403
offset=lastlastline=lastline=0;
407
// send first buffer line
408
int i = origbuffer.find('\n', 0)+1;
410
qs=origbuffer.mid (0,i);
411
lastline=i; //the character position, not a line number
422
void KOASpell::checkNextWord()
427
if ( !ksdlg->previousWord() )
433
void KOASpell::dialog(const QString & word, QStringList & sugg )
439
connect (ksdlg, SIGNAL (command (int)), this, SLOT (dialog2(int)));
440
ksdlg->init (word, &sugg);
441
if (!ksdlg->previousWord())
442
misspellingWord (word, sugg, lastpos+offset-word.length());
444
misspellingWord (word, sugg, lastpos+offset+1);
449
void KOASpell::dialog2 (int result)
454
disconnect (ksdlg, SIGNAL (command (int)), this, SLOT (dialog2(int)));
458
dlgreplacement=ksdlg->replacement();
459
bool testNextWord = true;
460
QString _replacement;
464
emit ignoreword(dlgorigword);
467
// would be better to lower case only words with beginning cap
468
ignorelist.prepend(dlgorigword.lower());
469
emit ignoreall (dlgorigword);
472
addPersonal (dlgorigword);
474
emit addword (dlgorigword);
475
// adding to personal dict takes effect at the next line, not the current
476
ignorelist.prepend(dlgorigword.lower());
479
replacelist.append (dlgorigword);
480
_replacement = replacement();
481
replacelist.append (_replacement);
483
emit replaceall( dlgorigword , _replacement );
484
correctWord( dlgorigword , _replacement );
486
case KOS_ADDAUTOCORRECT:
487
//todo add new word ????
488
emit addAutoCorrect (dlgorigword , replacement());
490
correctWord( dlgorigword , replacement() );
492
case KOS_CHECKAGAINWITHNEWLANGUAGE:
493
changeSpellLanguage( ksdlg->languageIndex());
494
spellCheckReplaceWord( dlgreplacement);
495
testNextWord = false;
498
spellCheckReplaceWord( dlgreplacement);
499
testNextWord = false;
502
testNextWord = false;
505
emit done (newbuffer);
509
testNextWord = false;
510
// kdDebug(30006) << "cancelled\n" << endl;
512
emit done (origbuffer);
520
void KOASpell::spellCheckReplaceWord( const QString & _word)
524
connect (ksdlg, SIGNAL (command (int)), this, SLOT (dialog2(int)));
526
lst=resultCheckWord( _word );
527
ksdlg->changeSuggList( &lst);
531
void KOASpell::deleteSpellChecker()
535
delete_aspell_speller(speller);
540
KOASpell::~KOASpell ()
542
deleteSpellChecker();
546
void KOASpell::changeSpellLanguage( int index )
548
deleteSpellChecker();
549
initConfig( KOSpellConfig::listOfLanguageFileName()[index].latin1());
551
kdDebug(30006)<<"Before KOSpellConfig::listOfLanguageFileName()[index].latin1() :"<<KOSpellConfig::listOfLanguageFileName()[index].latin1()<<endl;
552
aspell_config_replace(config, "lang",KOSpellConfig::listOfLanguageFileName()[index].latin1());
553
kdDebug(30006)<<" After aspell_config_retrieve(config, lang) :"<<aspell_config_retrieve(config, "lang")<<endl;
558
int KOASpell::modalCheck( QString& text, KOSpellConfig* _kcs )
563
KOASpell* m_spell = new KOASpell(0L, i18n("Spell Checker"), 0 ,_kcs,true );
564
QObject::connect( m_spell, SIGNAL( death() ),
565
m_spell, SLOT( slotModalSpellCheckerFinished() ) );
566
QObject::connect( m_spell, SIGNAL( corrected( const QString &, const QString &, unsigned int ) ),
567
m_spell, SLOT( slotSpellCheckerCorrected( const QString &, const QString &, unsigned int ) ) );
568
QObject::connect( m_spell, SIGNAL( done( const QString & ) ),
569
m_spell, SLOT( slotModalDone( const QString & ) ) );
571
bool result = m_spell->check( text );
579
while (m_spell->status()!=Finished)
580
kapp->processEvents();
587
void KOASpell::slotSpellCheckerCorrected( const QString & oldText, const QString & newText, unsigned int pos )
589
modaltext=modaltext.replace(pos,oldText.length(),newText);
593
void KOASpell::slotModalDone( const QString &/*_buffer*/ )
595
slotModalSpellCheckerFinished();
598
void KOASpell::slotModalSpellCheckerFinished()
600
modalreturn=(int)this->status();