Conflicts resolved. Haven't tested the Qt bits, if somebody wants to ... Anyway, if you want to consider this JMarc, here's the patch.
regards john Index: status.13x =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/Attic/status.13x,v retrieving revision 1.1.2.24 diff -u -r1.1.2.24 status.13x --- status.13x 17 Feb 2003 18:39:06 -0000 1.1.2.24 +++ status.13x 17 Feb 2003 19:05:48 -0000 @@ -78,3 +78,15 @@ - fix strerror() build problem with some gcc/glibc versions [bug #874] - revert is now disabled for an unchanged or unsaved document [bug #783] + +- The spell-checking system has been over-hauled, including the following + changes : + + o start spell-checking immediately on pressing F7 + o xform's broken start/stop button removed + o better spell progress feedback + o long hang on ispell error changed + o infinite hang on ispell error fixed + o reports ispell errors back to the user + o the personal dictionaries are always correctly written out + o "Accept" button became "Ignore All" for clarity Index: src/ChangeLog =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/ChangeLog,v retrieving revision 1.1021.2.4 diff -u -r1.1021.2.4 ChangeLog --- src/ChangeLog 17 Feb 2003 18:39:06 -0000 1.1021.2.4 +++ src/ChangeLog 17 Feb 2003 19:06:00 -0000 @@ -1,5 +1,13 @@ 2003-02-17 John Levon <[EMAIL PROTECTED]> + * SpellBase.h: + * ispell.h: + * ispell.C: + * pspell.h: + * pspell.C: reworking + +2003-02-17 John Levon <[EMAIL PROTECTED]> + * lyxfunc.C: fix bug 738 - revert behaves sensibly 2003-02-14 Jean-Marc Lasgouttes <[EMAIL PROTECTED]> Index: src/SpellBase.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/SpellBase.h,v retrieving revision 1.4 diff -u -r1.4 SpellBase.h --- src/SpellBase.h 1 Dec 2002 22:59:17 -0000 1.4 +++ src/SpellBase.h 17 Feb 2003 19:06:00 -0000 @@ -36,14 +36,8 @@ /// return true if the spellchecker instance still exists virtual bool alive() = 0; - /// clean up on messy exit - virtual void cleanUp() = 0; - /// check the given word of the given lang code and return the result virtual enum Result check(WordLangTuple const &) = 0; - - /// finish this spellchecker instance - virtual void close() = 0; /// insert the given word into the personal dictionary virtual void insert(WordLangTuple const &) = 0; Index: src/ispell.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/ispell.C,v retrieving revision 1.5 diff -u -r1.5 ispell.C --- src/ispell.C 27 Nov 2002 10:30:07 -0000 1.5 +++ src/ispell.C 17 Feb 2003 19:06:00 -0000 @@ -13,35 +13,6 @@ #pragma implementation #endif -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> -#include <fcntl.h> -#include <cstdio> - -// FIXME: do we need any of this horrible gook ? -#if TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <ctime> -#else -# if HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <ctime> -# endif -#endif - -#ifdef HAVE_SYS_SELECT_H -# ifdef HAVE_STRINGS_H - // <strings.h> is needed at least on AIX because FD_ZERO uses bzero(). - // BUT we cannot include both string.h and strings.h on Irix 6.5 :( -# ifdef _AIX -# include <strings.h> -# endif -# endif -#include <sys/select.h> -#endif - #include "LString.h" #include "lyxrc.h" #include "language.h" @@ -49,10 +20,13 @@ #include "encoding.h" #include "ispell.h" #include "WordLangTuple.h" +#include "gettext.h" #include "support/forkedcall.h" #include "support/lstrings.h" +#include <sys/select.h> + #ifndef CXX_GLOBAL_CSTD using std::strcpy; using std::strlen; @@ -61,18 +35,16 @@ #endif using std::endl; +using std::max; namespace { -/// pid for the `ispell' process. -pid_t isp_pid = -1; - class LaunchIspell : public ForkedProcess { public: /// LaunchIspell(BufferParams const & p, string const & l, - int * in, int * out) - : params(p), lang(l), pipein(in), pipeout(out) {} + int * in, int * out, int * err) + : params(p), lang(l), pipein(in), pipeout(out), pipeerr(err) {} /// virtual ForkedProcess * clone() const { return new LaunchIspell(*this); @@ -88,6 +60,7 @@ string const & lang; int * const pipein; int * const pipeout; + int * const pipeerr; }; @@ -100,7 +73,7 @@ int LaunchIspell::generateChild() { - isp_pid = fork(); + pid_t isp_pid = fork(); if (isp_pid != 0) { // failed (-1) or parent process (>0) @@ -110,10 +83,13 @@ // child process dup2(pipein[0], STDIN_FILENO); dup2(pipeout[1], STDOUT_FILENO); - ::close(pipein[0]); - ::close(pipein[1]); - ::close(pipeout[0]); - ::close(pipeout[1]); + dup2(pipeerr[1], STDERR_FILENO); + close(pipein[0]); + close(pipein[1]); + close(pipeout[0]); + close(pipeout[1]); + close(pipeerr[0]); + close(pipeerr[1]); char * argv[14]; int argc = 0; @@ -204,122 +180,161 @@ ISpell::ISpell(BufferParams const & params, string const & lang) - : str(0) + : in(0), out(0), inerr(0), str(0) { - static char o_buf[BUFSIZ]; // jc: it could be smaller - int pipein[2]; - int pipeout[2]; + lyxerr[Debug::GUI] << "Created ispell" << endl; + + // static due to the setvbuf. Ugly. + static char o_buf[BUFSIZ]; + + // We need to throw an exception not do this + pipein[0] = pipein[1] = pipeout[0] = pipeout[1] + = pipeerr[0] = pipeerr[1] = -1; - isp_pid = -1; + // This is what happens when goto gets banned. - if (pipe(pipein) == -1 || pipe(pipeout) == -1) { - lyxerr << "LyX: Can't create pipe for spellchecker!" << endl; - setError(); + if (pipe(pipein) == -1) { + error_ = _("Can't create pipe for spellchecker."); + return; + } + + if (pipe(pipeout) == -1) { + close(pipein[0]); + close(pipein[1]); + error_ = _("Can't create pipe for spellchecker."); + return; + } + + if (pipe(pipeerr) == -1) { + close(pipein[0]); + close(pipein[1]); + close(pipeout[0]); + close(pipeout[1]); + error_ = _("Can't create pipe for spellchecker."); return; } if ((out = fdopen(pipein[1], "w")) == 0) { - lyxerr << "LyX: Can't create stream for pipe for spellchecker!" - << endl; - setError(); + error_ = _("Can't open pipe for spellchecker."); return; } if ((in = fdopen(pipeout[0], "r")) == 0) { - lyxerr <<"LyX: Can't create stream for pipe for spellchecker!" - << endl; - setError(); + error_ = _("Can't open pipe for spellchecker."); return; } - setvbuf(out, o_buf, _IOLBF, BUFSIZ); + if ((inerr = fdopen(pipeerr[0], "r")) == 0) { + error_ = _("Can't open pipe for spellchecker."); + return; + } - isp_fd = pipeout[0]; + setvbuf(out, o_buf, _IOLBF, BUFSIZ); - LaunchIspell childprocess(params, lang, pipein, pipeout); - isp_pid = childprocess.start(); - if (isp_pid == -1) { - lyxerr << "LyX: Can't create child process for spellchecker!" - << endl; - setError(); + LaunchIspell * li = new LaunchIspell(params, lang, pipein, pipeout, pipeerr); + child_.reset(li); + if (li->start() == -1) { + error_ = _("Could not create an ispell process.\nYou may not have " + " the right languages installed."); + child_.reset(0); return; } - setError(); /* Parent process: Read ispells identification message */ - // Hmm...what are we using this id msg for? Nothing? (Lgb) - // Actually I used it to tell if it's truly Ispell or if it's - // aspell -- ([EMAIL PROTECTED]) - // But no code actually used the results for anything useful - // so I removed it again. Perhaps we can remove this code too. - // - jbl - char buf[2048]; - fd_set infds; - struct timeval tv; - int retval = 0; - FD_ZERO(&infds); - FD_SET(pipeout[0], &infds); - tv.tv_sec = 15; // fifteen second timeout. Probably too much, - // but it can't really hurt. - tv.tv_usec = 0; - // Configure provides us with macros which are supposed to do - // the right typecast. - retval = select(SELECT_TYPE_ARG1 (pipeout[0]+1), - SELECT_TYPE_ARG234 (&infds), - 0, - 0, - SELECT_TYPE_ARG5 (&tv)); + bool err_read; + bool error = select(err_read); - if (retval > 0) { - // Ok, do the reading. We don't have to FD_ISSET since - // there is only one fd in infds. - fgets(buf, 2048, in); - - fputs("!\n", out); // Set terse mode (silently accept correct words) - - } else if (retval == 0) { - // timeout. Give nice message to user. - lyxerr << "Ispell read timed out, what now?" << endl; - // This probably works but could need some thought - isp_pid = -1; - ::close(pipeout[0]); - ::close(pipeout[1]); - ::close(pipein[0]); - ::close(pipein[1]); - isp_fd = -1; + if (!error) { + if (!err_read) { + // Set terse mode (silently accept correct words) + fputs("!\n", out); + return; + } + + /* must have read something from stderr */ + error_ = buf; } else { - // Select returned error - lyxerr << "Select on ispell returned error, what now?" << endl; + // select returned error + error_ = _("The spell process returned an error.\nPerhaps " + "it has been configured wrongly ?"); } + + close(pipein[0]); + close(pipein[1]); + close(pipeout[0]); + close(pipeout[1]); + close(pipeerr[0]); + close(pipeerr[1]); + child_->kill(); + child_.reset(0); } ISpell::~ISpell() { - delete[] str; + lyxerr[Debug::GUI] << "Killing ispell" << endl; + + if (in) + fclose(in); + + if (inerr) + fclose(inerr); + + if (out) { + fputs("#\n", out); // Save personal dictionary + + fflush(out); + fclose(out); + } + + close(pipein[0]); + close(pipein[1]); + close(pipeout[0]); + close(pipeout[1]); + close(pipeerr[0]); + close(pipeerr[1]); + delete [] str; } -void ISpell::setError() +bool ISpell::select(bool & err_read) { - if (isp_pid == -1) { - error_ = - "\n\n" - "The spellcheck-process has died for some reason.\n" - "*One* possible reason could be that you do not have\n" - "a dictionary file for the language of this document\n" - "installed.\n" - "Check your spellchecker or set another dictionary\n" - "in the Spellchecker Options menu.\n\n"; - } else { - error_ = 0; + fd_set infds; + struct timeval tv; + int retval = 0; + FD_ZERO(&infds); + FD_SET(pipeout[0], &infds); + FD_SET(pipeerr[0], &infds); + tv.tv_sec = 2; + tv.tv_usec = 0; + + retval = ::select(SELECT_TYPE_ARG1 (max(pipeout[0], pipeerr[0]) + 1), + SELECT_TYPE_ARG234 (&infds), + 0, + 0, + SELECT_TYPE_ARG5 (&tv)); + + // error + if (retval <= 0) + return true; + + if (FD_ISSET(pipeerr[0], &infds)) { + fgets(buf, BUFSIZ, inerr); + err_read = true; + return false; } + + fgets(buf, BUFSIZ, in); + err_read = false; + return false; } string const ISpell::nextMiss() { + // Well, somebody is a sick fuck. + if (str == 0 || *(e+1) == '\0') return ""; char * b = e + 2; @@ -333,13 +348,7 @@ bool ISpell::alive() { - return isp_pid != -1; -} - - -void ISpell::cleanUp() -{ - ::fclose(out); + return child_.get() && child_->running(); } @@ -352,8 +361,18 @@ ::fputs(word.word().c_str(), out); ::fputc('\n', out); - char buf[1024]; - ::fgets(buf, 1024, in); + bool err_read; + bool error = select(err_read); + + if (error) { + error_ = _("Could not communicate with the spell-checker program"); + return UNKNOWN; + } + + if (err_read) { + error_ = buf; + return UNKNOWN; + } // I think we have to check if ispell is still alive here because // the signal-handler could have disabled blocking on the fd @@ -400,20 +419,6 @@ } -void ISpell::close() -{ - // Note: If you decide to optimize this out when it is not - // needed please note that when Aspell is used this command - // is also needed to save the replacement dictionary. - // -- Kevin Atkinson ([EMAIL PROTECTED]) - - fputs("#\n", out); // Save personal dictionary - - fflush(out); - fclose(out); -} - - void ISpell::insert(WordLangTuple const & word) { ::fputc('*', out); // Insert word in personal dictionary @@ -432,7 +437,5 @@ string const ISpell::error() { - if (error_) - return error_; - return ""; + return error_; } Index: src/ispell.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/ispell.h,v retrieving revision 1.5 diff -u -r1.5 ispell.h --- src/ispell.h 1 Dec 2002 22:59:17 -0000 1.5 +++ src/ispell.h 17 Feb 2003 19:06:00 -0000 @@ -10,11 +10,14 @@ #ifndef SP_ISPELL_H #define SP_ISPELL_H -#include <cstdio> - #include "SpellBase.h" +#include <boost/scoped_ptr.hpp> + +#include <cstdio> + class BufferParams; +class ForkedProcess; /// i/a spell process-based spellchecker class ISpell : public SpellBase { @@ -26,15 +29,9 @@ /// return true if the spellchecker instance still exists virtual bool alive(); - /// clean up on messy exit - virtual void cleanUp(); - /// check the given word and return the result virtual enum Result check(WordLangTuple const & word); - /// finish this spellchecker instance - virtual void close(); - /// insert the given word into the personal dictionary virtual void insert(WordLangTuple const & word); @@ -48,17 +45,29 @@ virtual string const error(); private: - /// - void setError(); + /// read some data. Returns true on an error. Sets err_read + /// to true if the data was from stderr. + bool select(bool & err_read); /// instream to communicate with ispell FILE * in; /// outstream to communicate with ispell FILE * out; + /// errstream for ispell + FILE * inerr; + + /// pipe fds + int pipein[2]; + int pipeout[2]; + int pipeerr[2]; + + /// buffer for reading + char buf[BUFSIZ]; + /// spell error - char const * error_; - /// the fd of the outgoing pipe - int isp_fd; + string error_; + + boost::scoped_ptr<ForkedProcess> child_; // vileness below ... please FIXME /// str ??? Index: src/pspell.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/pspell.C,v retrieving revision 1.7 diff -u -r1.7 pspell.C --- src/pspell.C 1 Dec 2002 22:59:17 -0000 1.7 +++ src/pspell.C 17 Feb 2003 19:06:00 -0000 @@ -16,6 +16,7 @@ #ifdef USE_PSPELL #include "support/LAssert.h" +#include "debug.h" #define USE_ORIGINAL_MANAGER_FUNCS 1 // new aspell pspell missing extern "C" @@ -26,38 +27,39 @@ #include "pspell.h" #include "WordLangTuple.h" +using std::endl; + PSpell::PSpell(BufferParams const &, string const & lang) : els(0), spell_error_object(0) { addManager(lang); + lyxerr[Debug::GUI] << "created pspell" << endl; } PSpell::~PSpell() { - cleanUp(); - close(); + lyxerr[Debug::GUI] << "killed pspell" << endl; + + if (spell_error_object) { + delete_pspell_can_have_error(spell_error_object); + spell_error_object = 0; + } + if (els) delete_pspell_string_emulation(els); + Managers::iterator it = managers_.begin(); Managers::iterator end = managers_.end(); for (; it != end; ++it) { + pspell_manager_save_all_word_lists(it->second.manager); delete_pspell_manager(it->second.manager); delete_pspell_config(it->second.config); } } -void PSpell::cleanUp() -{ - if (spell_error_object) { - delete_pspell_can_have_error(spell_error_object); - spell_error_object = 0; - } -} - - void PSpell::addManager(string const & lang) { PspellConfig * config = new_pspell_config(); @@ -109,17 +111,6 @@ res = MISSED; } return res; -} - - -void PSpell::close() -{ - Managers::iterator it = managers_.begin(); - Managers::iterator end = managers_.end(); - - for (; it != end; ++it) { - pspell_manager_save_all_word_lists(it->second.manager); - } } Index: src/pspell.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/pspell.h,v retrieving revision 1.3 diff -u -r1.3 pspell.h --- src/pspell.h 1 Dec 2002 22:59:17 -0000 1.3 +++ src/pspell.h 17 Feb 2003 19:06:01 -0000 @@ -37,14 +37,8 @@ */ virtual bool alive() { return true; } - /// clean up on messy exit - virtual void cleanUp(); - /// check the given word and return the result virtual enum Result check(WordLangTuple const &); - - /// finish this spellchecker instance - virtual void close(); /// insert the given word into the personal dictionary virtual void insert(WordLangTuple const &); Index: src/frontends/controllers/ChangeLog =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/controllers/ChangeLog,v retrieving revision 1.273 diff -u -r1.273 ChangeLog --- src/frontends/controllers/ChangeLog 2 Feb 2003 00:48:38 -0000 1.273 +++ src/frontends/controllers/ChangeLog 17 Feb 2003 19:06:03 -0000 @@ -1,3 +1,10 @@ +2003-02-17 John Levon <[EMAIL PROTECTED]> + + * ControlDialog.tmpl: do build before setParams for spellchecker's sake + + * ControlSpellchecker.h: + * ControlSpellchecker.C: rework + 2003-01-31 Angus Leeming <[EMAIL PROTECTED]> * ViewBase.h: add an isVisible() pure virtual method. Index: src/frontends/controllers/ControlDialog.tmpl =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/controllers/ControlDialog.tmpl,v retrieving revision 1.9 diff -u -r1.9 ControlDialog.tmpl --- src/frontends/controllers/ControlDialog.tmpl 22 Oct 2002 12:39:05 -0000 1.9 +++ src/frontends/controllers/ControlDialog.tmpl 17 Feb 2003 19:06:03 -0000 @@ -32,15 +32,15 @@ connect(); + if (!dialog_built_) { + view().build(); + dialog_built_ = true; + } + setParams(); if (emergency_exit_) { hide(); return; - } - - if (!dialog_built_) { - view().build(); - dialog_built_ = true; } bc().readOnly(bufferIsReadonly()); Index: src/frontends/controllers/ControlSpellchecker.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/controllers/ControlSpellchecker.C,v retrieving revision 1.36 diff -u -r1.36 ControlSpellchecker.C --- src/frontends/controllers/ControlSpellchecker.C 15 Jan 2003 14:23:21 -0000 1.36 +++ src/frontends/controllers/ControlSpellchecker.C 17 Feb 2003 19:06:03 -0000 @@ -22,6 +22,7 @@ #include "language.h" #include "lyxrc.h" #include "lyxtext.h" +#include "debug.h" #include "ispell.h" #ifdef USE_PSPELL @@ -32,17 +33,41 @@ #include "BoostFormat.h" +using std::endl; + ControlSpellchecker::ControlSpellchecker(LyXView & lv, Dialogs & d) : ControlDialogBD(lv, d), - newval_(0.0), oldval_(0), newvalue_(0), count_(0), - stop_(false), speller_(0) + newval_(0.0), oldval_(0), newvalue_(0), count_(0) +{} + + +ControlSpellchecker::~ControlSpellchecker() {} void ControlSpellchecker::setParams() { - if (speller_) + lyxerr[Debug::GUI] << "spell setParams" << endl; + startSession(); +} + + +void ControlSpellchecker::clearParams() +{ + lyxerr[Debug::GUI] << "spell clearParams" << endl; + endSession(); +} + + +void ControlSpellchecker::startSession() +{ + lyxerr[Debug::GUI] << "spell startSession" << endl; + + if (speller_.get()) { + lyxerr[Debug::GUI] << "startSession: speller exists" << endl; + speller_.reset(0); return; + } // create spell object string tmp; @@ -51,70 +76,161 @@ tmp = (lyxrc.isp_use_alt_lang) ? lyxrc.isp_alt_lang : buffer()->params.language->code(); - speller_ = new PSpell(buffer()->params, tmp); + speller_.reset(new PSpell(buffer()->params, tmp)); } else { #endif tmp = (lyxrc.isp_use_alt_lang) ? lyxrc.isp_alt_lang : buffer()->params.language->lang(); - speller_ = new ISpell(buffer()->params, tmp); + speller_.reset(new ISpell(buffer()->params, tmp)); #ifdef USE_PSPELL } #endif - if (!speller_->error().empty()) { - emergency_exit_ = true; - Alert::alert("The spellchecker has failed", speller_->error()); - clearParams(); + // reset values to initial + newval_ = 0.0; + oldval_ = 0; + newvalue_ = 0; + count_ = 0; + emergency_exit_ = false; + + // start off the check + if (speller_->error().empty()) { + check(); return; } + + emergency_exit_ = true; + string message = speller_->error(); + if (message.empty()) + message = _("The spell-checker could not be started.\n" + "Maybe it is mis-configured."); + + Alert::alert(_("The spell-checker has failed"), message); + speller_.reset(0); +} + + +void ControlSpellchecker::endSession() +{ + lyxerr[Debug::GUI] << "spell endSession" << endl; + + bufferview()->endOfSpellCheck(); + + emergency_exit_ = true; + + if (!speller_.get()) { + lyxerr[Debug::GUI] << "endSession with no speller" << endl; + return; + } + + speller_.reset(0); } void ControlSpellchecker::check() { + lyxerr[Debug::GUI] << "spell check a word" << endl; + SpellBase::Result res = SpellBase::OK; - stop_ = false; // clear any old selection LyXText * text = bufferview()->getLyXText(); bufferview()->toggleSelection(true); bufferview()->update(text, BufferView::SELECT); - while ((res == SpellBase::OK || res == SpellBase::IGNORE) && !stop_) { + while ((res == SpellBase::OK || res == SpellBase::IGNORE)) { word_ = bufferview()->nextWord(newval_); - if (word_.word().empty()) { - clearParams(); + // end of document + if (word_.word().empty()) break; - } ++count_; // Update slider if and only if value has changed newvalue_ = int(100.0 * newval_); if (newvalue_!= oldval_) { + lyxerr[Debug::GUI] << "Updating spell progress." << endl; oldval_ = newvalue_; // set progress bar - view().partialUpdate(0); + view().partialUpdate(SPELL_PROGRESSED); } - if (!speller_ || !speller_->alive()) { - clearParams(); - stop(); + // speller might be dead ... + if (!checkAlive()) return; - } res = speller_->check(word_); + + // ... or it might just be reporting an error + if (!checkAlive()) + return; } - if (!stop_ && !word_.word().empty()) + lyxerr[Debug::GUI] << "Found word \"" << word_.word() << "\"" << endl; + + if (!word_.word().empty()) { bufferview()->selectLastWord(); + } else { + showSummary(); + endSession(); + return; + } // set suggestions if (res != SpellBase::OK && res != SpellBase::IGNORE) { - view().partialUpdate(1); + lyxerr[Debug::GUI] << "Found a word needing checking." << endl; + view().partialUpdate(SPELL_FOUND_WORD); + } +} + + +bool ControlSpellchecker::checkAlive() +{ + if (speller_->alive() && speller_->error().empty()) + return true; + + string message = speller_->error(); + if (message.empty()) + message = _("The spell-checker has died for some reason.\n" + "Maybe it has been killed."); + + view().hide(); + speller_.reset(0); + + Alert::alert(_("The spell-checker has failed"), message); + return false; +} + + +void ControlSpellchecker::showSummary() +{ + if (!checkAlive() || count_ == 0) { + view().hide(); + return; + } + + string message; + +#if USE_BOOST_FORMAT + if (count_ != 1) { + boost::format fmter("%1$d words checked."); + fmter % count_; + message += fmter.str(); + } else { + message += _("One word checked."); } +#else + if (count_ != 1) { + message += tostr(count_) + " words checked"; + } else { + message = _("One word checked."); + } +#endif + + view().hide(); + Alert::alert(_("Spell-checking is complete"), message); } @@ -160,64 +276,3 @@ } -void ControlSpellchecker::stop() -{ - stop_ = true; - bufferview()->endOfSpellCheck(); -} - - -void ControlSpellchecker::clearParams() -{ - if (!speller_) - return; - - if (speller_->alive()) { - speller_->close(); - - message_ = string(_("Spellchecking completed!")) + '\n'; - -#if USE_BOOST_FORMAT - if (count_ != 1) { - boost::format fmter("%1$d words checked."); - fmter % count_; - message_ += fmter.str(); - } else { - message_ += _("One word checked."); - } -#else - if (count_ != 1) { - message_ += tostr(count_) + " words checked"; - } else { - message_ = _("One word checked."); - } -#endif - } else { - message_ = speller_->error(); - speller_->cleanUp(); - if (message_.empty()) - message_ = _("The spell checker has died for some reason.\n" - "Maybe it has been killed."); - - // make sure that the dialog is not launched - emergency_exit_ = true; - Alert::alert("The spellchecker has failed", message_); - } - - delete speller_; - - bufferview()->endOfSpellCheck(); - - // show closing message if any words were checked. - if (count_ > 0) - view().partialUpdate(2); - - // reset values to initial - newval_ = 0.0; - oldval_ = 0; - newvalue_ = 0; - count_ = 0; - message_.erase(); - stop_ = false; - speller_ = 0; -} Index: src/frontends/controllers/ControlSpellchecker.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/controllers/ControlSpellchecker.h,v retrieving revision 1.14 diff -u -r1.14 ControlSpellchecker.h --- src/frontends/controllers/ControlSpellchecker.h 15 Jan 2003 14:23:21 -0000 1.14 +++ src/frontends/controllers/ControlSpellchecker.h 17 Feb 2003 19:06:03 -0000 @@ -20,15 +20,23 @@ #include "LString.h" #include "WordLangTuple.h" +#include <boost/scoped_ptr.hpp> + class SpellBase; /** A controller for Spellchecker dialogs. */ class ControlSpellchecker : public ControlDialogBD { public: - /// + enum State { + SPELL_PROGRESSED, //< update progress bar + SPELL_FOUND_WORD //< found a bad word + }; + ControlSpellchecker(LyXView &, Dialogs &); + ~ControlSpellchecker(); + /// replace word with replacement void replace(string const &); @@ -41,10 +49,8 @@ /// ignore all occurances of word void ignoreAll(); - /// stop checking - void stop(); - /// check text until next misspelled/unknown word + /// returns true when finished void check(); /// get suggestion @@ -56,13 +62,22 @@ /// returns progress value int getProgress() const { return oldval_; } - /// returns exit message - string const getMessage() const { return message_; } - /// returns word count int getCount() const { return count_; } private: + /// give error message is spellchecker dies + bool checkAlive(); + + /// start a spell-checking session + void startSession(); + + /// end a spell-checking session + void endSession(); + + /// show count of checked words at normal exit + void showSummary(); + /// set the params before show or update void setParams(); /// clean-up on hide. @@ -82,14 +97,8 @@ /// word count int count_; - /// exit message - string message_; - - /// set to true to stop checking - bool stop_; - /// The actual spellchecker object - SpellBase * speller_; + boost::scoped_ptr<SpellBase> speller_; }; #endif // CONTROLSPELLCHECKER_H Index: src/frontends/qt2/ChangeLog =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/qt2/ChangeLog,v retrieving revision 1.389.2.10 diff -u -r1.389.2.10 ChangeLog --- src/frontends/qt2/ChangeLog 17 Feb 2003 00:40:29 -0000 1.389.2.10 +++ src/frontends/qt2/ChangeLog 17 Feb 2003 19:06:06 -0000 @@ -1,5 +1,13 @@ 2003-02-17 John Levon <[EMAIL PROTECTED]> + * ui/QSpellcheckerDialogBase.ui: + * QSpellchecker.h: + * QSpellchecker.C: + * QSpellcheckerDialog.h: + * QSpellcheckerDialog.C: reworking + +2003-02-17 John Levon <[EMAIL PROTECTED]> + * ui/QSpellcheckerModule.ui: capitalization fix 2003-02-15 John Levon <[EMAIL PROTECTED]> Index: src/frontends/qt2/QSpellchecker.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/qt2/QSpellchecker.C,v retrieving revision 1.16 diff -u -r1.16 QSpellchecker.C --- src/frontends/qt2/QSpellchecker.C 13 Jan 2003 09:17:12 -0000 1.16 +++ src/frontends/qt2/QSpellchecker.C 17 Feb 2003 19:06:06 -0000 @@ -46,22 +46,6 @@ } -void QSpellchecker::update_contents() -{ - dialog_->wordED->setText(""); - dialog_->replaceCO->clear(); - dialog_->suggestionsLB->clear(); - dialog_->spellcheckPR->setProgress(0); - dialog_->spellcheckPB->setEnabled(true); - dialog_->wordED->setEnabled(false); - dialog_->replaceCO->setEnabled(false); - dialog_->replacePB->setEnabled(false); - dialog_->ignorePB->setEnabled(false); - dialog_->replacePB_3->setEnabled(false); - dialog_->addPB->setEnabled(false); -} - - void QSpellchecker::accept() { controller().ignoreAll(); @@ -86,35 +70,18 @@ } -void QSpellchecker::spellcheck() -{ - dialog_->spellcheckPB->setEnabled(false); - dialog_->wordED->setEnabled(true); - dialog_->replaceCO->setEnabled(true); - dialog_->replacePB->setEnabled(true); - dialog_->ignorePB->setEnabled(true); - dialog_->replacePB_3->setEnabled(true); - dialog_->addPB->setEnabled(true); - controller().check(); -} - - -void QSpellchecker::stop() +void QSpellchecker::partialUpdate(int s) { - controller().stop(); - dialog_->spellcheckPB->setEnabled(true); - hide(); -} + ControlSpellchecker::State const state = + static_cast<ControlSpellchecker::State>(s); + switch (state) { -void QSpellchecker::partialUpdate(int id) -{ - switch (id) { - case 0: + case ControlSpellchecker::SPELL_PROGRESSED: dialog_->spellcheckPR->setProgress(controller().getProgress()); break; - case 1: { + case ControlSpellchecker::SPELL_FOUND_WORD: { dialog_->wordED->setText(toqstr(controller().getWord())); dialog_->suggestionsLB->clear(); @@ -127,12 +94,5 @@ } break; - case 2: - dialog_->spellcheckPB->setEnabled(true); - hide(); - QMessageBox::information(0, qt_("Spellcheck complete"), - toqstr(controller().getMessage()), - qt_("OK")); - break; } } Index: src/frontends/qt2/QSpellchecker.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/qt2/QSpellchecker.h,v retrieving revision 1.7 diff -u -r1.7 QSpellchecker.h --- src/frontends/qt2/QSpellchecker.h 20 Oct 2002 01:48:28 -0000 1.7 +++ src/frontends/qt2/QSpellchecker.h 17 Feb 2003 19:06:06 -0000 @@ -34,17 +34,15 @@ /// update from controller void partialUpdate(int id); private: - void stop(); void accept(); void add(); void ignore(); void replace(); - void spellcheck(); /// Apply changes virtual void apply() {} - /// update - virtual void update_contents(); + /// not needed + virtual void update_contents() {} /// build the dialog virtual void build_dialog(); }; Index: src/frontends/qt2/QSpellcheckerDialog.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/qt2/QSpellcheckerDialog.C,v retrieving revision 1.9 diff -u -r1.9 QSpellcheckerDialog.C --- src/frontends/qt2/QSpellcheckerDialog.C 17 Dec 2002 20:37:10 -0000 1.9 +++ src/frontends/qt2/QSpellcheckerDialog.C 17 Feb 2003 19:06:06 -0000 @@ -29,13 +29,7 @@ form_(form) { connect(closePB, SIGNAL(clicked()), - this, SLOT(stop())); -} - - -void QSpellcheckerDialog::stop() -{ - form_->stop(); + form, SLOT(slotClose())); } @@ -45,12 +39,6 @@ } -void QSpellcheckerDialog::spellcheckClicked() -{ - form_->spellcheck(); -} - - void QSpellcheckerDialog::addClicked() { form_->add(); @@ -98,7 +86,6 @@ void QSpellcheckerDialog::closeEvent(QCloseEvent * e) { - form_->stop(); form_->slotWMHide(); e->accept(); } Index: src/frontends/qt2/QSpellcheckerDialog.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/qt2/QSpellcheckerDialog.h,v retrieving revision 1.9 diff -u -r1.9 QSpellcheckerDialog.h --- src/frontends/qt2/QSpellcheckerDialog.h 12 Dec 2002 21:07:20 -0000 1.9 +++ src/frontends/qt2/QSpellcheckerDialog.h 17 Feb 2003 19:06:06 -0000 @@ -28,9 +28,7 @@ virtual void suggestionChanged(const QString &); protected slots: - virtual void stop(); virtual void acceptClicked(); - virtual void spellcheckClicked(); virtual void addClicked(); virtual void replaceClicked(); virtual void ignoreClicked(); Index: src/frontends/qt2/ui/QSpellcheckerDialogBase.ui =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/qt2/ui/QSpellcheckerDialogBase.ui,v retrieving revision 1.1.2.1 diff -u -r1.1.2.1 QSpellcheckerDialogBase.ui --- src/frontends/qt2/ui/QSpellcheckerDialogBase.ui 13 Feb 2003 22:40:28 -0000 1.1.2.1 +++ src/frontends/qt2/ui/QSpellcheckerDialogBase.ui 17 Feb 2003 19:06:07 -0000 @@ -13,7 +13,7 @@ <rect> <x>0</x> <y>0</y> - <width>309</width> + <width>305</width> <height>395</height> </rect> </property> @@ -72,7 +72,7 @@ </property> <property stdset="1"> <name>text</name> - <string>A&dd</string> + <string>&Add</string> </property> <property> <name>toolTip</name> @@ -102,7 +102,7 @@ </property> <property stdset="1"> <name>text</name> - <string>&Accept</string> + <string>I&gnore All</string> </property> <property> <name>toolTip</name> @@ -218,7 +218,7 @@ </property> <property stdset="1"> <name>text</name> - <string>Unknown:</string> + <string>Unknown word:</string> </property> <property> <name>buddy</name> @@ -263,21 +263,6 @@ <string>Replace with selected word</string> </property> </widget> - <widget row="1" column="2" > - <class>QPushButton</class> - <property stdset="1"> - <name>name</name> - <cstring>spellcheckPB</cstring> - </property> - <property stdset="1"> - <name>text</name> - <string>&Start...</string> - </property> - <property> - <name>toolTip</name> - <string>Start spellcheck</string> - </property> - </widget> </grid> </widget> <connections> @@ -312,12 +297,6 @@ <slot>addClicked()</slot> </connection> <connection> - <sender>spellcheckPB</sender> - <signal>clicked()</signal> - <receiver>QSpellcheckerDialogBase</receiver> - <slot>spellcheckClicked()</slot> - </connection> - <connection> <sender>suggestionsLB</sender> <signal>doubleClicked(QListBoxItem*)</signal> <receiver>QSpellcheckerDialogBase</receiver> @@ -335,11 +314,9 @@ <slot access="public">optionsClicked()</slot> <slot access="public">replaceChanged(const QString &)</slot> <slot access="public">replaceClicked()</slot> - <slot access="public">spellcheckClicked()</slot> <slot access="public">suggestionChanged(const QString &)</slot> </connections> <tabstops> - <tabstop>spellcheckPB</tabstop> <tabstop>wordED</tabstop> <tabstop>replaceCO</tabstop> <tabstop>suggestionsLB</tabstop> Index: src/frontends/xforms/ChangeLog =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/xforms/ChangeLog,v retrieving revision 1.661.2.3 diff -u -r1.661.2.3 ChangeLog --- src/frontends/xforms/ChangeLog 15 Feb 2003 19:09:04 -0000 1.661.2.3 +++ src/frontends/xforms/ChangeLog 17 Feb 2003 19:06:12 -0000 @@ -1,3 +1,9 @@ +2003-02-17 John Levon <[EMAIL PROTECTED]> + + * FormSpellchecker.h: + * FormSpellchecker.C: + * forms/form_spellchecker.fd: reworking + 2003-02-15 John Levon <[EMAIL PROTECTED]> * forms/form_graphics.fd: fix duplicate 'a' shortcut Index: src/frontends/xforms/FormSpellchecker.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/xforms/FormSpellchecker.C,v retrieving revision 1.30 diff -u -r1.30 FormSpellchecker.C --- src/frontends/xforms/FormSpellchecker.C 26 Dec 2002 14:14:29 -0000 1.30 +++ src/frontends/xforms/FormSpellchecker.C 17 Feb 2003 19:06:13 -0000 @@ -15,8 +15,8 @@ #endif #include "xformsBC.h" -#include "ControlSpellchecker.h" #include "FormSpellchecker.h" +#include "ControlSpellchecker.h" #include "forms/form_spellchecker.h" #include "forms_gettext.h" @@ -26,11 +26,12 @@ #include FORMS_H_LOCATION -typedef FormCB<ControlSpellchecker, FormDB<FD_spellchecker> > base_class; +using std::endl; +typedef FormCB<ControlSpellchecker, FormDB<FD_spellchecker> > base_class; FormSpellchecker::FormSpellchecker() - : base_class(_("Spellchecker")), state_(STOPPED) + : base_class(_("Spellchecker")) {} @@ -64,8 +65,6 @@ tooltips().init(dialog_->browser_suggestions, str); // Work-around xforms' bug; enable tooltips for browser widgets. setPrehandler(dialog_->browser_suggestions); - str = _("Start the spellingchecker."); - tooltips().init(dialog_->button_start, str); str = _("Replace unknown word."); tooltips().init(dialog_->button_replace, str); str = _("Ignore unknown word."); @@ -79,16 +78,14 @@ } -void FormSpellchecker::updateState(State state) +void FormSpellchecker::partialUpdate(int s) { + ControlSpellchecker::State const state = + static_cast<ControlSpellchecker::State>(s); + switch (state) { - case READY_TO_START: - fl_set_slider_value(dialog_->slider_progress, 0.0); - fl_set_object_label(dialog_->slider_progress, "0 %"); - break; - case CHECKING: - { + case ControlSpellchecker::SPELL_FOUND_WORD: { // Set suggestions. string w = controller().getWord(); fl_set_input(dialog_->input_replacement, w.c_str()); @@ -101,8 +98,7 @@ // Fall through... } - case STARTED: - { + case ControlSpellchecker::SPELL_PROGRESSED: { int const progress = controller().getProgress(); if (progress == 0) break; @@ -114,68 +110,17 @@ fl_set_slider_bounds(dialog_->slider_progress, 0.0, total); fl_set_slider_value(dialog_->slider_progress, wordcount); fl_set_object_label(dialog_->slider_progress, label.c_str()); + fl_redraw_object(dialog_->slider_progress); break; } - case STOPPED: - { - controller().stop(); - - double const wordcount = controller().getCount(); - - fl_set_slider_bounds(dialog_->slider_progress, 0.0, wordcount); - fl_set_slider_value(dialog_->slider_progress, wordcount); - fl_set_object_label(dialog_->slider_progress, "100 %"); - break; - } } - - bool const state_change = state_ != state; - state_ = state; - - if (!state_change) - return; - - bool const running = (state == STARTED || state == CHECKING); - string const label = running ? _("Stop|#S") : _("Start|#S"); - - fl_set_object_label(dialog_->button_start, idex(label).c_str()); - fl_set_button_shortcut(dialog_->button_start, scex(label).c_str(), 1); - fl_redraw_object(dialog_->button_start); - - string const tip = running ? - _("Stop the spellingchecker.") : - _("Start the spellingchecker."); - tooltips().init(dialog_->button_start, tip); - - setEnabled(dialog_->button_replace, running); - setEnabled(dialog_->button_ignore, running); - setEnabled(dialog_->button_accept, running); - setEnabled(dialog_->button_add, running); - setEnabled(dialog_->browser_suggestions, running); - setEnabled(dialog_->input_replacement, running); -} - - -void FormSpellchecker::update() -{ - // clear input fields - fl_set_input(dialog_->input_replacement, ""); - fl_set_object_label(dialog_->text_unknown, ""); - fl_clear_browser(dialog_->browser_suggestions); - - // reset dialog and buttons into start condition - updateState(READY_TO_START); } ButtonPolicy::SMInput FormSpellchecker::input(FL_OBJECT * ob, long ob_value) { - if (ob == dialog_->button_start) { - updateState(STARTED); - controller().check(); - - } else if (ob == dialog_->button_replace) { + if (ob == dialog_->button_replace) { string const tmp = getString(dialog_->input_replacement); controller().replace(tmp); @@ -208,19 +153,4 @@ } return ButtonPolicy::SMI_VALID; -} - - -void FormSpellchecker::partialUpdate(int id) -{ - switch (id) { - case 1: - // Set suggestions. - updateState(CHECKING); - break; - case 2: - // End of spell checking. - updateState(STOPPED); - break; - } } Index: src/frontends/xforms/FormSpellchecker.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/xforms/FormSpellchecker.h,v retrieving revision 1.15 diff -u -r1.15 FormSpellchecker.h --- src/frontends/xforms/FormSpellchecker.h 29 Nov 2002 12:47:33 -0000 1.15 +++ src/frontends/xforms/FormSpellchecker.h 17 Feb 2003 19:06:13 -0000 @@ -33,26 +33,14 @@ virtual void apply() {} /// Build the dialog virtual void build(); - /// - virtual void update(); + /// not needed. + virtual void update() {} /// set suggestions and exit message virtual void partialUpdate(int); /// Filter the inputs virtual ButtonPolicy::SMInput input(FL_OBJECT *, long); - - /// - enum State { - READY_TO_START, - STARTED, - CHECKING, - STOPPED - }; - /// - void updateState(State state); - /// - State state_; }; #endif // FORMSPELLCHECKER_H Index: src/frontends/xforms/forms/form_spellchecker.fd =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/xforms/forms/form_spellchecker.fd,v retrieving revision 1.10 diff -u -r1.10 form_spellchecker.fd --- src/frontends/xforms/forms/form_spellchecker.fd 26 Jan 2003 16:58:37 -0000 1.10 +++ src/frontends/xforms/forms/form_spellchecker.fd 17 Feb 2003 19:06:13 -0000 @@ -11,7 +11,7 @@ Name: form_spellchecker Width: 385 Height: 375 -Number of Objects: 13 +Number of Objects: 12 -------------------- class: FL_BOX @@ -124,24 +124,6 @@ -------------------- class: FL_BUTTON type: NORMAL_BUTTON -box: 280 25 100 25 -boxtype: FL_UP_BOX -colors: FL_COL1 FL_COL1 -alignment: FL_ALIGN_CENTER -style: FL_NORMAL_STYLE -size: FL_NORMAL_SIZE -lcol: FL_BLACK -label: Start|#S -shortcut: -resize: FL_RESIZE_NONE -gravity: FL_NorthEast FL_NorthEast -name: button_start -callback: C_FormBaseInputCB -argument: 0 - --------------------- -class: FL_BUTTON -type: NORMAL_BUTTON box: 280 195 100 25 boxtype: FL_UP_BOX colors: FL_COL1 FL_COL1 @@ -185,7 +167,7 @@ style: FL_NORMAL_STYLE size: FL_NORMAL_SIZE lcol: FL_BLACK -label: Accept|#A +label: Ignore All|#g shortcut: resize: FL_RESIZE_X gravity: FL_NorthEast FL_NorthEast Index: src/support/forkedcall.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/forkedcall.C,v retrieving revision 1.11 diff -u -r1.11 forkedcall.C --- src/support/forkedcall.C 27 Nov 2002 10:30:28 -0000 1.11 +++ src/support/forkedcall.C 17 Feb 2003 19:06:14 -0000 @@ -147,6 +147,24 @@ return retval_; } + +bool ForkedProcess::running() const +{ + if (!pid()) + return false; + + // Un-UNIX like, but we don't have much use for + // knowing if a zombie exists, so just reap it first. + int waitstatus; + waitpid(pid(), &waitstatus, WNOHANG); + + // Racy of course, but it will do. + if (::kill(pid(), 0) && errno == ESRCH) + return false; + return true; +} + + void ForkedProcess::kill(int tol) { lyxerr << "ForkedProcess::kill(" << tol << ')' << endl; Index: src/support/forkedcall.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/forkedcall.h,v retrieving revision 1.7 diff -u -r1.7 forkedcall.h --- src/support/forkedcall.h 31 Oct 2002 12:42:26 -0000 1.7 +++ src/support/forkedcall.h 17 Feb 2003 19:06:14 -0000 @@ -98,6 +98,9 @@ /// Returns the identifying command (for display in the GUI perhaps). string const & command() const { return command_; } + /// is the process running ? + bool running() const; + /** Kill child prematurely. * First, a SIGHUP is sent to the child. * If that does not end the child process within "tolerance" Index: src/support/ChangeLog =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/ChangeLog,v retrieving revision 1.149 diff -u -r1.149 ChangeLog --- src/support/ChangeLog 4 Dec 2002 13:26:55 -0000 1.149 +++ src/support/ChangeLog 17 Feb 2003 19:08:40 -0000 @@ -1,3 +1,8 @@ +2003-02-17 John Levon <[EMAIL PROTECTED]> + + * forkedcall.h: + * forkedcall.C: add running() + 2002-12-04 Jean-Marc Lasgouttes <[EMAIL PROTECTED]> * filetools.C (getExtFromContents): remove detection of epsi