diff options
Diffstat (limited to 'tdeui/kspell.cpp')
-rw-r--r-- | tdeui/kspell.cpp | 1577 |
1 files changed, 0 insertions, 1577 deletions
diff --git a/tdeui/kspell.cpp b/tdeui/kspell.cpp deleted file mode 100644 index 7a17ad607..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(KProcess *, char *, int)), - this, TQT_SLOT(ispellErrors(KProcess *, char *, int)) ); - - connect( proc, TQT_SIGNAL(processExited(KProcess *)), - this, TQT_SLOT(ispellExit (KProcess *)) ); - - OUTPUT(KSpell2); - } - - if ( !proc->start() ) - { - m_status = Error; - TQTimer::singleShot( 0, this, TQT_SLOT(emitDeath())); - } -} - -void -KSpell::ispellErrors( KProcess *, 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("<") ); - context.replace( '>', TQString::fromLatin1(">") ); - 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( KProcess* ) -{ - 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" - |