00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
#include "koBgSpellCheck.h"
00023
#include "koBgSpellCheck.moc"
00024
#include <qtimer.h>
00025
#include <kdebug.h>
00026
#include <kospell.h>
00027
#include <koSconfig.h>
00028
#include <ksconfig.h>
00029
#include <kotextobject.h>
00030
#include <klocale.h>
00031
00032
00033
00034
class KoBgSpellCheck::KoBgSpellCheckPrivate
00035 {
00036
public:
00037 KSpellConfig * m_pKSpellConfig;
00038
QTimer * startTimer;
00039
QTimer * nextParagraphTimer;
00040 };
00041
00042 KoBgSpellCheck::KoBgSpellCheck()
00043 {
00044
#ifdef DEBUG_BGSPELLCHECKING
00045
kdDebug(32500) <<
"KoBgSpellCheck::KoBgSpellCheck " <<
this << endl;
00046
#endif
00047
d =
new KoBgSpellCheck::KoBgSpellCheckPrivate;
00048 d->m_pKSpellConfig=0L;
00049 d->startTimer =
new QTimer(
this );
00050 connect( d->startTimer, SIGNAL( timeout() ),
00051
this, SLOT( startBackgroundSpellCheck() ) );
00052 d->nextParagraphTimer =
new QTimer(
this );
00053 connect( d->nextParagraphTimer, SIGNAL( timeout() ),
00054
this, SLOT( spellCheckNextParagraph() ) );
00055
00056 m_bgSpell.kspell=0L;
00057 m_bDontCheckUpperWord=
false;
00058 m_bSpellCheckEnabled=
false;
00059 m_bDontCheckTitleCase=
false;
00060 m_bSpellCheckConfigure=
false;
00061 m_bgSpell.currentTextObj=0L;
00062 m_bgSpell.needsRepaint=
false;
00063 }
00064
00065 KoBgSpellCheck::~KoBgSpellCheck()
00066 {
00067
if ( m_bgSpell.kspell ) {
00068 m_bgSpell.kspell->cleanUp();
00069
delete m_bgSpell.kspell;
00070 }
00071
delete d->m_pKSpellConfig;
00072
delete d;
00073 }
00074
00075
void KoBgSpellCheck::addPersonalDictonary(
const QString & word )
00076 {
00077
if ( m_bgSpell.kspell )
00078 {
00079 m_bgSpell.kspell->addPersonal ( word);
00080 }
00081 }
00082
00083
void KoBgSpellCheck::spellCheckParagraphDeleted( KoTextParag *_parag,
KoTextObject *obj)
00084 {
00085
if ( m_bgSpell.currentTextObj == obj && m_bgSpell.currentParag == _parag)
00086 {
00087 stopSpellChecking();
00088 startBackgroundSpellCheck();
00089 }
00090 }
00091
00092
00093
void KoBgSpellCheck::enableBackgroundSpellCheck(
bool b )
00094 {
00095 m_bSpellCheckEnabled=b;
00096 startBackgroundSpellCheck();
00097 }
00098
00099
void KoBgSpellCheck::setIgnoreUpperWords(
bool b)
00100 {
00101 stopSpellChecking();
00102 m_bDontCheckUpperWord = b;
00103 startBackgroundSpellCheck();
00104 }
00105
00106
void KoBgSpellCheck::setIgnoreTitleCase(
bool b)
00107 {
00108 stopSpellChecking();
00109 m_bDontCheckTitleCase = b;
00110 startBackgroundSpellCheck();
00111 }
00112
00113
void KoBgSpellCheck::addIgnoreWordAll(
const QString & word)
00114 {
00115
if( m_spellListIgnoreAll.findIndex( word )==-1)
00116 m_spellListIgnoreAll.append( word );
00117 stopSpellChecking();
00118 spellConfig()->setIgnoreList( m_spellListIgnoreAll );
00119 startBackgroundSpellCheck();
00120 }
00121
00122
void KoBgSpellCheck::addIgnoreWordAllList(
const QStringList & list)
00123 {
00124 m_spellListIgnoreAll.clear();
00125 stopSpellChecking();
00126 spellConfig()->setIgnoreList( list );
00127 startBackgroundSpellCheck();
00128 }
00129
00130
void KoBgSpellCheck::clearIgnoreWordAll( )
00131 {
00132 m_spellListIgnoreAll.clear();
00133 stopSpellChecking();
00134 spellConfig()->setIgnoreList( m_spellListIgnoreAll );
00135 startBackgroundSpellCheck();
00136 }
00137
00138
void KoBgSpellCheck::startBackgroundSpellCheck()
00139 {
00140 d->startTimer->stop();
00141
if ( !m_bSpellCheckEnabled )
00142
return;
00143
00144
if ( !m_bgSpell.currentTextObj )
00145 {
00146 m_bgSpell.currentTextObj = nextTextObject(m_bgSpell.currentTextObj );
00147 }
00148
if ( !m_bgSpell.currentTextObj )
00149 {
00150
#ifdef DEBUG_BGSPELLCHECKING
00151
00152
#endif
00153
d->startTimer->start( 1000,
true );
00154
return;
00155 }
00156
#ifdef DEBUG_BGSPELLCHECKING
00157
kdDebug(32500) <<
"KoBgSpellCheck::startBackgroundSpellCheck" << endl;
00158
#endif
00159
00160 m_bgSpell.currentParag = m_bgSpell.currentTextObj->textDocument()->firstParag();
00161 nextParagraphNeedingCheck();
00162
00163
#ifdef DEBUG_BGSPELLCHECKING
00164
kdDebug(32500) <<
"fs=" << m_bgSpell.currentTextObj <<
" parag=" << m_bgSpell.currentParag << endl;
00165
#endif
00166
00167
if ( !m_bgSpell.currentTextObj || !m_bgSpell.currentParag ) {
00168
if ( m_bgSpell.currentTextObj )
00169 {
00170
if ( (m_bgSpell.currentTextObj->textDocument()->firstParag() == m_bgSpell.currentTextObj->textDocument()->lastParag()) && m_bgSpell.currentTextObj->textDocument()->firstParag()->length() <= 1)
00171 m_bgSpell.currentTextObj->setNeedSpellCheck(
false);
00172 }
00173
00174
#ifdef DEBUG_BGSPELLCHECKING
00175
kdDebug(32500) <<
"KoBgSpellCheck::startBackgroundSpellCheck nothing to check this time." << endl;
00176
#endif
00177
d->startTimer->start( 1000,
true );
00178
return;
00179 }
00180
00181
bool needsWait =
false;
00182
if ( !m_bgSpell.kspell )
00183 {
00184 m_bgSpell.kspell =
new KoSpell(0L,
this, SLOT( spellCheckerReady() ), d->m_pKSpellConfig );
00185
00186 needsWait =
true;
00187 connect( m_bgSpell.kspell, SIGNAL( death() ),
00188
this, SLOT( spellCheckerFinished() ) );
00189 connect( m_bgSpell.kspell, SIGNAL( misspelling(
const QString &,
int ) ),
00190
this, SLOT( spellCheckerMisspelling(
const QString &,
int ) ) );
00191 connect( m_bgSpell.kspell, SIGNAL( done() ),
00192
this, SLOT( spellCheckerDone() ) );
00193 }
00194 m_bgSpell.kspell->setIgnoreUpperWords( m_bDontCheckUpperWord );
00195 m_bgSpell.kspell->setIgnoreTitleCase( m_bDontCheckTitleCase );
00196
if ( !needsWait )
00197 spellCheckerReady();
00198 }
00199
00200
void KoBgSpellCheck::spellCheckerReady()
00201 {
00202
00203
00204
if (m_bgSpell.currentTextObj)
00205 m_bgSpell.currentParag = m_bgSpell.currentTextObj->textDocument()->firstParag();
00206
00207
#ifdef DEBUG_BGSPELLCHECKING
00208
kdDebug(32500) <<
"KoBgSpellCheck::spellCheckerReady textobj=" << m_bgSpell.currentTextObj << endl;
00209
#endif
00210
d->nextParagraphTimer->start( 10,
true );
00211 }
00212
00213
00214
00215
void KoBgSpellCheck::nextParagraphNeedingCheck()
00216 {
00217
#ifdef DEBUG_BGSPELLCHECKING
00218
kdDebug(32500) <<
"KoBgSpellCheck::nextParagraphNeedingCheck textobj=" <<m_bgSpell.currentTextObj <<endl;
00219
#endif
00220
if ( !m_bgSpell.currentTextObj ) {
00221 m_bgSpell.currentParag = 0L;
00222
return;
00223 }
00224
00225
00226
00227
00228
if(m_bgSpell.needsRepaint)
00229 {
00230 slotRepaintChanged( m_bgSpell.currentTextObj );
00231 m_bgSpell.needsRepaint=
false;
00232 }
00233
00234 KoTextParag* parag = m_bgSpell.currentParag;
00235
if ( parag && parag->string() && parag->string()->needsSpellCheck() )
00236 {
00237
#ifdef DEBUG_BGSPELLCHECKING
00238
kdDebug(32500) <<
"current parag " << parag <<
" needs checking again." <<endl;
00239
#endif
00240
return;
00241 }
00242
00243
if ( parag && parag->next() )
00244 parag = parag->next();
00245
00246
while ( parag && !parag->string()->needsSpellCheck() )
00247 parag = parag->next();
00248
while ( parag && parag->length() <= 1 )
00249 {
00250 parag->string()->setNeedsSpellCheck(
false );
00251
while ( parag && !parag->string()->needsSpellCheck() )
00252 parag = parag->next();
00253 }
00254
00255
if ( !parag ) {
00256 parag = m_bgSpell.currentTextObj->textDocument()->firstParag();
00257
while ( parag != m_bgSpell.currentParag && !parag->string()->needsSpellCheck() )
00258 parag = parag->next();
00259
while ( parag != m_bgSpell.currentParag && parag->length() <= 1 )
00260 {
00261 parag->string()->setNeedsSpellCheck(
false );
00262
while ( parag != m_bgSpell.currentParag && !parag->string()->needsSpellCheck() )
00263 parag = parag->next();
00264 }
00265
if ( parag == m_bgSpell.currentParag && !parag->string()->needsSpellCheck() )
00266 parag = 0;
00267 }
00268
00269
if ( parag )
00270 m_bgSpell.currentParag = parag;
00271
else
00272 {
00273
KoTextObject *obj = m_bgSpell.currentTextObj;
00274
00275 obj->
setNeedSpellCheck(
false);
00276
00277 m_bgSpell.currentTextObj = nextTextObject( m_bgSpell.currentTextObj );
00278
00279
if ( m_bgSpell.currentTextObj && m_bgSpell.currentTextObj != obj)
00280 {
00281 m_bgSpell.currentParag = m_bgSpell.currentTextObj->textDocument()->firstParag();
00282 }
00283
else
00284 {
00285
if ( m_bgSpell.currentTextObj )
00286 m_bgSpell.currentTextObj->setNeedSpellCheck(
false );
00287 m_bgSpell.currentParag = 0L;
00288 }
00289 }
00290
00291
00292 }
00293
00294
void KoBgSpellCheck::spellCheckNextParagraph()
00295 {
00296
#ifdef DEBUG_BGSPELLCHECKING
00297
kdDebug(32500) <<
"KoBgSpellCheck::spellCheckNextParagraph" << endl;
00298
#endif
00299
00300 nextParagraphNeedingCheck();
00301
#ifdef DEBUG_BGSPELLCHECKING
00302
kdDebug(32500) <<
"textobj=" << m_bgSpell.currentTextObj <<
" parag=" << m_bgSpell.currentParag << endl;
00303
#endif
00304
if ( !m_bgSpell.currentTextObj || !m_bgSpell.currentParag )
00305 {
00306
#ifdef DEBUG_BGSPELLCHECKING
00307
kdDebug(32500) <<
"KoBgSpellCheck::spellCheckNextParagraph scheduling restart" << endl;
00308
#endif
00309
00310
00311 d->startTimer->start( 100,
true );
00312
return;
00313 }
00314
00315
00316 KoTextStringChar *ch = m_bgSpell.currentParag->at( 0 );
00317
KoTextFormat format( *ch->format() );
00318 format.
setMisspelled(
false );
00319 m_bgSpell.currentParag->setFormat( 0, m_bgSpell.currentParag->length()-1, &format,
true, KoTextFormat::Misspelled );
00320
#ifdef DEBUG_BGSPELLCHECKING
00321
kdDebug(32500) <<
"KoBgSpellCheck::spellCheckNextParagraph spell checking parag " << m_bgSpell.currentParag->paragId() << endl;
00322
#endif
00323
00324
00325
QString text = m_bgSpell.currentParag->string()->toString();
00326 text.remove( text.length() - 1, 1 );
00327
00328
00329
00330
00331
00332 m_bgSpell.currentParag->string()->setNeedsSpellCheck(
false );
00333
00334
00335 m_bgSpell.kspell->check(text);
00336 }
00337
00338
void KoBgSpellCheck::spellCheckerMisspelling(
const QString &old,
int pos )
00339 {
00340
KoTextObject * textobj = m_bgSpell.currentTextObj;
00341
#ifdef DEBUG_BGSPELLCHECKING
00342
kdDebug(32500) <<
"KoBgSpellCheck::spellCheckerMisspelling textobj=" << textobj <<
" old=" << old <<
" pos=" << pos << endl;
00343
#endif
00344
Q_ASSERT( textobj );
00345
if ( !textobj )
return;
00346 KoTextParag* parag = m_bgSpell.currentParag;
00347
if ( !parag )
return;
00348
#ifdef DEBUG_BGSPELLCHECKING
00349
kdDebug(32500) <<
"KoBgSpellCheck::spellCheckerMisspelling parag=" << parag <<
" (id=" << parag->paragId() <<
", length=" << parag->length() <<
") pos=" << pos <<
" length=" << old.length() << endl;
00350
#endif
00351
KoTextStringChar *ch = parag->at( pos );
00352
KoTextFormat format( *ch->format() );
00353 format.
setMisspelled(
true );
00354 parag->setFormat( pos, old.length(), &format,
true, KoTextFormat::Misspelled );
00355 }
00356
00357
void KoBgSpellCheck::spellCheckerDone()
00358 {
00359
00360
00361 m_bgSpell.currentParag->setChanged(
true );
00362 m_bgSpell.needsRepaint=
true;
00363
00364
#ifdef DEBUG_BGSPELLCHECKING
00365
kdDebug(32500) <<
"KoBgSpellCheck::spellCheckerDone" << endl;
00366
#endif
00367
00368 d->nextParagraphTimer->start( 10,
true );
00369 }
00370
00371
void KoBgSpellCheck::spellCheckerFinished()
00372 {
00373
#ifdef DEBUG_BGSPELLCHECKING
00374
kdDebug(32500) <<
"--- KoBgSpellCheck::spellCheckerFinished ---" << endl;
00375
#endif
00376
KoSpell::spellStatus status = m_bgSpell.kspell->status();
00377 m_bgSpell.kspell->cleanUp();
00378
delete m_bgSpell.kspell;
00379 m_bgSpell.kspell = 0;
00380 m_bgSpell.currentParag = 0;
00381 m_bgSpell.currentTextObj = 0;
00382
if (status == KoSpell::Error)
00383 {
00384
00385 kdWarning() <<
"ISpell/ASpell not configured correctly." << endl;
00386
if ( !m_bSpellCheckConfigure )
00387 {
00388 m_bSpellCheckConfigure=
true;
00389 configurateSpellChecker();
00390 }
00391
return;
00392 }
00393
else if (status == KoSpell::Crashed)
00394 {
00395 kdWarning() <<
"ISpell/ASpell seems to have crashed." << endl;
00396
return;
00397 }
00398
00399 }
00400
00401 KSpellConfig* KoBgSpellCheck::spellConfig()
00402 {
00403
if ( !d->m_pKSpellConfig )
00404 d->m_pKSpellConfig =
new KSpellConfig();
00405
return d->m_pKSpellConfig;
00406 }
00407
00408
void KoBgSpellCheck::setKSpellConfig(
const KOSpellConfig &_kspell)
00409 {
00410 (
void)spellConfig();
00411 stopSpellChecking();
00412
00413 d->m_pKSpellConfig->setNoRootAffix(_kspell.
noRootAffix ());
00414 d->m_pKSpellConfig->setRunTogether(_kspell.
runTogether ());
00415 d->m_pKSpellConfig->setDictionary(_kspell.
dictionary ());
00416 d->m_pKSpellConfig->setDictFromList(_kspell.
dictFromList());
00417 d->m_pKSpellConfig->setEncoding(_kspell.
encoding());
00418 d->m_pKSpellConfig->setClient(_kspell.
client());
00419 m_bSpellCheckConfigure =
false;
00420 startBackgroundSpellCheck();
00421 }
00422
00423
void KoBgSpellCheck::stopSpellChecking()
00424 {
00425
#ifdef DEBUG_BGSPELLCHECKING
00426
kdDebug(32500) <<
"KoBgSpellCheck::stopSpellChecking" << endl;
00427
#endif
00428
if ( m_bgSpell.kspell ) {
00429 m_bgSpell.kspell->cleanUp();
00430
delete m_bgSpell.kspell;
00431 m_bgSpell.kspell = 0;
00432 }
00433 m_bgSpell.currentParag = 0;
00434 m_bgSpell.currentTextObj = 0;
00435 d->startTimer->stop();
00436 d->nextParagraphTimer->stop();
00437 }