summaryrefslogtreecommitdiffstats
path: root/tdeui/kspell.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdeui/kspell.cpp')
-rw-r--r--tdeui/kspell.cpp1577
1 files changed, 0 insertions, 1577 deletions
diff --git a/tdeui/kspell.cpp b/tdeui/kspell.cpp
deleted file mode 100644
index b91c74a4d..000000000
--- a/tdeui/kspell.cpp
+++ /dev/null
@@ -1,1577 +0,0 @@
-/* This file is part of the KDE libraries
- Copyright (C) 1997 David Sweet <dsweet@kde.org>
- Copyright (C) 2000-2001 Wolfram Diestel <wolfram@steloj.de>
- Copyright (C) 2003 Zack Rusin <zack@kde.org>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License version 2 as published by the Free Software Foundation.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <stdlib.h> // atoi
-
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-
-#include <tqregexp.h>
-#include <tqtextcodec.h>
-#include <tqtimer.h>
-
-#include <kapplication.h>
-#include <kmessagebox.h>
-#include <kdebug.h>
-#include <klocale.h>
-#include "kspell.h"
-#include "kspelldlg.h"
-#include <twin.h>
-#include <kprocio.h>
-
-#define MAXLINELENGTH 10000
-#undef IGNORE //fix possible conflict
-
-enum {
- GOOD= 0,
- IGNORE= 1,
- REPLACE= 2,
- MISTAKE= 3
-};
-
-enum checkMethod { Method1 = 0, Method2 };
-
-struct BufferedWord
-{
- checkMethod method;
- TQString word;
- bool useDialog;
- bool suggest;
-};
-
-class KSpell::KSpellPrivate
-{
-public:
- bool endOfResponse;
- bool m_bIgnoreUpperWords;
- bool m_bIgnoreTitleCase;
- bool m_bNoMisspellingsEncountered;
- SpellerType type;
- KSpell* suggestSpell;
- bool checking;
- TQValueList<BufferedWord> unchecked;
- TQTimer *checkNextTimer;
- bool aspellV6;
-};
-
-//TODO
-//Parse stderr output
-//e.g. -- invalid dictionary name
-
-/*
- Things to put in KSpellConfigDlg:
- make root/affix combinations that aren't in the dictionary (-m)
- don't generate any affix/root combinations (-P)
- Report run-together words with missing blanks as spelling errors. (-B)
- default dictionary (-d [dictionary])
- personal dictionary (-p [dictionary])
- path to ispell -- NO: ispell should be in $PATH
- */
-
-
-// Connects a slot to KProcIO's output signal
-#define OUTPUT(x) (connect (proc, TQT_SIGNAL (readReady(KProcIO *)), this, TQT_SLOT (x(KProcIO *))))
-
-// Disconnect a slot from...
-#define NOOUTPUT(x) (disconnect (proc, TQT_SIGNAL (readReady(KProcIO *)), this, TQT_SLOT (x(KProcIO *))))
-
-
-
-KSpell::KSpell( TQWidget *_parent, const TQString &_caption,
- TQObject *obj, const char *slot, KSpellConfig *_ksc,
- bool _progressbar, bool _modal )
-{
- initialize( _parent, _caption, obj, slot, _ksc,
- _progressbar, _modal, Text );
-}
-
-KSpell::KSpell( TQWidget *_parent, const TQString &_caption,
- TQObject *obj, const char *slot, KSpellConfig *_ksc,
- bool _progressbar, bool _modal, SpellerType type )
-{
- initialize( _parent, _caption, obj, slot, _ksc,
- _progressbar, _modal, type );
-}
-
-void KSpell::hide() { ksdlg->hide(); }
-
-int KSpell::heightDlg() const { return ksdlg->height(); }
-int KSpell::widthDlg() const { return ksdlg->width(); }
-
-// Check if aspell is at least version 0.6
-static bool determineASpellV6()
-{
- TQString result;
- FILE *fs = popen("aspell -v", "r");
- if (fs)
- {
- // Close textstream before we close fs
- {
- TQTextStream ts(fs, IO_ReadOnly);
- result = ts.read().stripWhiteSpace();
- }
- pclose(fs);
- }
-
- TQRegExp rx("Aspell (\\d.\\d)");
- if (rx.search(result) != -1)
- {
- float version = rx.cap(1).toFloat();
- return (version >= 0.6);
- }
- return false;
-}
-
-
-void
-KSpell::startIspell()
- //trystart = {0,1,2}
-{
- if ((trystart == 0) && (ksconfig->client() == KS_CLIENT_ASPELL))
- d->aspellV6 = determineASpellV6();
-
- kdDebug(750) << "Try #" << trystart << endl;
-
- if ( trystart > 0 ) {
- proc->resetAll();
- }
-
- switch ( ksconfig->client() )
- {
- case KS_CLIENT_ISPELL:
- *proc << "ispell";
- kdDebug(750) << "Using ispell" << endl;
- break;
- case KS_CLIENT_ASPELL:
- *proc << "aspell";
- kdDebug(750) << "Using aspell" << endl;
- break;
- case KS_CLIENT_HSPELL:
- *proc << "hspell";
- kdDebug(750) << "Using hspell" << endl;
- break;
- case KS_CLIENT_ZEMBEREK:
- *proc << "zpspell";
- kdDebug(750) << "Using zemberek(zpspell)" << endl;
- break;
- }
-
- if ( ksconfig->client() == KS_CLIENT_ISPELL || ksconfig->client() == KS_CLIENT_ASPELL )
- {
- *proc << "-a" << "-S";
-
- switch ( d->type )
- {
- case HTML:
- //Debian uses an ispell version that has the -h option instead.
- //Not sure what they did, but the preferred spell checker
- //on that platform is aspell anyway, so use -H untill I'll come
- //up with something better.
- *proc << "-H";
- break;
- case TeX:
- //same for aspell and ispell
- *proc << "-t";
- break;
- case Nroff:
- //only ispell supports
- if ( ksconfig->client() == KS_CLIENT_ISPELL )
- *proc << "-n";
- break;
- case Text:
- default:
- //nothing
- break;
- }
- if (ksconfig->noRootAffix())
- {
- *proc<<"-m";
- }
- if (ksconfig->runTogether())
- {
- *proc << "-B";
- }
- else
- {
- *proc << "-C";
- }
-
-
- if (trystart<2)
- {
- if (! ksconfig->dictionary().isEmpty())
- {
- kdDebug(750) << "using dictionary [" << ksconfig->dictionary() << "]" << endl;
- *proc << "-d";
- *proc << ksconfig->dictionary();
- }
- }
-
- //Note to potential debuggers: -Tlatin2 _is_ being added on the
- // _first_ try. But, some versions of ispell will fail with this
- // option, so kspell tries again without it. That's why as 'ps -ax'
- // shows "ispell -a -S ..." withou the "-Tlatin2" option.
-
- if ( trystart<1 ) {
- switch ( ksconfig->encoding() )
- {
- case KS_E_LATIN1:
- *proc << "-Tlatin1";
- break;
- case KS_E_LATIN2:
- *proc << "-Tlatin2";
- break;
- case KS_E_LATIN3:
- *proc << "-Tlatin3";
- break;
-
- // add the other charsets here
- case KS_E_LATIN4:
- case KS_E_LATIN5:
- case KS_E_LATIN7:
- case KS_E_LATIN8:
- case KS_E_LATIN9:
- case KS_E_LATIN13:
- // will work, if this is the default charset in the dictionary
- kdError(750) << "charsets ISO-8859-4, -5, -7, -8, -9 and -13 not supported yet" << endl;
- break;
- case KS_E_LATIN15: // ISO-8859-15 (Latin 9)
- if (ksconfig->client() == KS_CLIENT_ISPELL)
- {
- /*
- * As far as I know, there are no ispell dictionary using ISO-8859-15
- * but users have the tendency to select this encoding instead of ISO-8859-1
- * So put ispell in ISO-8859-1 (Latin 1) mode.
- */
- *proc << "-Tlatin1";
- }
- else
- kdError(750) << "ISO-8859-15 not supported for aspell yet." << endl;
- break;
- case KS_E_UTF8:
- *proc << "-Tutf8";
- if (ksconfig->client() == KS_CLIENT_ASPELL)
- *proc << "--encoding=utf-8";
- break;
- case KS_E_KOI8U:
- *proc << "-w'"; // add ' as a word char
- break;
- default:
- break;
- }
- }
-
- // -a : pipe mode
- // -S : sort suggestions by probable correctness
- }
- else // hspell and Zemberek(zpspell) doesn't need all the rest of the options
- *proc << "-a";
-
- if (trystart == 0) //don't connect these multiple times
- {
- connect( proc, TQT_SIGNAL(receivedStderr(TDEProcess *, char *, int)),
- this, TQT_SLOT(ispellErrors(TDEProcess *, char *, int)) );
-
- connect( proc, TQT_SIGNAL(processExited(TDEProcess *)),
- this, TQT_SLOT(ispellExit (TDEProcess *)) );
-
- OUTPUT(KSpell2);
- }
-
- if ( !proc->start() )
- {
- m_status = Error;
- TQTimer::singleShot( 0, this, TQT_SLOT(emitDeath()));
- }
-}
-
-void
-KSpell::ispellErrors( TDEProcess *, char *buffer, int buflen )
-{
- buffer[buflen-1] = '\0';
- // kdDebug(750) << "ispellErrors [" << buffer << "]\n" << endl;
-}
-
-void KSpell::KSpell2( KProcIO * )
-
-{
- TQString line;
-
- kdDebug(750) << "KSpell::KSpell2" << endl;
-
- trystart = maxtrystart; //We've officially started ispell and don't want
- //to try again if it dies.
-
- if ( proc->readln( line, true ) == -1 )
- {
- TQTimer::singleShot( 0, this, TQT_SLOT(emitDeath()) );
- return;
- }
-
-
- if ( line[0] != '@' ) //@ indicates that ispell is working fine
- {
- TQTimer::singleShot( 0, this, TQT_SLOT(emitDeath()) );
- return;
- }
-
- //We want to recognize KDE in any text!
- if ( !ignore("kde") )
- {
- kdDebug(750) << "@KDE was false" << endl;
- TQTimer::singleShot( 0, this, TQT_SLOT(emitDeath()) );
- return;
- }
-
- //We want to recognize linux in any text!
- if ( !ignore("linux") )
- {
- kdDebug(750) << "@Linux was false" << endl;
- TQTimer::singleShot( 0, this, TQT_SLOT(emitDeath()) );
- return;
- }
-
- NOOUTPUT( KSpell2 );
-
- m_status = Running;
- emit ready( this );
-}
-
-void
-KSpell::setUpDialog( bool reallyuseprogressbar )
-{
- if ( dialogsetup )
- return;
-
- //Set up the dialog box
- ksdlg = new KSpellDlg( parent, "dialog",
- progressbar && reallyuseprogressbar, modaldlg );
- ksdlg->setCaption( caption );
-
- connect( ksdlg, TQT_SIGNAL(command(int)),
- this, TQT_SLOT(slotStopCancel(int)) );
- connect( this, TQT_SIGNAL(progress(unsigned int)),
- ksdlg, TQT_SLOT(slotProgress(unsigned int)) );
-
-#ifdef Q_WS_X11 // FIXME(E): Implement for Qt/Embedded
- KWin::setIcons( ksdlg->winId(), kapp->icon(), kapp->miniIcon() );
-#endif
- if ( modaldlg )
- ksdlg->setFocus();
- dialogsetup = true;
-}
-
-bool KSpell::addPersonal( const TQString & word )
-{
- TQString qs = word.simplifyWhiteSpace();
-
- //we'll let ispell do the work here b/c we can
- if ( qs.find(' ') != -1 || qs.isEmpty() ) // make sure it's a _word_
- return false;
-
- qs.prepend( "*" );
- personaldict = true;
-
- return proc->writeStdin( qs );
-}
-
-bool KSpell::writePersonalDictionary()
-{
- return proc->writeStdin(TQString("#"));
-}
-
-bool KSpell::ignore( const TQString & word )
-{
- TQString qs = word.simplifyWhiteSpace();
-
- //we'll let ispell do the work here b/c we can
- if ( qs.find (' ') != -1 || qs.isEmpty() ) // make sure it's a _word_
- return false;
-
- qs.prepend( "@" );
-
- return proc->writeStdin( qs );
-}
-
-bool
-KSpell::cleanFputsWord( const TQString & s, bool appendCR )
-{
- TQString qs(s);
- bool empty = true;
-
- for( unsigned int i = 0; i < qs.length(); i++ )
- {
- //we need some punctuation for ornaments
- if ( qs[i] != '\'' && qs[i] != '\"' && qs[i] != '-'
- && qs[i].isPunct() || qs[i].isSpace() )
- {
- qs.remove(i,1);
- i--;
- } else {
- if ( qs[i].isLetter() )
- empty=false;
- }
- }
-
- // don't check empty words, otherwise synchronization will lost
- if (empty)
- return false;
-
- return proc->writeStdin( "^"+qs, appendCR );
-}
-
-bool
-KSpell::cleanFputs( const TQString & s, bool appendCR )
-{
- TQString qs(s);
- unsigned l = qs.length();
-
- // some uses of '$' (e.g. "$0") cause ispell to skip all following text
- for( unsigned int i = 0; i < l; ++i )
- {
- if( qs[i] == '$' )
- qs[i] = ' ';
- }
-
- if ( l<MAXLINELENGTH )
- {
- if ( qs.isEmpty() )
- qs="";
- return proc->writeStdin( "^"+qs, appendCR );
- }
- else
- return proc->writeStdin( TQString::fromAscii( "^\n" ),appendCR );
-}
-
-bool KSpell::checkWord( const TQString & buffer, bool _usedialog )
-{
- if (d->checking) { // don't check multiple words simultaneously
- BufferedWord bufferedWord;
- bufferedWord.method = Method1;
- bufferedWord.word = buffer;
- bufferedWord.useDialog = _usedialog;
- d->unchecked.append( bufferedWord );
- return true;
- }
- d->checking = true;
- TQString qs = buffer.simplifyWhiteSpace();
-
- if ( qs.find (' ') != -1 || qs.isEmpty() ) { // make sure it's a _word_
- d->checkNextTimer->start( 0, true );
- return false;
- }
- ///set the dialog signal handler
- dialog3slot = TQT_SLOT(checkWord3());
-
- usedialog = _usedialog;
- setUpDialog( false );
- if ( _usedialog )
- {
- emitProgress();
- }
- else
- ksdlg->hide();
-
- TQString blank_line;
- while (proc->readln( blank_line, true ) != -1); // eat spurious blanks
-
- OUTPUT(checkWord2);
- // connect (this, TQT_SIGNAL (dialog3()), this, TQT_SLOT (checkWord3()));
-
- proc->writeStdin(TQString("%")); // turn off terse mode
- proc->writeStdin( buffer ); // send the word to ispell
-
- return true;
-}
-
-bool KSpell::checkWord( const TQString & buffer, bool _usedialog, bool suggest )
-{
- if (d->checking) { // don't check multiple words simultaneously
- BufferedWord bufferedWord;
- bufferedWord.method = Method2;
- bufferedWord.word = buffer;
- bufferedWord.useDialog = _usedialog;
- bufferedWord.suggest = suggest;
- d->unchecked.append( bufferedWord );
- return true;
- }
- d->checking = true;
- TQString qs = buffer.simplifyWhiteSpace();
-
- if ( qs.find (' ') != -1 || qs.isEmpty() ) { // make sure it's a _word_
- d->checkNextTimer->start( 0, true );
- return false;
- }
-
- ///set the dialog signal handler
- if ( !suggest ) {
- dialog3slot = TQT_SLOT(checkWord3());
- usedialog = _usedialog;
- setUpDialog( false );
- if ( _usedialog )
- {
- emitProgress();
- }
- else
- ksdlg->hide();
- }
-
- TQString blank_line;
- while (proc->readln( blank_line, true ) != -1); // eat spurious blanks
-
- OUTPUT(checkWord2);
- // connect (this, TQT_SIGNAL (dialog3()), this, TQT_SLOT (checkWord3()));
-
- proc->writeStdin(TQString("%")); // turn off terse mode
- proc->writeStdin( buffer ); // send the word to ispell
-
- return true;
-}
-
-void KSpell::checkWord2( KProcIO* )
-{
- TQString word;
- TQString line;
- proc->readln( line, true ); //get ispell's response
-
-/* ispell man page: "Each sentence of text input is terminated with an
- additional blank line, indicating that ispell has completed processing
- the input line."
- <sanders>
- But there can be multiple lines returned in the case of an error,
- in this case we should consume all the output given otherwise spell checking
- can get out of sync.
- </sanders>
-*/
- TQString blank_line;
- while (proc->readln( blank_line, true ) != -1); // eat the blank line
- NOOUTPUT(checkWord2);
-
- bool mistake = ( parseOneResponse(line, word, sugg) == MISTAKE );
- if ( mistake && usedialog )
- {
- cwword = word;
- dialog( word, sugg, TQT_SLOT(checkWord3()) );
- d->checkNextTimer->start( 0, true );
- return;
- }
- else if( mistake )
- {
- emit misspelling( word, sugg, lastpos );
- }
-
- //emits a "corrected" signal _even_ if no change was made
- //so that the calling program knows when the check is complete
- emit corrected( word, word, 0L );
- d->checkNextTimer->start( 0, true );
-}
-
-void KSpell::checkNext()
-{
-// Queue words to prevent kspell from turning into a fork bomb
- d->checking = false;
- if (!d->unchecked.empty()) {
- BufferedWord buf = d->unchecked.front();
- d->unchecked.pop_front();
-
- if (buf.method == Method1)
- checkWord( buf.word, buf.useDialog );
- else
- checkWord( buf.word, buf.useDialog, buf.suggest );
- }
-}
-
-void KSpell::suggestWord( KProcIO * )
-{
- TQString word;
- TQString line;
- proc->readln( line, true ); //get ispell's response
-
-/* ispell man page: "Each sentence of text input is terminated with an
- additional blank line, indicating that ispell has completed processing
- the input line." */
- TQString blank_line;
- proc->readln( blank_line, true ); // eat the blank line
-
- NOOUTPUT(checkWord2);
-
- bool mistake = ( parseOneResponse(line, word, sugg) == MISTAKE );
- if ( mistake && usedialog )
- {
- cwword=word;
- dialog( word, sugg, TQT_SLOT(checkWord3()) );
- return;
- }
-}
-
-void KSpell::checkWord3()
-{
- disconnect( this, TQT_SIGNAL(dialog3()), this, TQT_SLOT(checkWord3()) );
-
- emit corrected( cwword, replacement(), 0L );
-}
-
-TQString KSpell::funnyWord( const TQString & word )
- // composes a guess from ispell to a readable word
- // e.g. "re+fry-y+ies" -> "refries"
-{
- TQString qs;
- unsigned int i=0;
-
- for( i=0; word [i]!='\0';i++ )
- {
- if (word [i]=='+')
- continue;
- if (word [i]=='-')
- {
- TQString shorty;
- unsigned int j;
- int k;
-
- for( j = i+1; word[j] != '\0' && word[j] != '+' && word[j] != '-'; j++ )
- shorty += word[j];
-
- i = j-1;
-
- if ( !( k = qs.findRev(shorty) ) || k != -1 )
- qs.remove( k, shorty.length() );
- else
- {
- qs += '-';
- qs += shorty; //it was a hyphen, not a '-' from ispell
- }
- }
- else
- qs += word[i];
- }
-
- return qs;
-}
-
-
-int KSpell::parseOneResponse( const TQString &buffer, TQString &word, TQStringList & sugg )
- // buffer is checked, word and sugg are filled in
- // returns
- // GOOD if word is fine
- // IGNORE if word is in ignorelist
- // REPLACE if word is in replacelist
- // MISTAKE if word is misspelled
-{
- word = "";
- posinline=0;
-
- sugg.clear();
-
- if ( buffer[0] == '*' || buffer[0] == '+' || buffer[0] == '-' )
- {
- return GOOD;
- }
-
- if ( buffer[0] == '&' || buffer[0] == '?' || buffer[0] == '#' )
- {
- int i,j;
-
-
- word = buffer.mid( 2, buffer.find( ' ', 3 ) -2 );
- //check() needs this
- orig=word;
-
- if( d->m_bIgnoreTitleCase && word == word.upper() )
- return IGNORE;
-
- if( d->m_bIgnoreUpperWords && word[0] == word[0].upper() )
- {
- TQString text = word[0] + word.right( word.length()-1 ).lower();
- if( text == word )
- return IGNORE;
- }
-
- /////// Ignore-list stuff //////////
- //We don't take advantage of ispell's ignore function because
- //we can't interrupt ispell's output (when checking a large
- //buffer) to add a word to _it's_ ignore-list.
- if ( ignorelist.findIndex( word.lower() ) != -1 )
- return IGNORE;
-
- //// Position in line ///
- TQString qs2;
-
- if ( buffer.find( ':' ) != -1 )
- qs2 = buffer.left( buffer.find(':') );
- else
- qs2 = buffer;
-
- posinline = qs2.right( qs2.length()-qs2.findRev(' ') ).toInt()-1;
-
- ///// Replace-list stuff ////
- TQStringList::Iterator it = replacelist.begin();
- for( ;it != replacelist.end(); ++it, ++it ) // Skip two entries at a time.
- {
- if ( word == *it ) // Word matches
- {
- ++it;
- word = *it; // Replace it with the next entry
- return REPLACE;
- }
- }
-
- /////// Suggestions //////
- if ( buffer[0] != '#' )
- {
- TQString qs = buffer.mid( buffer.find(':')+2, buffer.length() );
- qs += ',';
- sugg.clear();
- i = j = 0;
-
- while( (unsigned int)i < qs.length() )
- {
- TQString temp = qs.mid( i, (j=qs.find (',',i)) - i );
- sugg.append( funnyWord(temp) );
-
- i=j+2;
- }
- }
-
- if ( (sugg.count()==1) && (sugg.first() == word) )
- return GOOD;
-
- return MISTAKE;
- }
-
- if ( buffer.isEmpty() ) {
- kdDebug(750) << "Got an empty response: ignoring"<<endl;
- return GOOD;
- }
-
- kdError(750) << "HERE?: [" << buffer << "]" << endl;
- kdError(750) << "Please report this to zack@kde.org" << endl;
- kdError(750) << "Thank you!" << endl;
-
- emit done( false );
- emit done( KSpell::origbuffer );
- return MISTAKE;
-}
-
-bool KSpell::checkList (TQStringList *_wordlist, bool _usedialog)
- // prepare check of string list
-{
- wordlist=_wordlist;
- if ((totalpos=wordlist->count())==0)
- return false;
- wlIt = wordlist->begin();
- usedialog=_usedialog;
-
- // prepare the dialog
- setUpDialog();
-
- //set the dialog signal handler
- dialog3slot = TQT_SLOT (checkList4 ());
-
- proc->writeStdin (TQString("%")); // turn off terse mode & check one word at a time
-
- //lastpos now counts which *word number* we are at in checkListReplaceCurrent()
- lastpos = -1;
- checkList2();
-
- // when checked, KProcIO calls checkList3a
- OUTPUT(checkList3a);
-
- return true;
-}
-
-void KSpell::checkList2 ()
- // send one word from the list to KProcIO
- // invoked first time by checkList, later by checkListReplaceCurrent and checkList4
-{
- // send next word
- if (wlIt != wordlist->end())
- {
- kdDebug(750) << "KS::cklist2 " << lastpos << ": " << *wlIt << endl;
-
- d->endOfResponse = false;
- bool put;
- lastpos++; offset=0;
- put = cleanFputsWord (*wlIt);
- ++wlIt;
-
- // when cleanFPutsWord failed (e.g. on empty word)
- // try next word; may be this is not good for other
- // problems, because this will make read the list up to the end
- if (!put) {
- checkList2();
- }
- }
- else
- // end of word list
- {
- NOOUTPUT(checkList3a);
- ksdlg->hide();
- emit done(true);
- }
-}
-
-void KSpell::checkList3a (KProcIO *)
- // invoked by KProcIO, when data from ispell are read
-{
- //kdDebug(750) << "start of checkList3a" << endl;
-
- // don't read more data, when dialog is waiting
- // for user interaction
- if ( dlgon ) {
- //kdDebug(750) << "dlgon: don't read more data" << endl;
- return;
- }
-
- int e, tempe;
-
- TQString word;
- TQString line;
-
- do
- {
- tempe=proc->readln( line, true ); //get ispell's response
-
- //kdDebug(750) << "checkList3a: read bytes [" << tempe << "]" << endl;
-
-
- if ( tempe == 0 ) {
- d->endOfResponse = true;
- //kdDebug(750) << "checkList3a: end of resp" << endl;
- } else if ( tempe>0 ) {
- if ( (e=parseOneResponse( line, word, sugg ) ) == MISTAKE ||
- e==REPLACE )
- {
- dlgresult=-1;
-
- if ( e == REPLACE )
- {
- TQString old = *(--wlIt); ++wlIt;
- dlgreplacement = word;
- checkListReplaceCurrent();
- // inform application
- emit corrected( old, *(--wlIt), lastpos ); ++wlIt;
- }
- else if( usedialog )
- {
- cwword = word;
- dlgon = true;
- // show the dialog
- dialog( word, sugg, TQT_SLOT(checkList4()) );
- return;
- }
- else
- {
- d->m_bNoMisspellingsEncountered = false;
- emit misspelling( word, sugg, lastpos );
- }
- }
-
- }
- emitProgress (); //maybe
-
- // stop when empty line or no more data
- } while (tempe > 0);
-
- //kdDebug(750) << "checkList3a: exit loop with [" << tempe << "]" << endl;
-
- // if we got an empty line, t.e. end of ispell/aspell response
- // and the dialog isn't waiting for user interaction, send next word
- if (d->endOfResponse && !dlgon) {
- //kdDebug(750) << "checkList3a: send next word" << endl;
- checkList2();
- }
-}
-
-void KSpell::checkListReplaceCurrent()
-{
-
- // go back to misspelled word
- wlIt--;
-
- TQString s = *wlIt;
- s.replace(posinline+offset,orig.length(),replacement());
- offset += replacement().length()-orig.length();
- wordlist->insert (wlIt, s);
- wlIt = wordlist->remove (wlIt);
- // wlIt now points to the word after the repalced one
-
-}
-
-void KSpell::checkList4 ()
- // evaluate dialog return, when a button was pressed there
-{
- dlgon=false;
- TQString old;
-
- disconnect (this, TQT_SIGNAL (dialog3()), this, TQT_SLOT (checkList4()));
-
- //others should have been processed by dialog() already
- switch (dlgresult)
- {
- case KS_REPLACE:
- case KS_REPLACEALL:
- kdDebug(750) << "KS: cklist4: lastpos: " << lastpos << endl;
- old = *(--wlIt);
- ++wlIt;
- // replace word
- checkListReplaceCurrent();
- emit corrected( old, *(--wlIt), lastpos );
- ++wlIt;
- break;
- case KS_CANCEL:
- ksdlg->hide();
- emit done( false );
- return;
- case KS_STOP:
- ksdlg->hide();
- emit done( true );
- return;
- case KS_CONFIG:
- ksdlg->hide();
- emit done( false );
- //check( origbuffer.mid( lastpos ), true );
- //trystart = 0;
- //proc->disconnect();
- //proc->kill();
- //delete proc;
- //proc = new KProcIO( codec );
- //startIspell();
- return;
- };
-
- // read more if there is more, otherwise send next word
- if (!d->endOfResponse) {
- //kdDebug(750) << "checkList4: read more from response" << endl;
- checkList3a(NULL);
- }
-}
-
-bool KSpell::check( const TQString &_buffer, bool _usedialog )
-{
- TQString qs;
-
- usedialog = _usedialog;
- setUpDialog();
- //set the dialog signal handler
- dialog3slot = TQT_SLOT(check3());
-
- kdDebug(750) << "KS: check" << endl;
- origbuffer = _buffer;
- if ( ( totalpos = origbuffer.length() ) == 0 )
- {
- emit done( origbuffer );
- return false;
- }
-
-
- // Torben: I corrected the \n\n problem directly in the
- // origbuffer since I got errors otherwise
- if ( !origbuffer.endsWith("\n\n" ) )
- {
- if (origbuffer.at(origbuffer.length()-1)!='\n')
- {
- origbuffer+='\n';
- origbuffer+='\n'; //shouldn't these be removed at some point?
- }
- else
- origbuffer+='\n';
- }
-
- newbuffer = origbuffer;
-
- // KProcIO calls check2 when read from ispell
- OUTPUT( check2 );
- proc->writeStdin(TQString("!"));
-
- //lastpos is a position in newbuffer (it has offset in it)
- offset = lastlastline = lastpos = lastline = 0;
-
- emitProgress();
-
- // send first buffer line
- int i = origbuffer.find( '\n', 0 ) + 1;
- qs = origbuffer.mid( 0, i );
- cleanFputs( qs, false );
-
- lastline=i; //the character position, not a line number
-
- if ( usedialog )
- {
- emitProgress();
- }
- else
- ksdlg->hide();
-
- return true;
-}
-
-
-void KSpell::check2( KProcIO * )
- // invoked by KProcIO when read from ispell
-{
- int e, tempe;
- TQString word;
- TQString line;
- static bool recursive = false;
- if (recursive &&
- !ksdlg )
- {
- return;
- }
- recursive = true;
-
- do
- {
- tempe = proc->readln( line, false ); //get ispell's response
- //kdDebug(750) << "KSpell::check2 (" << tempe << "b)" << endl;
-
- if ( tempe>0 )
- {
- if ( ( e=parseOneResponse (line, word, sugg) )==MISTAKE ||
- e==REPLACE)
- {
- dlgresult=-1;
-
- // for multibyte encoding posinline needs correction
- if ((ksconfig->encoding() == KS_E_UTF8) && !d->aspellV6) {
- // kdDebug(750) << "line: " << origbuffer.mid(lastlastline,
- // lastline-lastlastline) << endl;
- // kdDebug(750) << "posinline uncorr: " << posinline << endl;
-
- // convert line to UTF-8, cut at pos, convert back to UCS-2
- // and get string length
- posinline = (TQString::fromUtf8(
- origbuffer.mid(lastlastline,lastline-lastlastline).utf8(),
- posinline)).length();
- // kdDebug(750) << "posinline corr: " << posinline << endl;
- }
-
- lastpos = posinline+lastlastline+offset;
-
- //orig is set by parseOneResponse()
-
- if (e==REPLACE)
- {
- dlgreplacement=word;
- emit corrected( orig, replacement(), lastpos );
- offset += replacement().length()-orig.length();
- newbuffer.replace( lastpos, orig.length(), word );
- }
- else //MISTAKE
- {
- cwword = word;
- //kdDebug(750) << "(Before dialog) word=[" << word << "] cwword =[" << cwword << "]\n" << endl;
- if ( usedialog ) {
- // show the word in the dialog
- dialog( word, sugg, TQT_SLOT(check3()) );
- } else {
- // No dialog, just emit misspelling and continue
- d->m_bNoMisspellingsEncountered = false;
- emit misspelling( word, sugg, lastpos );
- dlgresult = KS_IGNORE;
- check3();
- }
- recursive = false;
- return;
- }
- }
-
- }
-
- emitProgress(); //maybe
-
- } while( tempe>0 );
-
- if ( tempe == -1 ) { //we were called, but no data seems to be ready...
- // Make sure we don't get called directly again and make sure we do get
- // called when new data arrives.
- NOOUTPUT( check2 );
- proc->enableReadSignals(true);
- OUTPUT( check2 );
- recursive = false;
- return;
- }
-
- proc->ackRead();
-
- //If there is more to check, then send another line to ISpell.
- if ( (unsigned int)lastline < origbuffer.length() )
- {
- int i;
- TQString qs;
-
- //kdDebug(750) << "[EOL](" << tempe << ")[" << temp << "]" << endl;
-
- lastpos = (lastlastline=lastline) + offset; //do we really want this?
- i = origbuffer.find('\n', lastline) + 1;
- qs = origbuffer.mid( lastline, i-lastline );
- cleanFputs( qs, false );
- lastline = i;
- recursive = false;
- return;
- }
- else
- //This is the end of it all
- {
- ksdlg->hide();
- // kdDebug(750) << "check2() done" << endl;
- newbuffer.truncate( newbuffer.length()-2 );
- emitProgress();
- emit done( newbuffer );
- }
- recursive = false;
-}
-
-void KSpell::check3 ()
- // evaluates the return value of the dialog
-{
- disconnect (this, TQT_SIGNAL (dialog3()), this, TQT_SLOT (check3()));
- kdDebug(750) << "check3 [" << cwword << "] [" << replacement() << "] " << dlgresult << endl;
-
- //others should have been processed by dialog() already
- switch (dlgresult)
- {
- case KS_REPLACE:
- case KS_REPLACEALL:
- offset+=replacement().length()-cwword.length();
- newbuffer.replace (lastpos, cwword.length(),
- replacement());
- emit corrected (dlgorigword, replacement(), lastpos);
- break;
- case KS_CANCEL:
- // kdDebug(750) << "canceled\n" << endl;
- ksdlg->hide();
- emit done( origbuffer );
- return;
- case KS_CONFIG:
- ksdlg->hide();
- emit done( origbuffer );
- KMessageBox::information( 0, i18n("You have to restart the dialog for changes to take effect") );
- //check( origbuffer.mid( lastpos ), true );
- return;
- case KS_STOP:
- ksdlg->hide();
- //buffer=newbuffer);
- emitProgress();
- emit done (newbuffer);
- return;
- };
-
- proc->ackRead();
-}
-
-void
-KSpell::slotStopCancel (int result)
-{
- if (dialogwillprocess)
- return;
-
- kdDebug(750) << "KSpell::slotStopCancel [" << result << "]" << endl;
-
- if (result==KS_STOP || result==KS_CANCEL)
- if (!dialog3slot.isEmpty())
- {
- dlgresult=result;
- connect (this, TQT_SIGNAL (dialog3()), this, dialog3slot.ascii());
- emit dialog3();
- }
-}
-
-
-void KSpell::dialog( const TQString & word, TQStringList & sugg, const char *_slot )
-{
- dlgorigword = word;
-
- dialog3slot = _slot;
- dialogwillprocess = true;
- connect( ksdlg, TQT_SIGNAL(command(int)), this, TQT_SLOT(dialog2(int)) );
- TQString tmpBuf = newbuffer;
- kdDebug(750)<<" position = "<<lastpos<<endl;
-
- // extract a context string, replace all characters which might confuse
- // the RichText display and highlight the possibly wrong word
- TQString marker( "_MARKER_" );
- tmpBuf.replace( lastpos, word.length(), marker );
- TQString context = tmpBuf.mid(QMAX(lastpos-18,0), 2*18+marker.length());
- context.replace( '\n',TQString::fromLatin1(" "));
- context.replace( '<', TQString::fromLatin1("&lt;") );
- context.replace( '>', TQString::fromLatin1("&gt;") );
- context.replace( marker, TQString::fromLatin1("<b>%1</b>").arg( word ) );
- context = "<qt>" + context + "</qt>";
-
- ksdlg->init( word, &sugg, context );
- d->m_bNoMisspellingsEncountered = false;
- emit misspelling( word, sugg, lastpos );
-
- emitProgress();
- ksdlg->show();
-}
-
-void KSpell::dialog2( int result )
-{
- TQString qs;
-
- disconnect( ksdlg, TQT_SIGNAL(command(int)), this, TQT_SLOT(dialog2(int)) );
- dialogwillprocess = false;
- dlgresult = result;
- ksdlg->standby();
-
- dlgreplacement = ksdlg->replacement();
-
- //process result here
- switch ( dlgresult )
- {
- case KS_IGNORE:
- emit ignoreword( dlgorigword );
- break;
- case KS_IGNOREALL:
- // would be better to lower case only words with beginning cap
- ignorelist.prepend( dlgorigword.lower() );
- emit ignoreall( dlgorigword );
- break;
- case KS_ADD:
- addPersonal( dlgorigword );
- personaldict = true;
- emit addword( dlgorigword );
- // adding to pesonal dict takes effect at the next line, not the current
- ignorelist.prepend( dlgorigword.lower() );
- break;
- case KS_REPLACEALL:
- {
- replacelist.append( dlgorigword );
- TQString _replacement = replacement();
- replacelist.append( _replacement );
- emit replaceall( dlgorigword , _replacement );
- }
- break;
- case KS_SUGGEST:
- checkWord( ksdlg->replacement(), false, true );
- return;
- break;
- }
-
- connect( this, TQT_SIGNAL(dialog3()), this, dialog3slot.ascii() );
- emit dialog3();
-}
-
-
-KSpell::~KSpell()
-{
- delete proc;
- delete ksconfig;
- delete ksdlg;
- delete d->checkNextTimer;
- delete d;
-}
-
-
-KSpellConfig KSpell::ksConfig() const
-{
- ksconfig->setIgnoreList(ignorelist);
- ksconfig->setReplaceAllList(replacelist);
- return *ksconfig;
-}
-
-void KSpell::cleanUp()
-{
- if ( m_status == Cleaning )
- return; // Ignore
-
- if ( m_status == Running )
- {
- if ( personaldict )
- writePersonalDictionary();
- m_status = Cleaning;
- }
- proc->closeStdin();
-}
-
-void KSpell::ispellExit( TDEProcess* )
-{
- kdDebug() << "KSpell::ispellExit() " << m_status << endl;
-
- if ( (m_status == Starting) && (trystart < maxtrystart) )
- {
- trystart++;
- startIspell();
- return;
- }
-
- if ( m_status == Starting )
- m_status = Error;
- else if (m_status == Cleaning)
- m_status = d->m_bNoMisspellingsEncountered ? FinishedNoMisspellingsEncountered : Finished;
- else if ( m_status == Running )
- m_status = Crashed;
- else // Error, Finished, Crashed
- return; // Dead already
-
- kdDebug(750) << "Death" << endl;
- TQTimer::singleShot( 0, this, TQT_SLOT(emitDeath()) );
-}
-
-// This is always called from the event loop to make
-// sure that the receiver can safely delete the
-// KSpell object.
-void KSpell::emitDeath()
-{
- bool deleteMe = autoDelete; // Can't access object after next call!
- emit death();
- if ( deleteMe )
- deleteLater();
-}
-
-void KSpell::setProgressResolution (unsigned int res)
-{
- progres=res;
-}
-
-void KSpell::emitProgress ()
-{
- uint nextprog = (uint) (100.*lastpos/(double)totalpos);
-
- if ( nextprog >= curprog )
- {
- curprog = nextprog;
- emit progress( curprog );
- }
-}
-
-void KSpell::moveDlg( int x, int y )
-{
- TQPoint pt( x,y ), pt2;
- pt2 = parent->mapToGlobal( pt );
- ksdlg->move( pt2.x(),pt2.y() );
-}
-
-void KSpell::setIgnoreUpperWords(bool _ignore)
-{
- d->m_bIgnoreUpperWords=_ignore;
-}
-
-void KSpell::setIgnoreTitleCase(bool _ignore)
-{
- d->m_bIgnoreTitleCase=_ignore;
-}
-// --------------------------------------------------
-// Stuff for modal (blocking) spell checking
-//
-// Written by Torben Weis <weis@kde.org>. So please
-// send bug reports regarding the modal stuff to me.
-// --------------------------------------------------
-
-int
-KSpell::modalCheck( TQString& text )
-{
- return modalCheck( text,0 );
-}
-
-int
-KSpell::modalCheck( TQString& text, KSpellConfig* _kcs )
-{
- modalreturn = 0;
- modaltext = text;
-
- KSpell* spell = new KSpell( 0L, i18n("Spell Checker"), 0 ,
- 0, _kcs, true, true );
-
- while (spell->status()!=Finished)
- kapp->processEvents();
-
- text = modaltext;
-
- delete spell;
- return modalreturn;
-}
-
-void KSpell::slotSpellCheckerCorrected( const TQString & oldText, const TQString & newText, unsigned int pos )
-{
- modaltext=modaltext.replace(pos,oldText.length(),newText);
-}
-
-
-void KSpell::slotModalReady()
-{
- //kdDebug() << tqApp->loopLevel() << endl;
- //kdDebug(750) << "MODAL READY------------------" << endl;
-
- Q_ASSERT( m_status == Running );
- connect( this, TQT_SIGNAL( done( const TQString & ) ),
- this, TQT_SLOT( slotModalDone( const TQString & ) ) );
- TQObject::connect( this, TQT_SIGNAL( corrected( const TQString&, const TQString&, unsigned int ) ),
- this, TQT_SLOT( slotSpellCheckerCorrected( const TQString&, const TQString &, unsigned int ) ) );
- TQObject::connect( this, TQT_SIGNAL( death() ),
- this, TQT_SLOT( slotModalSpellCheckerFinished( ) ) );
- check( modaltext );
-}
-
-void KSpell::slotModalDone( const TQString &/*_buffer*/ )
-{
- //kdDebug(750) << "MODAL DONE " << _buffer << endl;
- //modaltext = _buffer;
- cleanUp();
-
- //kdDebug() << "ABOUT TO EXIT LOOP" << endl;
- //tqApp->exit_loop();
-
- //modalWidgetHack->close(true);
- slotModalSpellCheckerFinished();
-}
-
-void KSpell::slotModalSpellCheckerFinished( )
-{
- modalreturn=(int)this->status();
-}
-
-void KSpell::initialize( TQWidget *_parent, const TQString &_caption,
- TQObject *obj, const char *slot, KSpellConfig *_ksc,
- bool _progressbar, bool _modal, SpellerType type )
-{
- d = new KSpellPrivate;
-
- d->m_bIgnoreUpperWords =false;
- d->m_bIgnoreTitleCase =false;
- d->m_bNoMisspellingsEncountered = true;
- d->type = type;
- d->checking = false;
- d->aspellV6 = false;
- d->checkNextTimer = new TQTimer( this );
- connect( d->checkNextTimer, TQT_SIGNAL( timeout() ),
- this, TQT_SLOT( checkNext() ));
- autoDelete = false;
- modaldlg = _modal;
- progressbar = _progressbar;
-
- proc = 0;
- ksconfig = 0;
- ksdlg = 0;
- lastpos = 0;
-
- //won't be using the dialog in ksconfig, just the option values
- if ( _ksc )
- ksconfig = new KSpellConfig( *_ksc );
- else
- ksconfig = new KSpellConfig;
-
- codec = 0;
- switch ( ksconfig->encoding() )
- {
- case KS_E_LATIN1:
- codec = TQTextCodec::codecForName("ISO 8859-1");
- break;
- case KS_E_LATIN2:
- codec = TQTextCodec::codecForName("ISO 8859-2");
- break;
- case KS_E_LATIN3:
- codec = TQTextCodec::codecForName("ISO 8859-3");
- break;
- case KS_E_LATIN4:
- codec = TQTextCodec::codecForName("ISO 8859-4");
- break;
- case KS_E_LATIN5:
- codec = TQTextCodec::codecForName("ISO 8859-5");
- break;
- case KS_E_LATIN7:
- codec = TQTextCodec::codecForName("ISO 8859-7");
- break;
- case KS_E_LATIN8:
- codec = TQTextCodec::codecForName("ISO 8859-8-i");
- break;
- case KS_E_LATIN9:
- codec = TQTextCodec::codecForName("ISO 8859-9");
- break;
- case KS_E_LATIN13:
- codec = TQTextCodec::codecForName("ISO 8859-13");
- break;
- case KS_E_LATIN15:
- codec = TQTextCodec::codecForName("ISO 8859-15");
- break;
- case KS_E_UTF8:
- codec = TQTextCodec::codecForName("UTF-8");
- break;
- case KS_E_KOI8R:
- codec = TQTextCodec::codecForName("KOI8-R");
- break;
- case KS_E_KOI8U:
- codec = TQTextCodec::codecForName("KOI8-U");
- break;
- case KS_E_CP1251:
- codec = TQTextCodec::codecForName("CP1251");
- break;
- case KS_E_CP1255:
- codec = TQTextCodec::codecForName("CP1255");
- break;
- default:
- break;
- }
-
- kdDebug(750) << __FILE__ << ":" << __LINE__ << " Codec = " << (codec ? codec->name() : "<default>") << endl;
-
- // copy ignore list from ksconfig
- ignorelist += ksconfig->ignoreList();
-
- replacelist += ksconfig->replaceAllList();
- texmode=dlgon=false;
- m_status = Starting;
- dialogsetup = false;
- progres=10;
- curprog=0;
-
- dialogwillprocess = false;
- dialog3slot = TQString::null;
-
- personaldict = false;
- dlgresult = -1;
-
- caption = _caption;
-
- parent = _parent;
-
- trystart = 0;
- maxtrystart = 2;
-
- if ( obj && slot )
- // caller wants to know when kspell is ready
- connect( this, TQT_SIGNAL(ready(KSpell *)), obj, slot);
- else
- // Hack for modal spell checking
- connect( this, TQT_SIGNAL(ready(KSpell *)), this, TQT_SLOT(slotModalReady()) );
-
- proc = new KProcIO( codec );
-
- startIspell();
-}
-
-TQString KSpell::modaltext;
-int KSpell::modalreturn = 0;
-TQWidget* KSpell::modalWidgetHack = 0;
-
-#include "kspell.moc"
-