• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KDE3Support

  • sources
  • kde-4.12
  • kdelibs
  • kde3support
  • kdeui
k3spell.cpp
Go to the documentation of this file.
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) 2003 Zack Rusin <zack@kde.org>
5  Copyright (C) 2007-2008 Kevin Kofler <Kevin@tigcc.ticalc.org>
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Library General Public
9  License version 2 as published by the Free Software Foundation.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #include "k3spell.h"
23 
24 #include <config.h>
25 
26 #include <stdio.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <ctype.h>
31 #include <stdlib.h> // atoi
32 
33 #ifdef HAVE_STRINGS_H
34 #include <strings.h>
35 #endif
36 
37 
38 #include <QtGui/QApplication>
39 #include <QtCore/QTextCodec>
40 #include <QtCore/QTimer>
41 
42 #include <kmessagebox.h>
43 #include <kdebug.h>
44 #include <klocale.h>
45 #include "k3sconfig.h"
46 #include "k3spelldlg.h"
47 #include <kprocess.h>
48 #include <QTextStream>
49 
50 #define MAXLINELENGTH 10000
51 #undef IGNORE //fix possible conflict
52 
53 enum {
54  GOOD= 0,
55  IGNORE= 1,
56  REPLACE= 2,
57  MISTAKE= 3
58 };
59 
60 enum checkMethod { Method1 = 0, Method2 };
61 
62 struct BufferedWord
63 {
64  checkMethod method;
65  QString word;
66  bool useDialog;
67  bool suggest;
68 };
69 
70 class K3Spell::K3SpellPrivate
71 {
72 public:
73  bool endOfResponse;
74  bool m_bIgnoreUpperWords;
75  bool m_bIgnoreTitleCase;
76  bool m_bNoMisspellingsEncountered;
77  SpellerType type;
78  K3Spell* suggestSpell;
79  bool checking;
80  QList<BufferedWord> unchecked;
81  QTimer *checkNextTimer;
82  bool aspellV6;
83  QTextCodec* m_codec;
84  QString convertQByteArray( const QByteArray& b )
85  {
86  QTextCodec* originalCodec = QTextCodec::codecForCStrings();
87  QTextCodec::setCodecForCStrings( m_codec );
88  QString s( b );
89  QTextCodec::setCodecForCStrings( originalCodec );
90  return s;
91  }
92  QByteArray convertQString( const QString& s )
93  {
94  QTextCodec* originalCodec = QTextCodec::codecForCStrings();
95  QTextCodec::setCodecForCStrings( m_codec );
96  QByteArray b = s.toLatin1();
97  QTextCodec::setCodecForCStrings( originalCodec );
98  return b;
99  }
100 };
101 
102 //TODO
103 //Parse stderr output
104 //e.g. -- invalid dictionary name
105 
106 /*
107  Things to put in K3SpellConfigDlg:
108  make root/affix combinations that aren't in the dictionary (-m)
109  don't generate any affix/root combinations (-P)
110  Report run-together words with missing blanks as spelling errors. (-B)
111  default dictionary (-d [dictionary])
112  personal dictionary (-p [dictionary])
113  path to ispell -- NO: ispell should be in $PATH
114  */
115 
116 
117 // Connects a slot to KProcess's output signal
118 #define OUTPUT(x) (connect (proc, SIGNAL (readyReadStandardOutput()), this, SLOT (x())))
119 
120 // Disconnect a slot from...
121 #define NOOUTPUT(x) (disconnect (proc, SIGNAL (readyReadStandardOutput()), this, SLOT (x())))
122 
123 
124 
125 K3Spell::K3Spell( QWidget *_parent, const QString &_caption,
126  QObject *obj, const char *slot, K3SpellConfig *_ksc,
127  bool _progressbar, bool _modal )
128 {
129  initialize( _parent, _caption, obj, slot, _ksc,
130  _progressbar, _modal, Text );
131 }
132 
133 K3Spell::K3Spell( QWidget *_parent, const QString &_caption,
134  QObject *obj, const char *slot, K3SpellConfig *_ksc,
135  bool _progressbar, bool _modal, SpellerType type )
136 {
137  initialize( _parent, _caption, obj, slot, _ksc,
138  _progressbar, _modal, type );
139 }
140 
141 K3Spell::spellStatus K3Spell::status() const
142 {
143  return m_status;
144 }
145 
146 void K3Spell::hide() { ksdlg->hide(); }
147 
148 QStringList K3Spell::suggestions() const
149 {
150  return sugg;
151 }
152 
153 int K3Spell::dlgResult () const
154 {
155  return dlgresult;
156 }
157 
158 int K3Spell::heightDlg() const { return ksdlg->height(); }
159 int K3Spell::widthDlg() const { return ksdlg->width(); }
160 
161 QString K3Spell::intermediateBuffer() const
162 {
163  return K3Spell::newbuffer;
164 }
165 
166 // Check if aspell is at least version 0.6
167 static bool determineASpellV6()
168 {
169  QString result;
170  FILE *fs = popen("aspell -v", "r");
171  if (fs)
172  {
173  // Close textstream before we close fs
174  {
175  QTextStream ts(fs, QIODevice::ReadOnly);
176  result = ts.readAll().trimmed();
177  }
178  pclose(fs);
179  }
180 
181  QRegExp rx("Aspell (\\d.\\d)");
182  if (rx.indexIn(result) != -1)
183  {
184  float version = rx.cap(1).toFloat();
185  return (version >= 0.6);
186  }
187  return false;
188 }
189 
190 
191 void
192 K3Spell::startIspell()
193  //trystart = {0,1,2}
194 {
195  if ((trystart == 0) && (ksconfig->client() == KS_CLIENT_ASPELL))
196  d->aspellV6 = determineASpellV6();
197 
198  kDebug(750) << "Try #" << trystart;
199 
200  if ( trystart > 0 ) {
201  proc->reset();
202  }
203 
204  switch ( ksconfig->client() )
205  {
206  case KS_CLIENT_ISPELL:
207  *proc << "ispell";
208  kDebug(750) << "Using ispell";
209  break;
210  case KS_CLIENT_ASPELL:
211  *proc << "aspell";
212  kDebug(750) << "Using aspell";
213  break;
214  case KS_CLIENT_HSPELL:
215  *proc << "hspell";
216  kDebug(750) << "Using hspell";
217  break;
218  case KS_CLIENT_ZEMBEREK:
219  *proc << "zpspell";
220  kDebug(750) << "Using zemberek(zpspell)";
221  break;
222  case KS_CLIENT_HUNSPELL:
223  *proc << "hunspell";
224  kDebug(750) << "Using hunspell";
225  break;
226  }
227 
228  // Hunspell doesn't need all of these options, but it'll ignore those it doesn't understand.
229  if ( ksconfig->client() == KS_CLIENT_ISPELL || ksconfig->client() == KS_CLIENT_ASPELL || ksconfig->client() == KS_CLIENT_HUNSPELL )
230  {
231  *proc << "-a" << "-S";
232 
233  switch ( d->type )
234  {
235  case HTML:
236  //Debian uses an ispell version that has the -h option instead.
237  //Not sure what they did, but the preferred spell checker
238  //on that platform is aspell anyway, so use -H untill I'll come
239  //up with something better.
240  *proc << "-H";
241  break;
242  case TeX:
243  //same for aspell and ispell
244  *proc << "-t";
245  break;
246  case Nroff:
247  //only ispell and hunspell support
248  if ( ksconfig->client() == KS_CLIENT_ISPELL || ksconfig->client() == KS_CLIENT_HUNSPELL )
249  *proc << "-n";
250  break;
251  case Text:
252  default:
253  //nothing
254  break;
255  }
256  if (ksconfig->noRootAffix())
257  {
258  *proc<<"-m";
259  }
260  if (ksconfig->runTogether())
261  {
262  *proc << "-B";
263  }
264  else
265  {
266  *proc << "-C";
267  }
268 
269 
270  if (trystart<2)
271  {
272  if (! ksconfig->dictionary().isEmpty())
273  {
274  kDebug(750) << "using dictionary [" << ksconfig->dictionary() << "]";
275  *proc << "-d";
276  *proc << ksconfig->dictionary();
277  }
278  }
279 
280  //Note to potential debuggers: -Tlatin2 _is_ being added on the
281  // _first_ try. But, some versions of ispell will fail with this
282  // option, so k3spell tries again without it. That's why as 'ps -ax'
283  // shows "ispell -a -S ..." withou the "-Tlatin2" option.
284 
285  if ( ksconfig->client() == KS_CLIENT_HUNSPELL && trystart<1 ) {
286  // Note: This sets I/O encoding. Hunspell correctly handles dictionary encoding != I/O encoding.
287  // It will be faster if the I/O encoding matches the dictionary encoding, but using UTF-8 is always safe.
288  switch ( ksconfig->encoding() )
289  {
290  case KS_E_LATIN1:
291  *proc << "-i" << "ISO-8859-1";
292  break;
293  case KS_E_LATIN2:
294  *proc << "-i" << "ISO-8859-2";
295  break;
296  case KS_E_LATIN3:
297  *proc << "-i" << "ISO-8859-3";
298  break;
299  case KS_E_LATIN4:
300  *proc << "-i" << "ISO-8859-4";
301  break;
302  case KS_E_LATIN5:
303  *proc << "-i" << "ISO-8859-5";
304  break;
305  case KS_E_LATIN7:
306  *proc << "-i" << "ISO-8859-7";
307  break;
308  case KS_E_LATIN8:
309  *proc << "-i" << "ISO-8859-8";
310  break;
311  case KS_E_LATIN9:
312  *proc << "-i" << "ISO-8859-9";
313  break;
314  case KS_E_LATIN13:
315  *proc << "-i" << "ISO-8859-13";
316  break;
317  case KS_E_LATIN15:
318  *proc << "-i" << "ISO-8859-15";
319  break;
320  case KS_E_UTF8:
321  *proc << "-i" << "UTF-8";
322  break;
323  case KS_E_KOI8R:
324  *proc << "-i" << "KOI8-R";
325  break;
326  case KS_E_KOI8U:
327  *proc << "-i" << "KOI8-U";
328  break;
329  case KS_E_CP1251:
330  *proc << "-i" << "CP1251";
331  break;
332  case KS_E_CP1255:
333  *proc << "-i" << "CP1255";
334  break;
335  default:
336  break;
337  }
338  } else if ( trystart<1 ) {
339  switch ( ksconfig->encoding() )
340  {
341  case KS_E_LATIN1:
342  *proc << "-Tlatin1";
343  break;
344  case KS_E_LATIN2:
345  *proc << "-Tlatin2";
346  break;
347  case KS_E_LATIN3:
348  *proc << "-Tlatin3";
349  break;
350 
351  // add the other charsets here
352  case KS_E_LATIN4:
353  case KS_E_LATIN5:
354  case KS_E_LATIN7:
355  case KS_E_LATIN8:
356  case KS_E_LATIN9:
357  case KS_E_LATIN13:
358  // will work, if this is the default charset in the dictionary
359  kError(750) << "charsets ISO-8859-4, -5, -7, -8, -9 and -13 not supported yet" << endl;
360  break;
361  case KS_E_LATIN15: // ISO-8859-15 (Latin 9)
362  if (ksconfig->client() == KS_CLIENT_ISPELL)
363  {
364  /*
365  * As far as I know, there are no ispell dictionary using ISO-8859-15
366  * but users have the tendency to select this encoding instead of ISO-8859-1
367  * So put ispell in ISO-8859-1 (Latin 1) mode.
368  */
369  *proc << "-Tlatin1";
370  }
371  else
372  kError(750) << "ISO-8859-15 not supported for aspell yet." << endl;
373  break;
374  case KS_E_UTF8:
375  *proc << "-Tutf8";
376  if (ksconfig->client() == KS_CLIENT_ASPELL)
377  *proc << "--encoding=utf-8";
378  break;
379  case KS_E_KOI8U:
380  *proc << "-w'"; // add ' as a word char
381  break;
382  default:
383  break;
384  }
385  }
386 
387  // -a : pipe mode
388  // -S : sort suggestions by probable correctness
389  }
390  else // hspell and Zemberek(zpspell) doesn't need all the rest of the options
391  *proc << "-a";
392 
393  if (trystart == 0) //don't connect these multiple times
394  {
395  connect( proc, SIGNAL(readyReadStandardError()),
396  this, SLOT(ispellErrors()) );
397 
398  connect( proc, SIGNAL(finished(int,QProcess::ExitStatus)),
399  this, SLOT(ispellExit()) );
400 
401  proc->setOutputChannelMode( KProcess::SeparateChannels );
402  proc->setNextOpenMode( QIODevice::ReadWrite | QIODevice::Text );
403 
404  OUTPUT(K3Spell2);
405  }
406 
407  proc->start();
408  if ( !proc->waitForStarted() )
409  {
410  m_status = Error;
411  QTimer::singleShot( 0, this, SLOT(emitDeath()));
412  }
413 }
414 
415 void
416 K3Spell::ispellErrors( )
417 {
418  // buffer[buflen-1] = '\0';
419  // kDebug(750) << "ispellErrors [" << buffer << "]\n";
420 }
421 
422 void K3Spell::K3Spell2( )
423 
424 {
425  QString line;
426 
427  kDebug(750) << "K3Spell::K3Spell2";
428 
429  trystart = maxtrystart; //We've officially started ispell and don't want
430  //to try again if it dies.
431 
432  QByteArray data;
433  qint64 read = proc->readLine(data.data(),data.count());
434  if ( read == -1 )
435  {
436  QTimer::singleShot( 0, this, SLOT(emitDeath()) );
437  return;
438  }
439  line = d->convertQByteArray( data );
440 
441  if ( !line.startsWith('@') ) //@ indicates that ispell is working fine
442  {
443  QTimer::singleShot( 0, this, SLOT(emitDeath()) );
444  return;
445  }
446 
447  //We want to recognize KDE in any text!
448  if ( !ignore("kde") )
449  {
450  kDebug(750) << "@KDE was false";
451  QTimer::singleShot( 0, this, SLOT(emitDeath()) );
452  return;
453  }
454 
455  //We want to recognize linux in any text!
456  if ( !ignore("linux") )
457  {
458  kDebug(750) << "@Linux was false";
459  QTimer::singleShot( 0, this, SLOT(emitDeath()) );
460  return;
461  }
462 
463  NOOUTPUT( K3Spell2 );
464 
465  m_status = Running;
466  emit ready( this );
467 }
468 
469 void
470 K3Spell::setUpDialog( bool reallyuseprogressbar )
471 {
472  if ( dialogsetup )
473  return;
474 
475  //Set up the dialog box
476  ksdlg = new K3SpellDlg( parent, progressbar && reallyuseprogressbar, modaldlg );
477  ksdlg->setCaption( caption );
478 
479  connect( ksdlg, SIGNAL(command(int)),
480  this, SLOT(slotStopCancel(int)) );
481  connect( this, SIGNAL(progress(uint)),
482  ksdlg, SLOT(slotProgress(uint)) );
483 
484  if ( modaldlg )
485  ksdlg->setFocus();
486  dialogsetup = true;
487 }
488 
489 bool K3Spell::addPersonal( const QString & word )
490 {
491  QString qs = word.simplified();
492 
493  //we'll let ispell do the work here b/c we can
494  if ( qs.indexOf(' ') != -1 || qs.isEmpty() ) // make sure it's a _word_
495  return false;
496 
497  qs.prepend( "*" );
498  personaldict = true;
499 
500  return proc->write( d->convertQString( qs ) );
501 }
502 
503 bool K3Spell::writePersonalDictionary()
504 {
505  return proc->write( QByteArray( "#" ) );
506 }
507 
508 bool K3Spell::ignore( const QString & word )
509 {
510  QString qs = word.simplified();
511 
512  //we'll let ispell do the work here b/c we can
513  if ( qs.indexOf (' ') != -1 || qs.isEmpty() ) // make sure it's a _word_
514  return false;
515 
516  qs.prepend( "@" );
517 
518  return proc->write( d->convertQString( qs ) );
519 }
520 
521 bool
522 K3Spell::cleanFputsWord( const QString & s )
523 {
524  QString qs(s);
525  bool empty = true;
526 
527  for( int i = 0; i < qs.length(); i++ )
528  {
529  //we need some punctuation for ornaments
530  if ( (qs[i] != '\'' && qs[i] != '\"' && qs[i] != '-'
531  && qs[i].isPunct()) || qs[i].isSpace() )
532  {
533  qs.remove(i,1);
534  i--;
535  } else {
536  if ( qs[i].isLetter() )
537  empty=false;
538  }
539  }
540 
541  // don't check empty words, otherwise synchronization will lost
542  if (empty)
543  return false;
544 
545  return proc->write( d->convertQString( QString('^'+qs+'\n') ) );
546 }
547 
548 bool
549 K3Spell::cleanFputs( const QString & s )
550 {
551  QString qs(s);
552  unsigned l = qs.length();
553 
554  // some uses of '$' (e.g. "$0") cause ispell to skip all following text
555  for( unsigned int i = 0; i < l; ++i )
556  {
557  if( qs[i] == '$' )
558  qs[i] = ' ';
559  }
560 
561  if ( l<MAXLINELENGTH )
562  {
563  if ( qs.isEmpty() )
564  qs="";
565  return proc->write( d->convertQString('^'+qs+'\n') );
566  }
567  else
568  return proc->write( d->convertQString( "^\n" ) );
569 }
570 
571 bool K3Spell::checkWord( const QString & buffer, bool _usedialog )
572 {
573  if (d->checking) { // don't check multiple words simultaneously
574  BufferedWord bufferedWord;
575  bufferedWord.method = Method1;
576  bufferedWord.word = buffer;
577  bufferedWord.useDialog = _usedialog;
578  d->unchecked.append( bufferedWord );
579  return true;
580  }
581  d->checking = true;
582  QString qs = buffer.simplified();
583 
584  if ( qs.indexOf (' ') != -1 || qs.isEmpty() ) { // make sure it's a _word_
585  d->checkNextTimer->setInterval(0);
586  d->checkNextTimer->setSingleShot(true);
587  d->checkNextTimer->start();
588  return false;
589  }
591  dialog3slot = SLOT(checkWord3());
592 
593  usedialog = _usedialog;
594  setUpDialog( false );
595  if ( _usedialog )
596  {
597  emitProgress();
598  }
599  else
600  ksdlg->hide();
601 
602  QByteArray data;
603  while (proc->readLine( data.data(), data.count() ) != -1 )
604  ; // eat spurious blanks
605 
606  OUTPUT(checkWord2);
607  // connect (this, SIGNAL (dialog3()), this, SLOT (checkWord3()));
608 
609  proc->write( d->convertQString( QString( "%" ) ) ); // turn off terse mode
610  proc->write( d->convertQString( buffer ) ); // send the word to ispell
611 
612  return true;
613 }
614 
615 bool K3Spell::checkWord( const QString & buffer, bool _usedialog, bool suggest )
616 {
617  if (d->checking) { // don't check multiple words simultaneously
618  BufferedWord bufferedWord;
619  bufferedWord.method = Method2;
620  bufferedWord.word = buffer;
621  bufferedWord.useDialog = _usedialog;
622  bufferedWord.suggest = suggest;
623  d->unchecked.append( bufferedWord );
624  return true;
625  }
626  d->checking = true;
627  QString qs = buffer.simplified();
628 
629  if ( qs.indexOf (' ') != -1 || qs.isEmpty() ) { // make sure it's a _word_
630  d->checkNextTimer->setInterval(0);
631  d->checkNextTimer->setSingleShot(true);
632  d->checkNextTimer->start();
633  return false;
634  }
635 
637  if ( !suggest ) {
638  dialog3slot = SLOT(checkWord3());
639  usedialog = _usedialog;
640  setUpDialog( false );
641  if ( _usedialog )
642  {
643  emitProgress();
644  }
645  else
646  ksdlg->hide();
647  }
648 
649  QByteArray data;
650  while (proc->readLine( data.data(), data.count() ) != -1 ) ; // eat spurious blanks
651 
652  OUTPUT(checkWord2);
653  // connect (this, SIGNAL (dialog3()), this, SLOT (checkWord3()));
654 
655  proc->write( d->convertQString( QString( "%" ) ) ); // turn off terse mode
656  proc->write( d->convertQString( buffer ) ); // send the word to ispell
657 
658  return true;
659 }
660 
661 void K3Spell::checkWord2( )
662 {
663  QString word;
664  QString line;
665  line = d->convertQByteArray( proc->readLine() ); //get ispell's response
666 
667 /* ispell man page: "Each sentence of text input is terminated with an
668  additional blank line, indicating that ispell has completed processing
669  the input line."
670  <sanders>
671  But there can be multiple lines returned in the case of an error,
672  in this case we should consume all the output given otherwise spell checking
673  can get out of sync.
674  </sanders>
675 */
676  QByteArray data;
677  while (proc->readLine( data.data(), data.count() ) != -1 ) ; // eat spurious blanks
678  NOOUTPUT(checkWord2);
679 
680  bool mistake = ( parseOneResponse(line, word, sugg) == MISTAKE );
681  if ( mistake && usedialog )
682  {
683  cwword = word;
684  dialog( word, sugg, SLOT(checkWord3()) );
685  d->checkNextTimer->setInterval(0);
686  d->checkNextTimer->setSingleShot(true);
687  d->checkNextTimer->start();
688  return;
689  }
690  else if( mistake )
691  {
692  emit misspelling( word, sugg, lastpos );
693  }
694 
695  //emits a "corrected" signal _even_ if no change was made
696  //so that the calling program knows when the check is complete
697  emit corrected( word, word, 0L );
698  d->checkNextTimer->setInterval(0);
699  d->checkNextTimer->setSingleShot(true);
700  d->checkNextTimer->start();
701 }
702 
703 void K3Spell::checkNext()
704 {
705 // Queue words to prevent kspell from turning into a fork bomb
706  d->checking = false;
707  if (!d->unchecked.empty()) {
708  BufferedWord buf = d->unchecked.front();
709  d->unchecked.pop_front();
710 
711  if (buf.method == Method1)
712  checkWord( buf.word, buf.useDialog );
713  else
714  checkWord( buf.word, buf.useDialog, buf.suggest );
715  }
716 }
717 
718 void K3Spell::suggestWord()
719 {
720  QString word;
721  QString line;
722  line = d->convertQByteArray( proc->readLine() ); //get ispell's response
723 
724 /* ispell man page: "Each sentence of text input is terminated with an
725  additional blank line, indicating that ispell has completed processing
726  the input line." */
727  QByteArray data;
728  while (proc->readLine( data.data(), data.count() ) != -1 ) ; // eat spurious blanks
729 
730  NOOUTPUT(checkWord2);
731 
732  bool mistake = ( parseOneResponse(line, word, sugg) == MISTAKE );
733  if ( mistake && usedialog )
734  {
735  cwword=word;
736  dialog( word, sugg, SLOT(checkWord3()) );
737  return;
738  }
739 }
740 
741 void K3Spell::checkWord3()
742 {
743  disconnect( this, SIGNAL(dialog3()), this, SLOT(checkWord3()) );
744 
745  emit corrected( cwword, replacement(), 0L );
746 }
747 
748 QString K3Spell::funnyWord( const QString & word )
749  // composes a guess from ispell to a readable word
750  // e.g. "re+fry-y+ies" -> "refries"
751 {
752  QString qs;
753  for( int i=0; i<word.size(); i++ )
754  {
755  if (word [i]=='+')
756  continue;
757  if (word [i]=='-')
758  {
759  QString shorty;
760  int j, k;
761 
762  for( j = i+1; j < word.size() && word[j] != '+' && word[j] != '-'; j++ )
763  shorty += word[j];
764 
765  i = j-1;
766 
767  if ( !( k = qs.lastIndexOf(shorty) ) || k != -1 )
768  qs.remove( k, shorty.length() );
769  else
770  {
771  qs += '-';
772  qs += shorty; //it was a hyphen, not a '-' from ispell
773  }
774  }
775  else
776  qs += word[i];
777  }
778 
779  return qs;
780 }
781 
782 
783 int K3Spell::parseOneResponse( const QString &buffer, QString &word, QStringList & sugg )
784  // buffer is checked, word and sugg are filled in
785  // returns
786  // GOOD if word is fine
787  // IGNORE if word is in ignorelist
788  // REPLACE if word is in replacelist
789  // MISTAKE if word is misspelled
790 {
791  word = "";
792  posinline=0;
793 
794  sugg.clear();
795 
796  if ( buffer[0] == '*' || buffer[0] == '+' || buffer[0] == '-' )
797  {
798  return GOOD;
799  }
800 
801  if ( buffer[0] == '&' || buffer[0] == '?' || buffer[0] == '#' )
802  {
803  int i,j;
804 
805 
806  word = buffer.mid( 2, buffer.indexOf( ' ', 3 ) -2 );
807  //check() needs this
808  orig=word;
809 
810  if( d->m_bIgnoreTitleCase && word == word.toUpper() )
811  return IGNORE;
812 
813  if( d->m_bIgnoreUpperWords && word[0] == word[0].toUpper() )
814  {
815  QString text = word[0] + word.right( word.length()-1 ).toLower();
816  if( text == word )
817  return IGNORE;
818  }
819 
821  //We don't take advantage of ispell's ignore function because
822  //we can't interrupt ispell's output (when checking a large
823  //buffer) to add a word to _it's_ ignore-list.
824  if ( ignorelist.indexOf( word.toLower() ) != -1 )
825  return IGNORE;
826 
828  QString qs2;
829 
830  if ( buffer.indexOf( ':' ) != -1 )
831  qs2 = buffer.left( buffer.indexOf(':') );
832  else
833  qs2 = buffer;
834 
835  posinline = qs2.right( qs2.length()-qs2.lastIndexOf(' ') ).toInt()-1;
836 
838  QStringList::Iterator it = replacelist.begin();
839  for( ;it != replacelist.end(); ++it, ++it ) // Skip two entries at a time.
840  {
841  if ( word == *it ) // Word matches
842  {
843  ++it;
844  word = *it; // Replace it with the next entry
845  return REPLACE;
846  }
847  }
848 
850  if ( buffer[0] != '#' )
851  {
852  QString qs = buffer.mid( buffer.indexOf(':')+2, buffer.length() );
853  qs += ',';
854  sugg.clear();
855  i = j = 0;
856 
857  while( i < qs.length() )
858  {
859  QString temp = qs.mid( i, (j=qs.indexOf(',',i)) - i );
860  sugg.append( funnyWord(temp) );
861 
862  i=j+2;
863  }
864  }
865 
866  if ( (sugg.count()==1) && (sugg.first() == word) )
867  return GOOD;
868 
869  return MISTAKE;
870  }
871 
872  if ( buffer.isEmpty() ) {
873  kDebug(750) << "Got an empty response: ignoring";
874  return GOOD;
875  }
876 
877  kError(750) << "HERE?: [" << buffer << "]" << endl;
878  kError(750) << "Please report this to zack@kde.org" << endl;
879  kError(750) << "Thank you!" << endl;
880 
881  emit done( false );
882  emit done( K3Spell::origbuffer );
883  return MISTAKE;
884 }
885 
886 bool K3Spell::checkList (QStringList *_wordlist, bool _usedialog)
887  // prepare check of string list
888 {
889  wordlist=_wordlist;
890  if ((totalpos=wordlist->count())==0)
891  return false;
892  wlIt = wordlist->begin();
893  usedialog=_usedialog;
894 
895  // prepare the dialog
896  setUpDialog();
897 
898  //set the dialog signal handler
899  dialog3slot = SLOT (checkList4());
900 
901  proc->write(QByteArray( '%' ) ); // turn off terse mode & check one word at a time
902 
903  //lastpos now counts which *word number* we are at in checkListReplaceCurrent()
904  lastpos = -1;
905  checkList2();
906 
907  // when checked, KProcess calls checkList3a
908  OUTPUT(checkList3a);
909 
910  return true;
911 }
912 
913 void K3Spell::checkList2 ()
914  // send one word from the list to KProcess
915  // invoked first time by checkList, later by checkListReplaceCurrent and checkList4
916 {
917  // send next word
918  if (wlIt != wordlist->end())
919  {
920  kDebug(750) << "KS::cklist2 " << lastpos << ": " << *wlIt;
921 
922  d->endOfResponse = false;
923  bool put;
924  lastpos++; offset=0;
925  put = cleanFputsWord (*wlIt);
926  ++wlIt;
927 
928  // when cleanFPutsWord failed (e.g. on empty word)
929  // try next word; may be this is not good for other
930  // problems, because this will make read the list up to the end
931  if (!put) {
932  checkList2();
933  }
934  }
935  else
936  // end of word list
937  {
938  NOOUTPUT(checkList3a);
939  ksdlg->hide();
940  emit done(true);
941  }
942 }
943 
944 void K3Spell::checkList3a ()
945  // invoked by KProcess, when data from ispell are read
946 {
947  //kDebug(750) << "start of checkList3a";
948 
949  // don't read more data, when dialog is waiting
950  // for user interaction
951  if ( dlgon ) {
952  //kDebug(750) << "dlgon: don't read more data";
953  return;
954  }
955 
956  int e;
957  qint64 tempe;
958 
959  QString word;
960  QString line;
961 
962  do
963  {
964  QByteArray data;
965  tempe = proc->readLine( data.data(), data.count() ); //get ispell's response
966 
967  //kDebug(750) << "checkList3a: read bytes [" << tempe << "]";
968  line = d->convertQByteArray( data );
969 
970  if ( tempe == 0 ) {
971  d->endOfResponse = true;
972  //kDebug(750) << "checkList3a: end of resp";
973  } else if ( tempe>0 ) {
974  if ( (e=parseOneResponse( line, word, sugg ) ) == MISTAKE ||
975  e==REPLACE )
976  {
977  dlgresult=-1;
978 
979  if ( e == REPLACE )
980  {
981  QString old = *(--wlIt); ++wlIt;
982  dlgreplacement = word;
983  checkListReplaceCurrent();
984  // inform application
985  emit corrected( old, *(--wlIt), lastpos ); ++wlIt;
986  }
987  else if( usedialog )
988  {
989  cwword = word;
990  dlgon = true;
991  // show the dialog
992  dialog( word, sugg, SLOT(checkList4()) );
993  return;
994  }
995  else
996  {
997  d->m_bNoMisspellingsEncountered = false;
998  emit misspelling( word, sugg, lastpos );
999  }
1000  }
1001 
1002  }
1003  emitProgress (); //maybe
1004 
1005  // stop when empty line or no more data
1006  } while (tempe > 0);
1007 
1008  //kDebug(750) << "checkList3a: exit loop with [" << tempe << "]";
1009 
1010  // if we got an empty line, t.e. end of ispell/aspell response
1011  // and the dialog isn't waiting for user interaction, send next word
1012  if (d->endOfResponse && !dlgon) {
1013  //kDebug(750) << "checkList3a: send next word";
1014  checkList2();
1015  }
1016 }
1017 
1018 void K3Spell::checkListReplaceCurrent()
1019 {
1020 
1021  // go back to misspelled word
1022  wlIt--;
1023 
1024  QString s = *wlIt;
1025  s.replace(posinline+offset,orig.length(),replacement());
1026  offset += replacement().length()-orig.length();
1027  wordlist->insert (wlIt, s);
1028  wlIt = wordlist->erase (wlIt);
1029  // wlIt now points to the word after the repalced one
1030 
1031 }
1032 
1033 void K3Spell::checkList4 ()
1034  // evaluate dialog return, when a button was pressed there
1035 {
1036  dlgon=false;
1037  QString old;
1038 
1039  disconnect (this, SIGNAL (dialog3()), this, SLOT (checkList4()));
1040 
1041  //others should have been processed by dialog() already
1042  switch (dlgresult)
1043  {
1044  case KS_REPLACE:
1045  case KS_REPLACEALL:
1046  kDebug(750) << "KS: cklist4: lastpos: " << lastpos;
1047  old = *(--wlIt);
1048  ++wlIt;
1049  // replace word
1050  checkListReplaceCurrent();
1051  emit corrected( old, *(--wlIt), lastpos );
1052  ++wlIt;
1053  break;
1054  case KS_CANCEL:
1055  ksdlg->hide();
1056  emit done( false );
1057  return;
1058  case KS_STOP:
1059  ksdlg->hide();
1060  emit done( true );
1061  return;
1062  case KS_CONFIG:
1063  ksdlg->hide();
1064  emit done( false );
1065  //check( origbuffer.mid( lastpos ), true );
1066  //trystart = 0;
1067  //proc->disconnect();
1068  //proc->kill();
1069  //delete proc;
1070  //proc = new KProcess( codec );
1071  //startIspell();
1072  return;
1073  };
1074 
1075  // read more if there is more, otherwise send next word
1076  if (!d->endOfResponse) {
1077  //kDebug(750) << "checkList4: read more from response";
1078  checkList3a();
1079  }
1080 }
1081 
1082 bool K3Spell::check( const QString &_buffer, bool _usedialog )
1083 {
1084  QString qs;
1085 
1086  usedialog = _usedialog;
1087  setUpDialog();
1088  //set the dialog signal handler
1089  dialog3slot = SLOT(check3());
1090 
1091  kDebug(750) << "KS: check";
1092  origbuffer = _buffer;
1093  if ( ( totalpos = origbuffer.length() ) == 0 )
1094  {
1095  emit done( origbuffer );
1096  return false;
1097  }
1098 
1099 
1100  // Torben: I corrected the \n\n problem directly in the
1101  // origbuffer since I got errors otherwise
1102  if ( !origbuffer.endsWith("\n\n" ) )
1103  {
1104  if (origbuffer.at(origbuffer.length()-1)!='\n')
1105  {
1106  origbuffer+='\n';
1107  origbuffer+='\n'; //shouldn't these be removed at some point?
1108  }
1109  else
1110  origbuffer+='\n';
1111  }
1112 
1113  newbuffer = origbuffer;
1114 
1115  // KProcess calls check2 when read from ispell
1116  OUTPUT( check2 );
1117  proc->write( QByteArray( "!" ) );
1118 
1119  //lastpos is a position in newbuffer (it has offset in it)
1120  offset = lastlastline = lastpos = lastline = 0;
1121 
1122  emitProgress();
1123 
1124  // send first buffer line
1125  int i = origbuffer.indexOf( '\n', 0 ) + 1;
1126  qs = origbuffer.mid( 0, i );
1127  cleanFputs( qs );
1128 
1129  lastline=i; //the character position, not a line number
1130 
1131  if ( usedialog )
1132  {
1133  emitProgress();
1134  }
1135  else
1136  ksdlg->hide();
1137 
1138  return true;
1139 }
1140 
1141 int K3Spell::lastPosition() const
1142 {
1143  return lastpos;
1144 }
1145 
1146 
1147 void K3Spell::check2()
1148  // invoked by KProcess when read from ispell
1149 {
1150  int e;
1151  qint64 tempe;
1152  QString word;
1153  QString line;
1154  static bool recursive = false;
1155  if (recursive &&
1156  !ksdlg )
1157  {
1158  return;
1159  }
1160  recursive = true;
1161 
1162  do
1163  {
1164  QByteArray data;
1165  tempe = proc->readLine( data.data(), data.count() ); //get ispell's response
1166  line = d->convertQByteArray( data );
1167  //kDebug(750) << "K3Spell::check2 (" << tempe << "b)";
1168 
1169  if ( tempe>0 )
1170  {
1171  if ( ( e=parseOneResponse (line, word, sugg) )==MISTAKE ||
1172  e==REPLACE)
1173  {
1174  dlgresult=-1;
1175 
1176  // for multibyte encoding posinline needs correction
1177  if ((ksconfig->encoding() == KS_E_UTF8) && !d->aspellV6) {
1178  // kDebug(750) << "line: " << origbuffer.mid(lastlastline,
1179  // lastline-lastlastline) << endl;
1180  // kDebug(750) << "posinline uncorr: " << posinline;
1181 
1182  // convert line to UTF-8, cut at pos, convert back to UCS-2
1183  // and get string length
1184  posinline = (QString::fromUtf8(
1185  origbuffer.mid(lastlastline,lastline-lastlastline).toUtf8(),
1186  posinline)).length();
1187  // kDebug(750) << "posinline corr: " << posinline;
1188  }
1189 
1190  lastpos = posinline+lastlastline+offset;
1191 
1192  //orig is set by parseOneResponse()
1193 
1194  if (e==REPLACE)
1195  {
1196  dlgreplacement=word;
1197  emit corrected( orig, replacement(), lastpos );
1198  offset += replacement().length()-orig.length();
1199  newbuffer.replace( lastpos, orig.length(), word );
1200  }
1201  else //MISTAKE
1202  {
1203  cwword = word;
1204  //kDebug(750) << "(Before dialog) word=[" << word << "] cwword =[" << cwword << "]\n";
1205  if ( usedialog ) {
1206  // show the word in the dialog
1207  dialog( word, sugg, SLOT(check3()) );
1208  } else {
1209  // No dialog, just emit misspelling and continue
1210  d->m_bNoMisspellingsEncountered = false;
1211  emit misspelling( word, sugg, lastpos );
1212  dlgresult = KS_IGNORE;
1213  check3();
1214  }
1215  recursive = false;
1216  return;
1217  }
1218  }
1219 
1220  }
1221 
1222  emitProgress(); //maybe
1223 
1224  } while( tempe>0 );
1225 
1226  if ( tempe == -1 ) { //we were called, but no data seems to be ready...
1227  // Make sure we don't get called directly again and make sure we do get
1228  // called when new data arrives.
1229  NOOUTPUT( check2 );
1230 // proc->enableReadSignals(true);
1231  OUTPUT( check2 );
1232  recursive = false;
1233  return;
1234  }
1235 
1236 // proc->ackRead();
1237 
1238  //If there is more to check, then send another line to ISpell.
1239  if ( lastline < origbuffer.length() )
1240  {
1241  int i;
1242  QString qs;
1243 
1244  //kDebug(750) << "[EOL](" << tempe << ")[" << temp << "]";
1245 
1246  lastpos = (lastlastline=lastline) + offset; //do we really want this?
1247  i = origbuffer.indexOf('\n', lastline) + 1;
1248  qs = origbuffer.mid( lastline, i-lastline );
1249  cleanFputs( qs );
1250  lastline = i;
1251  recursive = false;
1252  return;
1253  }
1254  else
1255  //This is the end of it all
1256  {
1257  ksdlg->hide();
1258  // kDebug(750) << "check2() done";
1259  newbuffer.truncate( newbuffer.length()-2 );
1260  emitProgress();
1261  emit done( newbuffer );
1262  }
1263  recursive = false;
1264 }
1265 
1266 void K3Spell::check3 ()
1267  // evaluates the return value of the dialog
1268 {
1269  disconnect (this, SIGNAL (dialog3()), this, SLOT (check3()));
1270  kDebug(750) << "check3 [" << cwword << "] [" << replacement() << "] " << dlgresult;
1271 
1272  //others should have been processed by dialog() already
1273  switch (dlgresult)
1274  {
1275  case KS_REPLACE:
1276  case KS_REPLACEALL:
1277  offset+=replacement().length()-cwword.length();
1278  newbuffer.replace (lastpos, cwword.length(),
1279  replacement());
1280  emit corrected (dlgorigword, replacement(), lastpos);
1281  break;
1282  case KS_CANCEL:
1283  // kDebug(750) << "canceled\n";
1284  ksdlg->hide();
1285  emit done( origbuffer );
1286  return;
1287  case KS_CONFIG:
1288  ksdlg->hide();
1289  emit done( origbuffer );
1290  KMessageBox::information( 0, i18n("You have to restart the dialog for changes to take effect") );
1291  //check( origbuffer.mid( lastpos ), true );
1292  return;
1293  case KS_STOP:
1294  ksdlg->hide();
1295  //buffer=newbuffer);
1296  emitProgress();
1297  emit done (newbuffer);
1298  return;
1299  };
1300 
1301 // proc->ackRead();
1302 }
1303 
1304 void
1305 K3Spell::slotStopCancel (int result)
1306 {
1307  if (dialogwillprocess)
1308  return;
1309 
1310  kDebug(750) << "K3Spell::slotStopCancel [" << result << "]";
1311 
1312  if (result==KS_STOP || result==KS_CANCEL)
1313  if (!dialog3slot.isEmpty())
1314  {
1315  dlgresult=result;
1316  connect (this, SIGNAL (dialog3()), this, dialog3slot.toLatin1().constData());
1317  emit dialog3();
1318  }
1319 }
1320 
1321 
1322 void K3Spell::dialog( const QString & word, QStringList & sugg, const char *_slot )
1323 {
1324  dlgorigword = word;
1325 
1326  dialog3slot = _slot;
1327  dialogwillprocess = true;
1328  connect( ksdlg, SIGNAL(command(int)), this, SLOT(dialog2(int)) );
1329  QString tmpBuf = newbuffer;
1330  kDebug(750)<<" position = "<<lastpos;
1331 
1332  // extract a context string, replace all characters which might confuse
1333  // the RichText display and highlight the possibly wrong word
1334  QString marker( "_MARKER_" );
1335  tmpBuf.replace( lastpos, word.length(), marker );
1336  QString context = tmpBuf.mid(qMax(lastpos-18,0), 2*18+marker.length());
1337  context.replace( '\n',QLatin1Char(' '));
1338  context.replace( '<', QLatin1String("&lt;") );
1339  context.replace( '>', QLatin1String("&gt;") );
1340  context.replace( marker, QString::fromLatin1("<b>%1</b>").arg( word ) );
1341  context = "<qt>" + context + "</qt>";
1342 
1343  ksdlg->init( word, &sugg, context );
1344  d->m_bNoMisspellingsEncountered = false;
1345  emit misspelling( word, sugg, lastpos );
1346 
1347  emitProgress();
1348  ksdlg->show();
1349 }
1350 
1351 QString K3Spell::replacement () const
1352 {
1353  return dlgreplacement;
1354 }
1355 
1356 void K3Spell::dialog2( int result )
1357 {
1358  QString qs;
1359 
1360  disconnect( ksdlg, SIGNAL(command(int)), this, SLOT(dialog2(int)) );
1361  dialogwillprocess = false;
1362  dlgresult = result;
1363  ksdlg->standby();
1364 
1365  dlgreplacement = ksdlg->replacement();
1366 
1367  //process result here
1368  switch ( dlgresult )
1369  {
1370  case KS_IGNORE:
1371  emit ignoreword( dlgorigword );
1372  break;
1373  case KS_IGNOREALL:
1374  // would be better to lower case only words with beginning cap
1375  ignorelist.prepend( dlgorigword.toLower() );
1376  emit ignoreall( dlgorigword );
1377  break;
1378  case KS_ADD:
1379  addPersonal( dlgorigword );
1380  personaldict = true;
1381  emit addword( dlgorigword );
1382  // adding to pesonal dict takes effect at the next line, not the current
1383  ignorelist.prepend( dlgorigword.toLower() );
1384  break;
1385  case KS_REPLACEALL:
1386  {
1387  replacelist.append( dlgorigword );
1388  QString _replacement = replacement();
1389  replacelist.append( _replacement );
1390  emit replaceall( dlgorigword , _replacement );
1391  }
1392  break;
1393  case KS_SUGGEST:
1394  checkWord( ksdlg->replacement(), false, true );
1395  return;
1396  break;
1397  }
1398 
1399  connect( this, SIGNAL(dialog3()), this, dialog3slot.toLatin1().constData() );
1400  emit dialog3();
1401 }
1402 
1403 
1404 K3Spell::~K3Spell()
1405 {
1406  delete proc;
1407  delete ksconfig;
1408  delete ksdlg;
1409  delete d->checkNextTimer;
1410  delete d;
1411 }
1412 
1413 
1414 K3SpellConfig K3Spell::ksConfig() const
1415 {
1416  ksconfig->setIgnoreList(ignorelist);
1417  ksconfig->setReplaceAllList(replacelist);
1418  return *ksconfig;
1419 }
1420 
1421 void K3Spell::cleanUp()
1422 {
1423  if ( m_status == Cleaning )
1424  return; // Ignore
1425 
1426  if ( m_status == Running )
1427  {
1428  if ( personaldict )
1429  writePersonalDictionary();
1430  m_status = Cleaning;
1431  }
1432  proc->closeWriteChannel();
1433 }
1434 
1435 void K3Spell::setAutoDelete(bool _autoDelete)
1436 {
1437  autoDelete = _autoDelete;
1438 }
1439 
1440 void K3Spell::ispellExit()
1441 {
1442  kDebug() << "K3Spell::ispellExit() " << m_status;
1443 
1444  if ( (m_status == Starting) && (trystart < maxtrystart) )
1445  {
1446  trystart++;
1447  startIspell();
1448  return;
1449  }
1450 
1451  if ( m_status == Starting )
1452  m_status = Error;
1453  else if (m_status == Cleaning)
1454  m_status = d->m_bNoMisspellingsEncountered ? FinishedNoMisspellingsEncountered : Finished;
1455  else if ( m_status == Running )
1456  m_status = Crashed;
1457  else // Error, Finished, Crashed
1458  return; // Dead already
1459 
1460  kDebug(750) << "Death";
1461  QTimer::singleShot( 0, this, SLOT(emitDeath()) );
1462 }
1463 
1464 // This is always called from the event loop to make
1465 // sure that the receiver can safely delete the
1466 // K3Spell object.
1467 void K3Spell::emitDeath()
1468 {
1469  bool deleteMe = autoDelete; // Can't access object after next call!
1470  emit death();
1471  if ( deleteMe )
1472  deleteLater();
1473 }
1474 
1475 void K3Spell::setProgressResolution (unsigned int res)
1476 {
1477  progres=res;
1478 }
1479 
1480 void K3Spell::emitProgress ()
1481 {
1482  uint nextprog = (uint) (100.*lastpos/(double)totalpos);
1483 
1484  if ( nextprog >= curprog )
1485  {
1486  curprog = nextprog;
1487  emit progress( curprog );
1488  }
1489 }
1490 
1491 void K3Spell::moveDlg( int x, int y )
1492 {
1493  QPoint pt( x,y ), pt2;
1494  pt2 = parent->mapToGlobal( pt );
1495  ksdlg->move( pt2.x(),pt2.y() );
1496 }
1497 
1498 void K3Spell::setIgnoreUpperWords(bool _ignore)
1499 {
1500  d->m_bIgnoreUpperWords=_ignore;
1501 }
1502 
1503 void K3Spell::setIgnoreTitleCase(bool _ignore)
1504 {
1505  d->m_bIgnoreTitleCase=_ignore;
1506 }
1507 // --------------------------------------------------
1508 // Stuff for modal (blocking) spell checking
1509 //
1510 // Written by Torben Weis <weis@kde.org>. So please
1511 // send bug reports regarding the modal stuff to me.
1512 // --------------------------------------------------
1513 
1514 int
1515 K3Spell::modalCheck( QString& text )
1516 {
1517  return modalCheck( text,0 );
1518 }
1519 
1520 int
1521 K3Spell::modalCheck( QString& text, K3SpellConfig* _kcs )
1522 {
1523  modalreturn = 0;
1524  modaltext = text;
1525 
1526  K3Spell* spell = new K3Spell( 0L, i18n("Spell Checker"), 0 ,
1527  0, _kcs, true, true );
1528 
1529  while (spell->status()!=Finished)
1530  qApp->processEvents();
1531 
1532  text = modaltext;
1533 
1534  delete spell;
1535  return modalreturn;
1536 }
1537 
1538 void K3Spell::slotSpellCheckerCorrected( const QString & oldText, const QString & newText, unsigned int pos )
1539 {
1540  modaltext=modaltext.replace(pos,oldText.length(),newText);
1541 }
1542 
1543 
1544 void K3Spell::slotModalReady()
1545 {
1546  //kDebug() << qApp->loopLevel();
1547  //kDebug(750) << "MODAL READY------------------";
1548 
1549  Q_ASSERT( m_status == Running );
1550  connect( this, SIGNAL(done(QString)),
1551  this, SLOT(slotModalDone(QString)) );
1552  QObject::connect( this, SIGNAL(corrected(QString,QString,uint)),
1553  this, SLOT(slotSpellCheckerCorrected(QString,QString,uint)) );
1554  QObject::connect( this, SIGNAL(death()),
1555  this, SLOT(slotModalSpellCheckerFinished()) );
1556  check( modaltext );
1557 }
1558 
1559 void K3Spell::slotModalDone( const QString &/*_buffer*/ )
1560 {
1561  //kDebug(750) << "MODAL DONE " << _buffer;
1562  //modaltext = _buffer;
1563  cleanUp();
1564 
1565  //kDebug() << "ABOUT TO EXIT LOOP";
1566  //qApp->exit_loop();
1567 
1568  //modalWidgetHack->close(true);
1569  slotModalSpellCheckerFinished();
1570 }
1571 
1572 void K3Spell::slotModalSpellCheckerFinished( )
1573 {
1574  modalreturn=(int)this->status();
1575 }
1576 
1577 void K3Spell::initialize( QWidget *_parent, const QString &_caption,
1578  QObject *obj, const char *slot, K3SpellConfig *_ksc,
1579  bool _progressbar, bool _modal, SpellerType type )
1580 {
1581  d = new K3SpellPrivate;
1582 
1583  d->m_bIgnoreUpperWords =false;
1584  d->m_bIgnoreTitleCase =false;
1585  d->m_bNoMisspellingsEncountered = true;
1586  d->type = type;
1587  d->checking = false;
1588  d->aspellV6 = false;
1589  d->checkNextTimer = new QTimer( this );
1590  connect( d->checkNextTimer, SIGNAL(timeout()),
1591  this, SLOT(checkNext()));
1592  autoDelete = false;
1593  modaldlg = _modal;
1594  progressbar = _progressbar;
1595 
1596  proc = 0;
1597  ksconfig = 0;
1598  ksdlg = 0;
1599  lastpos = 0;
1600 
1601  //won't be using the dialog in ksconfig, just the option values
1602  if ( _ksc )
1603  ksconfig = new K3SpellConfig( *_ksc );
1604  else
1605  ksconfig = new K3SpellConfig;
1606 
1607  d->m_codec = 0;
1608  switch ( ksconfig->encoding() )
1609  {
1610  case KS_E_LATIN1:
1611  d->m_codec = QTextCodec::codecForName("ISO 8859-1");
1612  break;
1613  case KS_E_LATIN2:
1614  d->m_codec = QTextCodec::codecForName("ISO 8859-2");
1615  break;
1616  case KS_E_LATIN3:
1617  d->m_codec = QTextCodec::codecForName("ISO 8859-3");
1618  break;
1619  case KS_E_LATIN4:
1620  d->m_codec = QTextCodec::codecForName("ISO 8859-4");
1621  break;
1622  case KS_E_LATIN5:
1623  d->m_codec = QTextCodec::codecForName("ISO 8859-5");
1624  break;
1625  case KS_E_LATIN7:
1626  d->m_codec = QTextCodec::codecForName("ISO 8859-7");
1627  break;
1628  case KS_E_LATIN8:
1629  d->m_codec = QTextCodec::codecForName("ISO 8859-8-i");
1630  break;
1631  case KS_E_LATIN9:
1632  d->m_codec = QTextCodec::codecForName("ISO 8859-9");
1633  break;
1634  case KS_E_LATIN13:
1635  d->m_codec = QTextCodec::codecForName("ISO 8859-13");
1636  break;
1637  case KS_E_LATIN15:
1638  d->m_codec = QTextCodec::codecForName("ISO 8859-15");
1639  break;
1640  case KS_E_UTF8:
1641  d->m_codec = QTextCodec::codecForName("UTF-8");
1642  break;
1643  case KS_E_KOI8R:
1644  d->m_codec = QTextCodec::codecForName("KOI8-R");
1645  break;
1646  case KS_E_KOI8U:
1647  d->m_codec = QTextCodec::codecForName("KOI8-U");
1648  break;
1649  case KS_E_CP1251:
1650  d->m_codec = QTextCodec::codecForName("CP1251");
1651  break;
1652  case KS_E_CP1255:
1653  d->m_codec = QTextCodec::codecForName("CP1255");
1654  break;
1655  default:
1656  break;
1657  }
1658 
1659  kDebug(750) << __FILE__ << ":" << __LINE__ << " Codec = " << (d->m_codec ? d->m_codec->name() : "<default>");
1660 
1661  // copy ignore list from ksconfig
1662  ignorelist += ksconfig->ignoreList();
1663 
1664  replacelist += ksconfig->replaceAllList();
1665  texmode=dlgon=false;
1666  m_status = Starting;
1667  dialogsetup = false;
1668  progres=10;
1669  curprog=0;
1670 
1671  dialogwillprocess = false;
1672  dialog3slot.clear();
1673 
1674  personaldict = false;
1675  dlgresult = -1;
1676 
1677  caption = _caption;
1678 
1679  parent = _parent;
1680 
1681  trystart = 0;
1682  maxtrystart = 2;
1683 
1684  if ( obj && slot )
1685  // caller wants to know when k3spell is ready
1686  connect( this, SIGNAL(ready(K3Spell*)), obj, slot);
1687  else
1688  // Hack for modal spell checking
1689  connect( this, SIGNAL(ready(K3Spell*)), this, SLOT(slotModalReady()) );
1690 
1691  proc = new KProcess();
1692 
1693  startIspell();
1694 }
1695 
1696 QString K3Spell::modaltext;
1697 int K3Spell::modalreturn = 0;
1698 QWidget* K3Spell::modalWidgetHack = 0;
1699 
1700 #include "k3spell.moc"
1701 
KS_E_LATIN4
Definition: k3sconfig.h:46
KProcess::setNextOpenMode
void setNextOpenMode(QIODevice::OpenMode mode)
i18n
QString i18n(const char *text)
KS_E_LATIN8
ISO-8859-7 (Greek)
Definition: k3sconfig.h:49
K3Spell::setUpDialog
void setUpDialog(bool reallyusedialogbox=true)
Definition: k3spell.cpp:470
K3Spell::maxtrystart
int maxtrystart
Definition: k3spell.h:525
qint64
K3Spell::ignoreall
void ignoreall(const QString &originalword)
Emitted when the user pressed "Ignore All" in the dialog.
K3Spell::dialog3slot
QString dialog3slot
Definition: k3spell.h:521
K3Spell::checkList4
void checkList4()
Definition: k3spell.cpp:1033
KS_E_LATIN15
ISO-8859-15 (Latin 9)
Definition: k3sconfig.h:52
determineASpellV6
static bool determineASpellV6()
Definition: k3spell.cpp:167
KProcess
put
TransferJob * put(const KUrl &url, int permissions, JobFlags flags=DefaultFlags)
kdebug.h
K3SpellDlg::replacement
QString replacement() const
Definition: k3spelldlg.cpp:114
K3SpellConfig::runTogether
bool runTogether() const
Definition: k3sconfig.cpp:1007
K3Spell::emitProgress
void emitProgress()
Definition: k3spell.cpp:1480
K3Spell::setAutoDelete
void setAutoDelete(bool _autoDelete)
Sets the auto-delete flag.
Definition: k3spell.cpp:1435
K3Spell::K3Spell2
void K3Spell2()
Definition: k3spell.cpp:422
K3Spell::lastlastline
unsigned int lastlastline
Definition: k3spell.h:530
K3SpellConfig::encoding
int encoding() const
Definition: k3sconfig.cpp:1026
K3Spell::Crashed
Definition: k3spell.h:65
K3Spell::progres
unsigned int progres
Definition: k3spell.h:532
K3Spell::ksConfig
K3SpellConfig ksConfig() const
Definition: k3spell.cpp:1414
K3Spell::modalWidgetHack
static QWidget * modalWidgetHack
Definition: k3spell.h:541
timeout
int timeout
K3Spell::dialog3
void dialog3()
KS_E_KOI8R
Definition: k3sconfig.h:54
KMessageBox::information
static void information(QWidget *parent, const QString &text, const QString &caption=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
KS_REPLACE
Definition: k3spelldlg.h:37
QWidget
K3Spell::parseOneResponse
int parseOneResponse(const QString &_buffer, QString &word, QStringList &sugg)
Definition: k3spell.cpp:783
K3Spell::checkWord
virtual bool checkWord(const QString &_buffer, bool usedialog=false)
Spellchecks a single word.
Definition: k3spell.cpp:571
K3Spell::replaceall
void replaceall(const QString &origword, const QString &replacement)
Emitted when the user pressed "ReplaceAll" in the dialog.
NOOUTPUT
#define NOOUTPUT(x)
Definition: k3spell.cpp:121
KS_SUGGEST
Definition: k3spelldlg.h:43
K3Spell::checkNext
void checkNext()
Definition: k3spell.cpp:703
k3sconfig.h
kError
static QDebug kError(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KS_IGNORE
Definition: k3spelldlg.h:39
KProcess::setOutputChannelMode
void setOutputChannelMode(OutputChannelMode mode)
K3SpellConfig
A configuration class/dialog for K3Spell.
Definition: k3sconfig.h:88
K3Spell::curprog
unsigned int curprog
Definition: k3spell.h:533
K3Spell::origbuffer
QString origbuffer
Definition: k3spell.h:516
K3Spell::writePersonalDictionary
bool writePersonalDictionary()
Definition: k3spell.cpp:503
QString
KS_E_LATIN13
ISO-8859-13 (Latin 7)
Definition: k3sconfig.h:51
K3Spell::ispellExit
void ispellExit()
Definition: k3spell.cpp:1440
QObject
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
klocale.h
KS_CLIENT_HUNSPELL
Definition: k3sconfig.h:65
KS_ADD
Definition: k3spelldlg.h:41
MISTAKE
Definition: k3spell.cpp:57
K3Spell::setIgnoreTitleCase
void setIgnoreTitleCase(bool b)
Call setIgnoreTitleCase(true) to tell the spell-checker to ignore words with a 'title' case...
Definition: k3spell.cpp:1503
K3Spell::~K3Spell
virtual ~K3Spell()
The destructor instructs ISpell/ASpell to write out the personal dictionary and then terminates ISpel...
Definition: k3spell.cpp:1404
KS_CANCEL
Definition: k3spelldlg.h:36
K3Spell::setProgressResolution
void setProgressResolution(unsigned int res)
Sets the resolution (in percent) of the progress() signals.
Definition: k3spell.cpp:1475
KS_CLIENT_ASPELL
Definition: k3sconfig.h:62
K3Spell::autoDelete
bool autoDelete
Definition: k3spell.h:512
K3Spell::checkWord2
void checkWord2()
Definition: k3spell.cpp:661
K3Spell::dlgorigword
QString dlgorigword
Definition: k3spell.h:519
K3SpellConfig::dictionary
const QString dictionary() const
Definition: k3sconfig.cpp:1013
K3Spell::check2
void check2()
Definition: k3spell.cpp:1147
K3Spell::modaldlg
bool modaldlg
Used for modalCheck.
Definition: k3spell.h:538
K3Spell::lastPosition
int lastPosition() const
Returns the position (when using check()) or word number (when using checkList()) of the last word ch...
Definition: k3spell.cpp:1141
KS_E_LATIN2
Definition: k3sconfig.h:44
K3Spell::slotStopCancel
void slotStopCancel(int)
Definition: k3spell.cpp:1305
KS_E_KOI8U
Definition: k3sconfig.h:55
K3Spell::parent
QWidget * parent
Definition: k3spell.h:494
K3Spell::progressbar
bool progressbar
Definition: k3spell.h:510
K3Spell::wlIt
QStringList::Iterator wlIt
Definition: k3spell.h:498
K3Spell::spellStatus
spellStatus
Possible states of the spell checker.
Definition: k3spell.h:65
kprocess.h
KS_CLIENT_ISPELL
Definition: k3sconfig.h:61
K3Spell::addPersonal
virtual bool addPersonal(const QString &word)
Adds a word to the user's personal dictionary.
Definition: k3spell.cpp:489
K3Spell::check3
void check3()
Definition: k3spell.cpp:1266
K3Spell::funnyWord
QString funnyWord(const QString &word)
Definition: k3spell.cpp:748
KS_CLIENT_HSPELL
Definition: k3sconfig.h:63
Method1
Definition: k3spell.cpp:60
KS_E_CP1255
Definition: k3sconfig.h:57
K3Spell::dialogwillprocess
bool dialogwillprocess
Definition: k3spell.h:509
K3SpellConfig::replaceAllList
QStringList replaceAllList() const
Definition: k3sconfig.cpp:1181
K3Spell::Starting
Definition: k3spell.h:65
K3SpellDlg
Definition: k3spelldlg.h:50
K3Spell::posinline
unsigned int posinline
Definition: k3spell.h:529
QStringList
K3Spell::sugg
QStringList sugg
Definition: k3spell.h:501
K3Spell::K3Spell
K3Spell(QWidget *parent, const QString &caption, QObject *receiver, const char *slot, K3SpellConfig *kcs=0, bool progressbar=true, bool modal=false)
Starts the spellchecker.
Definition: k3spell.cpp:125
K3Spell::lastline
int lastline
Definition: k3spell.h:528
K3Spell::cleanUp
virtual void cleanUp()
Cleans up ISpell.
Definition: k3spell.cpp:1421
K3Spell::ignorelist
QStringList ignorelist
Definition: k3spell.h:499
K3Spell::done
void done(const QString &buffer)
Emitted when check() is done.
K3Spell::personaldict
bool personaldict
Definition: k3spell.h:508
K3Spell::progress
void progress(unsigned int i)
Emitted during a check().
K3Spell::intermediateBuffer
QString intermediateBuffer() const
Returns the partially spellchecked buffer.
Definition: k3spell.cpp:161
K3Spell::caption
QString caption
Definition: k3spell.h:514
K3Spell::dialog2
void dialog2(int dlgresult)
Definition: k3spell.cpp:1356
Method2
Definition: k3spell.cpp:60
k3spell.h
K3Spell::dialogsetup
bool dialogsetup
Definition: k3spell.h:511
K3Spell::HTML
Definition: k3spell.h:80
K3Spell::SpellerType
SpellerType
These are possible types of documents which the spell checker can check.
Definition: k3spell.h:80
KS_E_UTF8
Definition: k3sconfig.h:53
REPLACE
Definition: k3spell.cpp:56
K3Spell::ignoreword
void ignoreword(const QString &originalword)
Emitted when the user pressed "Ignore" in the dialog.
K3Spell::heightDlg
int heightDlg() const
Returns the height of the dialog box.
Definition: k3spell.cpp:158
K3Spell::dialog
void dialog(const QString &word, QStringList &sugg, const char *_slot)
Definition: k3spell.cpp:1322
K3Spell::suggestions
QStringList suggestions() const
Returns list of suggested word replacements.
Definition: k3spell.cpp:148
K3Spell::emitDeath
void emitDeath()
Definition: k3spell.cpp:1467
K3Spell::setIgnoreUpperWords
void setIgnoreUpperWords(bool b)
Call setIgnoreUpperWords(true) to tell the spell-checker to ignore words that are completely uppercas...
Definition: k3spell.cpp:1498
K3Spell::totalpos
unsigned int totalpos
Definition: k3spell.h:527
KProcess::start
void start()
K3Spell::misspelling
void misspelling(const QString &originalword, const QStringList &suggestions, unsigned int pos)
Emitted whenever a misspelled word is found by check() or by checkWord().
K3Spell::widthDlg
int widthDlg() const
Returns the width of the dialog box.
Definition: k3spell.cpp:159
IGNORE
Definition: k3spell.cpp:55
K3Spell::orig
QString orig
Definition: k3spell.h:515
K3Spell::ready
void ready(K3Spell *)
Emitted after K3Spell has verified that ISpell/ASpell is running and working properly.
K3Spell::dlgresult
int dlgresult
Definition: k3spell.h:523
K3Spell::usedialog
bool usedialog
Definition: k3spell.h:505
K3Spell::Text
Definition: k3spell.h:80
K3Spell::replacelist
QStringList replacelist
Definition: k3spell.h:500
K3SpellConfig::noRootAffix
bool noRootAffix() const
Definition: k3sconfig.cpp:1001
K3Spell::FinishedNoMisspellingsEncountered
Definition: k3spell.h:65
KS_E_LATIN5
ISO-8859-5 (Cyrillic)
Definition: k3sconfig.h:47
K3Spell::trystart
int trystart
Definition: k3spell.h:524
K3Spell::death
void death()
Emitted on terminal errors and after clean up.
K3Spell::modalCheck
static int modalCheck(QString &text)
Definition: k3spell.cpp:1515
K3SpellConfig::setIgnoreList
void setIgnoreList(const QStringList &_ignorelist)
Options setting routines.
Definition: k3sconfig.cpp:1163
K3Spell::replacement
QString replacement() const
Definition: k3spell.cpp:1351
K3Spell::offset
unsigned int offset
Definition: k3spell.h:531
K3Spell::status
spellStatus status() const
Returns the status of K3Spell.
Definition: k3spell.cpp:141
K3Spell::suggestWord
void suggestWord()
Definition: k3spell.cpp:718
K3SpellConfig::setReplaceAllList
void setReplaceAllList(const QStringList &_replaceAllList)
The _replaceAllList contains word you like that replace word.
Definition: k3sconfig.cpp:1175
K3Spell::wordlist
QStringList * wordlist
Definition: k3spell.h:497
KS_E_LATIN1
Definition: k3sconfig.h:43
QPoint
k3spelldlg.h
KS_STOP
Definition: k3spelldlg.h:42
KS_E_LATIN9
ISO-8859-8 (Hebrew)
Definition: k3sconfig.h:50
K3Spell::hide
void hide()
Hides the dialog box.
Definition: k3spell.cpp:146
K3Spell::dlgResult
int dlgResult() const
Gets the result code of the dialog box.
Definition: k3spell.cpp:153
K3Spell::addword
void addword(const QString &originalword)
Emitted when the user pressed "Add" in the dialog.
K3Spell::modaltext
static QString modaltext
Definition: k3spell.h:539
K3Spell::checkList3a
void checkList3a()
Definition: k3spell.cpp:944
version
unsigned int version()
K3Spell::Running
Definition: k3spell.h:65
KProcess::SeparateChannels
KS_E_LATIN3
Definition: k3sconfig.h:45
KS_IGNOREALL
Definition: k3spelldlg.h:40
K3Spell::texmode
bool texmode
Definition: k3spell.h:506
K3Spell::modalreturn
static int modalreturn
Definition: k3spell.h:540
K3Spell::corrected
void corrected(const QString &originalword, const QString &newword, unsigned int pos)
Emitted after the "Replace" or "Replace All" buttons of the dialog was pressed, or if the word was co...
MAXLINELENGTH
#define MAXLINELENGTH
Definition: k3spell.cpp:50
K3SpellDlg::init
void init(const QString &_word, QStringList *_sugg)
Change the misspelled word and suggested replacements and enable the disabled buttons on the dialog b...
Definition: k3spelldlg.cpp:120
K3Spell::m_status
spellStatus m_status
Definition: k3spell.h:503
K3SpellDlg::standby
void standby()
Definition: k3spelldlg.cpp:188
KS_REPLACEALL
Definition: k3spelldlg.h:38
K3Spell::checkList2
void checkList2()
Definition: k3spell.cpp:913
K3Spell::ksconfig
K3SpellConfig * ksconfig
Definition: k3spell.h:495
K3Spell::initialize
void initialize(QWidget *_parent, const QString &_caption, QObject *obj, const char *slot, K3SpellConfig *_ksc, bool _progressbar, bool _modal, SpellerType type)
Definition: k3spell.cpp:1577
KS_CONFIG
Definition: k3spelldlg.h:44
K3Spell::newbuffer
QString newbuffer
Definition: k3spell.h:517
checkMethod
checkMethod
Definition: k3spell.cpp:60
KS_E_CP1251
Definition: k3sconfig.h:56
OUTPUT
#define OUTPUT(x)
Definition: k3spell.cpp:118
K3Spell::check
virtual bool check(const QString &_buffer, bool usedialog=true)
Spellchecks a buffer of many words in plain text format.
Definition: k3spell.cpp:1082
K3Spell::checkWord3
void checkWord3()
Definition: k3spell.cpp:741
K3Spell::TeX
Definition: k3spell.h:80
K3Spell::checkListReplaceCurrent
void checkListReplaceCurrent()
Definition: k3spell.cpp:1018
K3Spell::cwword
QString cwword
Definition: k3spell.h:518
K3Spell::moveDlg
void moveDlg(int x, int y)
Moves the dialog.
Definition: k3spell.cpp:1491
GOOD
Definition: k3spell.cpp:54
K3Spell::Cleaning
Definition: k3spell.h:65
K3Spell::dlgon
bool dlgon
Definition: k3spell.h:507
K3Spell::dlgreplacement
QString dlgreplacement
Definition: k3spell.h:520
kmessagebox.h
K3Spell::ksdlg
K3SpellDlg * ksdlg
Definition: k3spell.h:496
K3Spell::ispellErrors
void ispellErrors()
Definition: k3spell.cpp:416
K3Spell::startIspell
void startIspell()
Definition: k3spell.cpp:192
K3Spell::cleanFputsWord
bool cleanFputsWord(const QString &s)
Definition: k3spell.cpp:522
K3Spell::checkList
virtual bool checkList(QStringList *_wordlist, bool usedialog=true)
Spellchecks a list of words.
Definition: k3spell.cpp:886
K3Spell::ignore
virtual bool ignore(const QString &word)
Tells ISpell/ASpell to ignore this word for the life of this K3Spell instance.
Definition: k3spell.cpp:508
K3Spell::Nroff
Definition: k3spell.h:80
K3Spell::Finished
Definition: k3spell.h:65
K3SpellConfig::client
int client() const
Spell checker client,.
Definition: k3sconfig.cpp:988
KS_E_LATIN7
ISO-8859-6 (Arabic)
Definition: k3sconfig.h:48
K3Spell::proc
KProcess * proc
Definition: k3spell.h:493
K3Spell::Error
Definition: k3spell.h:65
K3Spell
KDE Spellchecker
Definition: k3spell.h:46
QList< BufferedWord >
K3Spell::lastpos
int lastpos
Definition: k3spell.h:526
K3Spell::cleanFputs
bool cleanFputs(const QString &s)
Definition: k3spell.cpp:549
K3SpellConfig::ignoreList
QStringList ignoreList() const
Definition: k3sconfig.cpp:1169
KS_CLIENT_ZEMBEREK
Definition: k3sconfig.h:64
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:51:59 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDE3Support

Skip menu "KDE3Support"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal