From 0f18dddbd600f76e14d2e082a8bae0cf61961afe Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=BCrgen=20Vigna?= Date: Fri, 13 Jul 2001 11:50:39 +0000 Subject: [PATCH] Edwin's spellchecker GUII patch with some fixes to it. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@2235 a592a061-630c-0410-9148-cb99ea01b6c8 --- forms/ChangeLog | 4 + po/POTFILES.in | 4 +- src/BufferView_pimpl.C | 4 +- src/ChangeLog | 13 + src/Makefile.am | 8 +- src/frontends/ChangeLog | 4 + src/frontends/Dialogs.h | 6 +- src/frontends/controllers/ChangeLog | 6 + .../controllers/ControlSpellchecker.C | 269 ++++++ .../controllers/ControlSpellchecker.h | 116 +++ src/frontends/controllers/GUI.h | 12 + src/frontends/controllers/Makefile.am | 2 + src/frontends/controllers/ViewBase.h | 7 +- src/frontends/xforms/ChangeLog | 12 + src/frontends/xforms/Dialogs.C | 4 + src/frontends/xforms/FormPreferences.C | 38 +- src/frontends/xforms/FormPreferences.h | 16 +- src/frontends/xforms/FormSpellchecker.C | 114 +++ src/frontends/xforms/FormSpellchecker.h | 53 ++ src/frontends/xforms/Makefile.am | 4 + src/frontends/xforms/form_preferences.C | 6 +- src/frontends/xforms/form_preferences.h | 4 +- src/frontends/xforms/form_spellchecker.C | 115 +++ src/frontends/xforms/form_spellchecker.h | 30 + .../xforms/forms/form_preferences.fd | 2 +- .../xforms/forms/form_spellchecker.fd | 286 ++++++ src/frontends/xforms/forms/makefile | 1 + src/lyx_gui_misc.C | 11 - src/lyxfunc.C | 5 +- src/sp_base.h | 47 + src/sp_ispell.h | 81 ++ src/sp_pspell.h | 66 ++ src/sp_spell.C | 580 ++++++++++++ src/spellchecker.C | 875 ------------------ src/spellchecker.h | 27 - 35 files changed, 1873 insertions(+), 959 deletions(-) create mode 100644 src/frontends/controllers/ControlSpellchecker.C create mode 100644 src/frontends/controllers/ControlSpellchecker.h create mode 100644 src/frontends/xforms/FormSpellchecker.C create mode 100644 src/frontends/xforms/FormSpellchecker.h create mode 100644 src/frontends/xforms/form_spellchecker.C create mode 100644 src/frontends/xforms/form_spellchecker.h create mode 100644 src/frontends/xforms/forms/form_spellchecker.fd create mode 100644 src/sp_base.h create mode 100644 src/sp_ispell.h create mode 100644 src/sp_pspell.h create mode 100644 src/sp_spell.C delete mode 100644 src/spellchecker.C delete mode 100644 src/spellchecker.h diff --git a/forms/ChangeLog b/forms/ChangeLog index 77d9b00b38..d7f94cb59e 100644 --- a/forms/ChangeLog +++ b/forms/ChangeLog @@ -1,3 +1,7 @@ +2001-07-13 Edwin Leuven + + * sp_form.fd: remove completely + 2001-06-27 John Levon * sp_form.fd: remove duplicate spell options diff --git a/po/POTFILES.in b/po/POTFILES.in index 300a18a53d..aa7a0456c4 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -24,6 +24,7 @@ src/frontends/controllers/ControlInclude.C src/frontends/controllers/ControlPreamble.C src/frontends/controllers/ControlPrint.C src/frontends/controllers/ControlSearch.C +src/frontends/controllers/ControlSpellchecker.C src/frontends/controllers/helper_funcs.C src/frontends/gnome/FormCitation.C src/frontends/gnome/FormIndex.C @@ -142,6 +143,8 @@ src/frontends/xforms/form_ref.C src/frontends/xforms/FormRef.C src/frontends/xforms/form_search.C src/frontends/xforms/FormSearch.C +src/frontends/xforms/form_spellchecker.C +src/frontends/xforms/FormSpellchecker.C src/frontends/xforms/form_tabular.C src/frontends/xforms/FormTabular.C src/frontends/xforms/form_tabular_create.C @@ -205,7 +208,6 @@ src/MenuBackend.C src/minibuffer.C src/paragraph.C src/print_form.C -src/spellchecker.C src/sp_form.C src/support/filetools.C src/support/getUserName.C diff --git a/src/BufferView_pimpl.C b/src/BufferView_pimpl.C index f42ae6f022..7fde8f3361 100644 --- a/src/BufferView_pimpl.C +++ b/src/BufferView_pimpl.C @@ -82,7 +82,7 @@ extern BufferList bufferlist; extern char ascii_type; extern bool math_insert_greek(BufferView *, char); -extern void sigchldhandler(pid_t pid, int * status); +extern void sigchldchecker(pid_t pid, int * status); extern int bibitemMaxWidth(BufferView *, LyXFont const &); @@ -1034,7 +1034,7 @@ void BufferView::Pimpl::cursorToggle() if (pid == -1) // error find out what is wrong ; // ignore it for now. else if (pid > 0) - sigchldhandler(pid, &status); + sigchldchecker(pid, &status); updatelist.update(bv_); diff --git a/src/ChangeLog b/src/ChangeLog index 748e086e93..0687d3eb56 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,16 @@ +2001-07-13 Edwin Leuven + + * BufferView_pimpl.C: sigchldchecker instead of sigchldhandeler in + cursorToggle() + * lyx_gui_misc.C: remove spellchecker + * lyxfunc.C: showSpellchecker + * sp_base.h: added + * sp_ispell.h: added + * sp_pspell.h: added + * sp_spell.C: added + * sp_form.[Ch]: removed + * spellchecker.[Ch]: removed + 2001-07-12 Lars Gullik Bjønnes * trans_decl.h: remove allowed from KmodInfo diff --git a/src/Makefile.am b/src/Makefile.am index 48c490fad5..374e4c6825 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -179,10 +179,10 @@ lyx_SOURCES = \ print_form.C \ print_form.h \ screen.C \ - sp_form.C \ - sp_form.h \ - spellchecker.C \ - spellchecker.h \ + sp_base.h \ + sp_spell.C \ + sp_ispell.h \ + sp_pspell.h \ stl_string_fwd.h \ tabular.C \ tabular.h \ diff --git a/src/frontends/ChangeLog b/src/frontends/ChangeLog index 9f3ec9e491..66fbde6d91 100644 --- a/src/frontends/ChangeLog +++ b/src/frontends/ChangeLog @@ -1,3 +1,7 @@ +2001-07-13 Edwin Leuven + + * Dialogs.h: added showSpellchecker + 2001-07-03 Jean-Marc Lasgouttes * GUIRunTime.h: (x11Display): diff --git a/src/frontends/Dialogs.h b/src/frontends/Dialogs.h index 84e41a936a..05c712d526 100644 --- a/src/frontends/Dialogs.h +++ b/src/frontends/Dialogs.h @@ -133,8 +133,6 @@ public: SigC::Signal0 showPreamble; /// SigC::Signal0 showPreferences; - /// bring up the spellchecker tab in preferences - SigC::Signal0 showSpellcheckerPreferences; /// SigC::Signal0 showPrint; /// @@ -143,6 +141,10 @@ public: SigC::Signal1 createRef; /// SigC::Signal0 showSearch; + /// bring up the spellchecker + SigC::Signal0 showSpellchecker; + /// bring up the spellchecker tab in preferences + SigC::Signal0 showSpellcheckerPreferences; /// pop up the splash SigC::Signal0 showSplash; /// destroy the splash dialog diff --git a/src/frontends/controllers/ChangeLog b/src/frontends/controllers/ChangeLog index fa5ab26b98..1db3254d79 100644 --- a/src/frontends/controllers/ChangeLog +++ b/src/frontends/controllers/ChangeLog @@ -1,3 +1,9 @@ +2001-07-13 Edwin Leuven + + * ControlSpellchecker.[Ch]: added + * ViewBase.h: added partialUpdate(int) member + * GUI.h: added spell stuff + 2001-07-12 Lars Gullik Bjønnes * ControlExternal.C: (*it). -> it-> diff --git a/src/frontends/controllers/ControlSpellchecker.C b/src/frontends/controllers/ControlSpellchecker.C new file mode 100644 index 0000000000..b68e9de899 --- /dev/null +++ b/src/frontends/controllers/ControlSpellchecker.C @@ -0,0 +1,269 @@ +/* This file is part of + * ====================================================== + * + * LyX, The Document Processor + * + * Copyright 2001 The LyX Team. + * + * ====================================================== + * + * \file ControlSpellchecker.C + * \author Edwin Leuven + */ + +#include + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include FORMS_H_LOCATION + +#ifdef HAVE_SYS_SELECT_H +# ifdef HAVE_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 +# endif +# endif +#include +#endif + +#include "buffer.h" +#include "lyxrc.h" +#include "BufferView.h" +#include "LyXView.h" +#include "gettext.h" +#include "support/lstrings.h" +#include "language.h" + +#include "ViewBase.h" +#include "ButtonControllerBase.h" +#include "ControlSpellchecker.h" +#include "Dialogs.h" +#include "Liason.h" + +#ifdef USE_PSPELL +# include "sp_pspell.h" +#else +# include "sp_ispell.h" +#endif + +#include "debug.h" + +using SigC::slot; + +ControlSpellchecker::ControlSpellchecker(LyXView & lv, Dialogs & d) + : ControlDialog(lv, d) +{ + d_.showSpellchecker.connect(SigC::slot(this, &ControlSpellchecker::show)); + + rtl_ = false; + word_ = ""; + newval_ = 0.0; + oldval_ = 0; + newvalue_ = 0; + count_ = 0; + message_ = ""; + stop_ = false; + result_ = SpellBase::ISP_UNKNOWN; + speller_ = 0; + +} + + +ControlSpellchecker::~ControlSpellchecker() +{ +} + + +void ControlSpellchecker::show() +{ + if (isBufferDependent() && !lv_.view()->available()) + return; + + if (!speller_) { + // create spell object +#ifdef USE_PSPELL + string tmp = (lyxrc.isp_use_alt_lang) ? + lyxrc.isp_alt_lang : lv_.buffer()->params.language->code(); + + speller_ = new PSpell(lv_.view()->buffer()->params, tmp); +#else + string tmp = (lyxrc.isp_use_alt_lang) ? + lyxrc.isp_alt_lang : lv_.buffer()->params.language->lang(); + + speller_ = new ISpell(lv_.view()->buffer()->params, tmp); +#endif + + if (lyxrc.isp_use_alt_lang) { + Language const * lang = languages.getLanguage(tmp); + if (lang) + rtl_ = lang->RightToLeft(); + } else { + rtl_ = lv_.buffer()->params.language->RightToLeft(); + } + + if (speller_->error() != 0) { + message_ = speller_->error(); + view().partialUpdate(2); + hide(); + return; + } + } + + bc().readOnly(isReadonly()); + view().show(); +} + + +void ControlSpellchecker::hide() +{ + delete speller_; + speller_ = 0; + + disconnect(); + view().hide(); +} + + +void ControlSpellchecker::check() +{ + result_ = SpellBase::ISP_UNKNOWN; + stop_ = false; + + while (result_!=SpellBase::ISP_MISSED && !stop_) { + word_ = lv_.view()->nextWord(newval_); + if (word_.empty()) { + quit(); + break; + } + + ++count_; + + // Update slider if and only if value has changed + newvalue_ = int(100.0*newval_); + if (newvalue_!= oldval_) { + oldval_ = newvalue_; + // set progress bar + view().partialUpdate(0); + } + + if (!speller_->alive()) quit(); + + result_ = speller_->check(word_); + } + + if (!stop_ && !word_.empty()) + lv_.view()->selectLastWord(); + + // set suggestions + if (result_==SpellBase::ISP_MISSED) { + view().partialUpdate(1); + } +} + + +void ControlSpellchecker::replace(string const & replacement) +{ + lv_.view()->replaceWord(replacement); + check(); +} + + +void ControlSpellchecker::replaceAll(string const & replacement) +{ + // TODO: add to list + replace(replacement); +} + + +void ControlSpellchecker::insert() +{ + speller_->insert(word_); +} + + +string ControlSpellchecker::getSuggestion() +{ + // this is needed because string tmp = nextmiss() + // segfaults when nextMiss is 0 + string tmp; + char const * w = speller_->nextMiss(); + + if (w!=0) { + tmp = w; + if (rtl_) reverse(tmp.begin(), tmp.end()); + } + + return tmp; +} + + +string ControlSpellchecker::getWord() +{ + string tmp = word_; + if (rtl_) reverse(tmp.begin(), tmp.end()); + return tmp; +} + + +void ControlSpellchecker::ignoreAll() +{ + speller_->accept(word_); + check(); +} + + +void ControlSpellchecker::stop() +{ + stop_ = true; +} + + +void ControlSpellchecker::quit() +{ + if (speller_->alive()) { + speller_->close(); + message_ = tostr(count_); + if (count_ != 1) { + message_ += _(" words checked."); + } else { + message_ += _(" word checked."); + } + message_ = "\n" + message_; + message_ = _("Spellchecking completed! ") + message_; + } else { + speller_->cleanUp(); + message_ = _("The spell checker has died for some reason.\n" + "Maybe it has been killed."); + } + + lv_.view()->endOfSpellCheck(); + + // hide dialog, disconnect and delete speller + hide(); + + // show closing message + view().partialUpdate(2); + + // reset values to initial + rtl_ = false; + word_ = ""; + newval_ = 0.0; + oldval_ = 0; + newvalue_ = 0; + count_ = 0; + message_ = ""; + stop_ = false; + result_ = SpellBase::ISP_UNKNOWN; +} + + +void ControlSpellchecker::options() +{ + lv_.getDialogs()->showSpellcheckerPreferences(); +} + + diff --git a/src/frontends/controllers/ControlSpellchecker.h b/src/frontends/controllers/ControlSpellchecker.h new file mode 100644 index 0000000000..9b4cb72a59 --- /dev/null +++ b/src/frontends/controllers/ControlSpellchecker.h @@ -0,0 +1,116 @@ +// -*- C++ -*- +/* This file is part of + * ====================================================== + * + * LyX, The Document Processor + * + * Copyright 2001 The LyX Team. + * + * ====================================================== + * + * \file ControlSpellchecker.h + * \author Edwin Leuven + */ + +#ifndef CONTROLSPELLCHECKER_H +#define CONTROLSPELLCHECKER_H + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "ControlDialogs.h" +#include "sp_base.h" + +/** A controller for Spellchecker dialogs. + */ +class ControlSpellchecker : public ControlDialog { +public: + /// + ControlSpellchecker(LyXView &, Dialogs &); + + /// + ~ControlSpellchecker(); + + /// replace word with replacement + void replace(string const &); + + /// replace all occurances of word + void replaceAll(string const &); + + /// insert word in personal dictionary + void insert(); + + /// ignore all occurances of word + void ignoreAll(); + + /// quit spellchecker + void quit(); + + /// stop checking + void stop(); + + /// check text until next misspelled/unknown word + void check(); + + /// spell options + void options(); + + /// get suggestion + string getSuggestion(); + + /// get word + string getWord(); + + /// returns progress value + int getProgress() { + return oldval_; + } + + /// returns exit message + string getMessage() { + return message_; + } + +private: + + /// set the params before show or update + void show(); + + /// clean-up on hide. + void hide(); + + /// not needed. + virtual void apply() {} + + /// right to left + bool rtl_; + + /// current word being checked + string word_; + + /// values for progress + float newval_; + int oldval_; + int newvalue_; + + /// word count + int count_; + + /// exit message + string message_; + + /// set to true to stop checking + bool stop_; + + /// spellchecker status + enum SpellBase::spellStatus result_; + + /// The actual spellchecker object + SpellBase * speller_; + +}; + +#endif // CONTROLSPELLCHECKER_H + + diff --git a/src/frontends/controllers/GUI.h b/src/frontends/controllers/GUI.h index c37220ddf1..e0c6482e36 100644 --- a/src/frontends/controllers/GUI.h +++ b/src/frontends/controllers/GUI.h @@ -294,6 +294,18 @@ public: : GUI(lv, d) {} }; +/** Specialization for Spellchecker dialog + */ +class ControlSpellchecker; + +template +class GUISpellchecker : + public GUI { +public: + /// + GUISpellchecker(LyXView & lv, Dialogs & d) + : GUI(lv, d) {} +}; /** Specialization for Toc dialog */ diff --git a/src/frontends/controllers/Makefile.am b/src/frontends/controllers/Makefile.am index b4f862e048..db785eba7e 100644 --- a/src/frontends/controllers/Makefile.am +++ b/src/frontends/controllers/Makefile.am @@ -61,6 +61,8 @@ libcontrollers_la_SOURCES=\ ControlRef.h \ ControlSearch.C \ ControlSearch.h \ + ControlSpellchecker.C \ + ControlSpellchecker.h \ ControlSplash.C \ ControlSplash.h \ ControlTabularCreate.C \ diff --git a/src/frontends/controllers/ViewBase.h b/src/frontends/controllers/ViewBase.h index 70ff2aa308..b00b58a9ca 100644 --- a/src/frontends/controllers/ViewBase.h +++ b/src/frontends/controllers/ViewBase.h @@ -47,7 +47,12 @@ public: void CancelButton() { controller_.CancelButton(); } /// void RestoreButton() { controller_.RestoreButton(); } - + + /** Defaults to nothing. Can be used by the Controller, however, to + indicate to the View that something has changed and that the + dialog therefore needs updating. */ + virtual void partialUpdate(int id) {} + protected: /// The view is, after all, controlled! ControlButtons & controller_; diff --git a/src/frontends/xforms/ChangeLog b/src/frontends/xforms/ChangeLog index bbf2eea014..a83ed65de8 100644 --- a/src/frontends/xforms/ChangeLog +++ b/src/frontends/xforms/ChangeLog @@ -1,3 +1,15 @@ +2001-07-13 Edwin Leuven + + * add spellchecker + + * FormPreferences.[Ch]: rename spellchecker to spelloptions + * form_preferences.[Ch]: idem + * forms/form_preferences.fd: idem + * FormSpellchecker.[Ch]: added + * form_spellchecker.[Ch]: added + * forms/form_spellchecker.fd: added + * Dialogs.C: add spellchecker + 2001-07-12 Lars Gullik Bjønnes * FormFiledialog.C: (*it). -> it-> diff --git a/src/frontends/xforms/Dialogs.C b/src/frontends/xforms/Dialogs.C index 4046c1771e..430da846db 100644 --- a/src/frontends/xforms/Dialogs.C +++ b/src/frontends/xforms/Dialogs.C @@ -37,6 +37,7 @@ #include "ControlPrint.h" #include "ControlRef.h" #include "ControlSearch.h" +#include "ControlSpellchecker.h" #include "ControlSplash.h" #include "ControlTabularCreate.h" #include "ControlToc.h" @@ -63,6 +64,7 @@ #include "form_print.h" #include "form_ref.h" #include "form_search.h" +#include "form_spellchecker.h" #include "form_splash.h" #include "form_tabular_create.h" #include "form_toc.h" @@ -85,6 +87,7 @@ #include "FormPrint.h" #include "FormRef.h" #include "FormSearch.h" +#include "FormSpellchecker.h" #include "FormSplash.h" #include "FormTabularCreate.h" #include "FormToc.h" @@ -122,6 +125,7 @@ Dialogs::Dialogs(LyXView * lv) add(new GUIPrint(*lv, *this)); add(new GUIRef(*lv, *this)); add(new GUISearch(*lv, *this)); + add(new GUISpellchecker(*lv, *this)); add(new GUITabularCreate(*lv, *this)); add(new GUIToc(*lv, *this)); add(new GUIUrl(*lv, *this)); diff --git a/src/frontends/xforms/FormPreferences.C b/src/frontends/xforms/FormPreferences.C index f8503dc84d..ea746e0d38 100644 --- a/src/frontends/xforms/FormPreferences.C +++ b/src/frontends/xforms/FormPreferences.C @@ -73,7 +73,7 @@ FormPreferences::FormPreferences(LyXView * lv, Dialogs * d) colors_(*this), converters_(*this), inputs_misc_(*this), formats_(*this), interface_(*this), language_(*this), lnf_misc_(*this), outputs_misc_(*this), paths_(*this), - printer_(*this), screen_fonts_(*this), spellchecker_(*this) + printer_(*this), screen_fonts_(*this), spelloptions_(*this) { // let the dialog be shown // This is a permanent connection so we won't bother @@ -144,7 +144,7 @@ void FormPreferences::showSpellPref() { show(); fl_set_folder(dialog_->tabfolder_prefs, lang_opts_tab_->form); - fl_set_folder(lang_opts_tab_->tabfolder_outer, spellchecker_.dialog()->form); + fl_set_folder(lang_opts_tab_->tabfolder_outer, spelloptions_.dialog()->form); } @@ -205,7 +205,7 @@ void FormPreferences::build() paths_.build(); printer_.build(); screen_fonts_.build(); - spellchecker_.build(); + spelloptions_.build(); // Now add them to the tabfolder fl_addto_tabfolder(dialog_->tabfolder_prefs, @@ -267,7 +267,7 @@ void FormPreferences::build() // then building usage fl_addto_tabfolder(lang_opts_tab_->tabfolder_outer, _("Spell checker"), - spellchecker_.dialog()->form); + spelloptions_.dialog()->form); fl_addto_tabfolder(lang_opts_tab_->tabfolder_outer, _("Language"), language_.dialog()->form); @@ -298,7 +298,7 @@ void FormPreferences::apply() paths_.apply(); printer_.apply(); screen_fonts_.apply(); - spellchecker_.apply(); + spelloptions_.apply(); } @@ -330,8 +330,8 @@ void FormPreferences::feedback(FL_OBJECT * ob) str = printer_.feedback(ob); } else if (ob->form->fdui == screen_fonts_.dialog()) { str = screen_fonts_.feedback(ob); - } else if (ob->form->fdui == spellchecker_.dialog()) { - str = spellchecker_.feedback(ob); + } else if (ob->form->fdui == spelloptions_.dialog()) { + str = spelloptions_.feedback(ob); } str = formatted(_(str), dialog_->text_warning->w-10, FL_SMALL_SIZE); @@ -364,8 +364,8 @@ bool FormPreferences::input(FL_OBJECT * ob, long) return paths_.input(ob); else if (ob->form->fdui == screen_fonts_.dialog()) return screen_fonts_.input(); - else if (ob->form->fdui == spellchecker_.dialog()) - return spellchecker_.input(ob); + else if (ob->form->fdui == spelloptions_.dialog()) + return spelloptions_.input(ob); return true; } @@ -387,7 +387,7 @@ void FormPreferences::update() paths_.update(); printer_.update(); screen_fonts_.update(); - spellchecker_.update(); + spelloptions_.update(); } @@ -2739,18 +2739,18 @@ void FormPreferences::ScreenFonts::update() -FormPreferences::SpellChecker::SpellChecker( FormPreferences & p ) +FormPreferences::SpellOptions::SpellOptions( FormPreferences & p ) : parent_(p) {} -FD_form_spellchecker const * FormPreferences::SpellChecker::dialog() +FD_form_spelloptions const * FormPreferences::SpellOptions::dialog() { return dialog_.get(); } -void FormPreferences::SpellChecker::apply() +void FormPreferences::SpellOptions::apply() { string choice = fl_get_choice_text(dialog_->choice_spell_command); @@ -2808,9 +2808,9 @@ void FormPreferences::SpellChecker::apply() } -void FormPreferences::SpellChecker::build() +void FormPreferences::SpellOptions::build() { - dialog_.reset(parent_.build_spellchecker()); + dialog_.reset(parent_.build_spelloptions()); fl_addto_choice(dialog_->choice_spell_command, _(" none | ispell | aspell ")); @@ -2833,7 +2833,7 @@ void FormPreferences::SpellChecker::build() string const -FormPreferences::SpellChecker::feedback(FL_OBJECT const * const ob) const +FormPreferences::SpellOptions::feedback(FL_OBJECT const * const ob) const { string str; @@ -2860,9 +2860,9 @@ FormPreferences::SpellChecker::feedback(FL_OBJECT const * const ob) const } -bool FormPreferences::SpellChecker::input(FL_OBJECT const * const ob) +bool FormPreferences::SpellOptions::input(FL_OBJECT const * const ob) { - // !ob if function is called from updateSpellChecker() to de/activate + // !ob if function is called from updateSpellOptions() to de/activate // objects, // otherwise the function is called by an xforms CB via input(). @@ -2913,7 +2913,7 @@ bool FormPreferences::SpellChecker::input(FL_OBJECT const * const ob) } -void FormPreferences::SpellChecker::update() +void FormPreferences::SpellOptions::update() { int choice = 1; if (lyxrc.isp_command == "none") diff --git a/src/frontends/xforms/FormPreferences.h b/src/frontends/xforms/FormPreferences.h index ad517ec980..4905320d34 100644 --- a/src/frontends/xforms/FormPreferences.h +++ b/src/frontends/xforms/FormPreferences.h @@ -45,7 +45,7 @@ struct FD_form_paths; struct FD_form_preferences; struct FD_form_printer; struct FD_form_screen_fonts; -struct FD_form_spellchecker; +struct FD_form_spelloptions; /** This class provides an XForms implementation of the FormPreferences Dialog. @@ -129,7 +129,7 @@ private: /// FD_form_screen_fonts * build_screen_fonts(); /// - FD_form_spellchecker * build_spellchecker(); + FD_form_spelloptions * build_spelloptions(); /// Real GUI implementation. boost::scoped_ptr dialog_; @@ -503,12 +503,12 @@ private: friend class ScreenFonts; /// - class SpellChecker { + class SpellOptions { public: /// - SpellChecker( FormPreferences & p ); + SpellOptions( FormPreferences & p ); /// - FD_form_spellchecker const * dialog(); + FD_form_spelloptions const * dialog(); /// void apply(); // not const because calls update()! /// @@ -524,10 +524,10 @@ private: /// FormPreferences & parent_; /// - boost::scoped_ptr dialog_; + boost::scoped_ptr dialog_; }; /// - friend class SpellChecker; + friend class SpellOptions; /** The tab folders. */ @@ -555,7 +555,7 @@ private: /// ScreenFonts screen_fonts_; /// - SpellChecker spellchecker_; + SpellOptions spelloptions_; /** A couple of helper structs to enable colors to be sorted by name and by color */ diff --git a/src/frontends/xforms/FormSpellchecker.C b/src/frontends/xforms/FormSpellchecker.C new file mode 100644 index 0000000000..8e1cde6f0f --- /dev/null +++ b/src/frontends/xforms/FormSpellchecker.C @@ -0,0 +1,114 @@ +/** + * \file FormSpellchecker.C + * Copyright 2001 The LyX Team. + * See the file COPYING. + * + * \author Edwin Leuven + */ + +#include + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include "xformsBC.h" +#include "ControlSpellchecker.h" +#include "FormSpellchecker.h" +#include "form_spellchecker.h" + +typedef FormCB > base_class; + +FormSpellchecker::FormSpellchecker(ControlSpellchecker & c) + : base_class(c, _("LyX: Spellchecker")), clickline_(-1) +{} + + +void FormSpellchecker::build() +{ + dialog_.reset(build_spellchecker()); + + // Manage the buttons + bc().setCancel(dialog_->done); + bc().addReadOnly(dialog_->replace); + bc().addReadOnly(dialog_->accept); + bc().addReadOnly(dialog_->insert); + bc().addReadOnly(dialog_->ignore); + bc().addReadOnly(dialog_->start); + bc().addReadOnly(dialog_->stop); +} + +void FormSpellchecker::update() +{ + string w = ""; + fl_set_input(dialog_->input, w.c_str()); + fl_set_object_label(dialog_->text, w.c_str()); + fl_clear_browser(dialog_->browser); + fl_set_slider_value(dialog_->slider, 0); + clickline_ = -1 ; +} + + +ButtonPolicy::SMInput FormSpellchecker::input(FL_OBJECT * obj, long) +{ + if (obj == dialog_->replace) { + string tmp = fl_get_input(dialog_->input); + controller().replace(tmp); + } else if (obj == dialog_->start) { + controller().check(); + fl_deactivate_object(dialog_->start); + fl_set_object_lcol(dialog_->start, FL_INACTIVE); + } else if (obj == dialog_->ignore) { + controller().check(); + } else if (obj == dialog_->accept) { + controller().ignoreAll(); + } else if (obj == dialog_->insert) { + controller().insert(); + } else if (obj == dialog_->done) { + controller().quit(); + } else if (obj == dialog_->options) { + controller().options(); + } else if (obj == dialog_->browser) { + int sel = fl_get_browser(dialog_->browser); + if (clickline_==sel) { + string tmp = fl_get_input(dialog_->input); + controller().replace(tmp); + } + clickline_ = sel; + string tmp = fl_get_browser_line(dialog_->browser, clickline_); + fl_set_input(dialog_->input, tmp.c_str()); + } + + return ButtonPolicy::SMI_VALID; +} + +void FormSpellchecker::partialUpdate(int id) +{ + // set suggestions + if (id==0) { + // set progress bar (always) + fl_set_slider_value(dialog_->slider, + controller().getProgress()); + } else if (id==1) { + string w = controller().getWord(); + fl_set_input(dialog_->input, w.c_str()); + fl_set_object_label(dialog_->text, w.c_str()); + fl_clear_browser(dialog_->browser); + while (!(w = controller().getSuggestion()).empty() ) { + fl_add_browser_line(dialog_->browser, w.c_str()); + } + } else if (id==2) { + fl_show_messages(controller().getMessage().c_str()); + } +} + + +void FormSpellchecker::showMessage(const char * msg) +{ + fl_show_message(msg, "", ""); +} + +// note there is a button accept in session +// it is not clear whether this is ingoreall or replaceall + + diff --git a/src/frontends/xforms/FormSpellchecker.h b/src/frontends/xforms/FormSpellchecker.h new file mode 100644 index 0000000000..171687a075 --- /dev/null +++ b/src/frontends/xforms/FormSpellchecker.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +/** + * \file FormSpellchecker.h + * Copyright 2001 The LyX Team. + * See the file COPYING. + * + * \author Edwin Leuven + */ + +#ifndef FORMSPELLCHECKER_H +#define FORMSPELLCHECKER_H + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "FormBase.h" + +class ControlSpellchecker; +struct FD_form_spellchecker; + +/** This class provides an XForms implementation of the FormSpellchecker Dialog. + */ +class FormSpellchecker : public FormCB > { +public: + /// + FormSpellchecker(ControlSpellchecker &); + +private: + /// not needed. + virtual void apply() {} + /// Build the dialog + virtual void build(); + /// not needed. + virtual void update(); + + /// update progress bar and suggestions + void partialUpdate(int); + + /// show an error message + void showMessage(const char * msg); + + /// line clicked in browser, necessart for double clicking + int clickline_; + + /// Filter the inputs + virtual ButtonPolicy::SMInput input(FL_OBJECT *, long); + + /// Fdesign generated method + FD_form_spellchecker * build_spellchecker(); +}; + +#endif // FORMSPELLCHECKER_H diff --git a/src/frontends/xforms/Makefile.am b/src/frontends/xforms/Makefile.am index cb78c0d61b..90328b5ac7 100644 --- a/src/frontends/xforms/Makefile.am +++ b/src/frontends/xforms/Makefile.am @@ -136,6 +136,10 @@ libxforms_la_SOURCES = \ FormSearch.h \ form_search.C \ form_search.h \ + FormSpellchecker.C \ + FormSpellchecker.h \ + form_spellchecker.C \ + form_spellchecker.h \ FormSplash.C \ FormSplash.h \ form_splash.C \ diff --git a/src/frontends/xforms/form_preferences.C b/src/frontends/xforms/form_preferences.C index f78dc671db..fdc3af0819 100644 --- a/src/frontends/xforms/form_preferences.C +++ b/src/frontends/xforms/form_preferences.C @@ -252,17 +252,17 @@ FD_form_outputs_misc * FormPreferences::build_outputs_misc() } /*---------------------------------------*/ -FD_form_spellchecker::~FD_form_spellchecker() +FD_form_spelloptions::~FD_form_spelloptions() { if ( form->visible ) fl_hide_form( form ); fl_free_form( form ); } -FD_form_spellchecker * FormPreferences::build_spellchecker() +FD_form_spelloptions * FormPreferences::build_spelloptions() { FL_OBJECT *obj; - FD_form_spellchecker *fdui = new FD_form_spellchecker; + FD_form_spelloptions *fdui = new FD_form_spelloptions; fdui->form = fl_bgn_form(FL_NO_BOX, 450, 360); fdui->form->u_vdata = this; diff --git a/src/frontends/xforms/form_preferences.h b/src/frontends/xforms/form_preferences.h index 54da663ac9..92f27deee9 100644 --- a/src/frontends/xforms/form_preferences.h +++ b/src/frontends/xforms/form_preferences.h @@ -86,8 +86,8 @@ struct FD_form_outputs_misc { FL_OBJECT *input_ascii_roff; FL_OBJECT *input_checktex; }; -struct FD_form_spellchecker { - ~FD_form_spellchecker(); +struct FD_form_spelloptions { + ~FD_form_spelloptions(); FL_FORM *form; FL_OBJECT *choice_spell_command; diff --git a/src/frontends/xforms/form_spellchecker.C b/src/frontends/xforms/form_spellchecker.C new file mode 100644 index 0000000000..a06a62c819 --- /dev/null +++ b/src/frontends/xforms/form_spellchecker.C @@ -0,0 +1,115 @@ +// File modified by fdfix.sh for use by lyx (with xforms >= 0.88) and gettext +#include +#include "lyx_gui_misc.h" +#include "gettext.h" + +/* Form definition file generated with fdesign. */ + +#include FORMS_H_LOCATION +#include +#include "form_spellchecker.h" +#include "FormSpellchecker.h" + +FD_form_spellchecker::~FD_form_spellchecker() +{ + if ( form->visible ) fl_hide_form( form ); + fl_free_form( form ); +} + + +FD_form_spellchecker * FormSpellchecker::build_spellchecker() +{ + FL_OBJECT *obj; + FD_form_spellchecker *fdui = new FD_form_spellchecker; + + fdui->form = fl_bgn_form(FL_NO_BOX, 540, 280); + fdui->form->u_vdata = this; + obj = fl_add_box(FL_UP_BOX, 0, 0, 540, 280, ""); + fl_set_object_lsize(obj, 0); + fdui->text = obj = fl_add_text(FL_NORMAL_TEXT, 80, 10, 220, 30, ""); + fl_set_object_boxtype(obj, FL_DOWN_BOX); + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_lalign(obj, FL_ALIGN_LEFT|FL_ALIGN_INSIDE); + fl_set_object_callback(obj, C_FormBaseInputCB, 0); + fdui->input = obj = fl_add_input(FL_NORMAL_INPUT, 80, 40, 220, 30, _("Replace")); + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_callback(obj, C_FormBaseInputCB, 0); + fdui->browser = obj = fl_add_browser(FL_SELECT_BROWSER, 80, 70, 220, 150, _("Near\nMisses")); + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_lalign(obj, FL_ALIGN_LEFT); + { + char const * const dummy = N_("Spellchecker Options...|#O"); + fdui->options = obj = fl_add_button(FL_NORMAL_BUTTON, 310, 210, 220, 30, idex(_(dummy))); + fl_set_button_shortcut(obj, scex(_(dummy)), 1); + } + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_callback(obj, C_FormBaseInputCB, 0); + { + char const * const dummy = N_("Start spellchecking|#S"); + fdui->start = obj = fl_add_button(FL_NORMAL_BUTTON, 310, 10, 220, 30, idex(_(dummy))); + fl_set_button_shortcut(obj, scex(_(dummy)), 1); + } + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_callback(obj, C_FormBaseInputCB, 0); + { + char const * const dummy = N_("Insert in personal dictionary|#I"); + fdui->insert = obj = fl_add_button(FL_NORMAL_BUTTON, 310, 50, 220, 30, idex(_(dummy))); + fl_set_button_shortcut(obj, scex(_(dummy)), 1); + } + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_callback(obj, C_FormBaseInputCB, 0); + { + char const * const dummy = N_("Ignore word|#g"); + fdui->ignore = obj = fl_add_button(FL_NORMAL_BUTTON, 310, 110, 220, 30, idex(_(dummy))); + fl_set_button_shortcut(obj, scex(_(dummy)), 1); + } + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_callback(obj, C_FormBaseInputCB, 0); + { + char const * const dummy = N_("Accept word in this session|#A"); + fdui->accept = obj = fl_add_button(FL_NORMAL_BUTTON, 310, 80, 220, 30, idex(_(dummy))); + fl_set_button_shortcut(obj, scex(_(dummy)), 1); + } + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_callback(obj, C_FormBaseInputCB, 0); + { + char const * const dummy = N_("Stop spellchecking|#T"); + fdui->stop = obj = fl_add_button(FL_NORMAL_BUTTON, 310, 180, 220, 30, idex(_(dummy))); + fl_set_button_shortcut(obj, scex(_(dummy)), 1); + } + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_callback(obj, C_FormBaseInputCB, 0); + { + char const * const dummy = N_("Close Spellchecker|#C^["); + fdui->done = obj = fl_add_button(FL_NORMAL_BUTTON, 310, 240, 220, 30, idex(_(dummy))); + fl_set_button_shortcut(obj, scex(_(dummy)), 1); + } + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_callback(obj, C_FormBaseInputCB, 0); + // xgettext:no-c-format + obj = fl_add_box(FL_NO_BOX, 10, 250, 50, 20, _("0 %")); + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_lalign(obj, FL_ALIGN_LEFT|FL_ALIGN_INSIDE); + // xgettext:no-c-format + obj = fl_add_box(FL_NO_BOX, 250, 250, 50, 20, _("100 %")); + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_lalign(obj, FL_ALIGN_RIGHT|FL_ALIGN_INSIDE); + { + char const * const dummy = N_("Replace word|#R"); + fdui->replace = obj = fl_add_button(FL_NORMAL_BUTTON, 310, 140, 220, 30, idex(_(dummy))); + fl_set_button_shortcut(obj, scex(_(dummy)), 1); + } + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_callback(obj, C_FormBaseInputCB, 0); + fdui->slider = obj = fl_add_slider(FL_HOR_FILL_SLIDER, 10, 230, 290, 20, ""); + fl_set_object_color(obj, FL_BLUE, FL_COL1); + fl_set_object_lsize(obj, 0); + fl_set_object_lalign(obj, FL_ALIGN_LEFT); + fl_end_form(); + + fdui->form->fdui = fdui; + + return fdui; +} +/*---------------------------------------*/ + diff --git a/src/frontends/xforms/form_spellchecker.h b/src/frontends/xforms/form_spellchecker.h new file mode 100644 index 0000000000..2f14d0cab7 --- /dev/null +++ b/src/frontends/xforms/form_spellchecker.h @@ -0,0 +1,30 @@ +// File modified by fdfix.sh for use by lyx (with xforms >= 0.88) and gettext +/** Header file generated with fdesign **/ + +#ifndef FD_form_spellchecker_h_ +#define FD_form_spellchecker_h_ + +/** Callbacks, globals and object handlers **/ +extern "C" void C_FormBaseInputCB(FL_OBJECT *, long); + + +/**** Forms and Objects ****/ +struct FD_form_spellchecker { + ~FD_form_spellchecker(); + + FL_FORM *form; + FL_OBJECT *text; + FL_OBJECT *input; + FL_OBJECT *browser; + FL_OBJECT *options; + FL_OBJECT *start; + FL_OBJECT *insert; + FL_OBJECT *ignore; + FL_OBJECT *accept; + FL_OBJECT *stop; + FL_OBJECT *done; + FL_OBJECT *replace; + FL_OBJECT *slider; +}; + +#endif /* FD_form_spellchecker_h_ */ diff --git a/src/frontends/xforms/forms/form_preferences.fd b/src/frontends/xforms/forms/form_preferences.fd index 06df621d42..f1c2ab4c30 100644 --- a/src/frontends/xforms/forms/form_preferences.fd +++ b/src/frontends/xforms/forms/form_preferences.fd @@ -675,7 +675,7 @@ callback: argument: =============== FORM =============== -Name: form_spellchecker +Name: form_spelloptions Width: 450 Height: 360 Number of Objects: 11 diff --git a/src/frontends/xforms/forms/form_spellchecker.fd b/src/frontends/xforms/forms/form_spellchecker.fd new file mode 100644 index 0000000000..78310c5fdc --- /dev/null +++ b/src/frontends/xforms/forms/form_spellchecker.fd @@ -0,0 +1,286 @@ +Magic: 13000 + +Internal Form Definition File + (do not change) + +Number of forms: 1 +Unit of measure: FL_COORD_PIXEL + +=============== FORM =============== +Name: form_spellchecker +Width: 540 +Height: 280 +Number of Objects: 15 + +-------------------- +class: FL_BOX +type: UP_BOX +box: 0 0 540 280 +boxtype: FL_UP_BOX +colors: FL_COL1 FL_COL1 +alignment: FL_ALIGN_CENTER +style: FL_NORMAL_STYLE +size: 0 +lcol: FL_BLACK +label: +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: +callback: +argument: + +-------------------- +class: FL_TEXT +type: NORMAL_TEXT +box: 80 10 220 30 +boxtype: FL_DOWN_BOX +colors: FL_COL1 FL_MCOL +alignment: FL_ALIGN_LEFT|FL_ALIGN_INSIDE +style: FL_NORMAL_STYLE +size: FL_NORMAL_SIZE +lcol: FL_BLACK +label: +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: text +callback: C_FormBaseInputCB +argument: 0 + +-------------------- +class: FL_INPUT +type: NORMAL_INPUT +box: 80 40 220 30 +boxtype: FL_DOWN_BOX +colors: FL_COL1 FL_MCOL +alignment: FL_ALIGN_LEFT +style: FL_NORMAL_STYLE +size: FL_NORMAL_SIZE +lcol: FL_BLACK +label: Replace +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: input +callback: C_FormBaseInputCB +argument: 0 + +-------------------- +class: FL_BROWSER +type: SELECT_BROWSER +box: 80 70 220 150 +boxtype: FL_DOWN_BOX +colors: FL_COL1 FL_YELLOW +alignment: FL_ALIGN_LEFT +style: FL_NORMAL_STYLE +size: FL_NORMAL_SIZE +lcol: FL_BLACK +label: Near\nMisses +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: browser +callback: +argument: + +-------------------- +class: FL_BUTTON +type: NORMAL_BUTTON +box: 310 210 220 30 +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: Spellchecker Options...|#O +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: options +callback: C_FormBaseInputCB +argument: 0 + +-------------------- +class: FL_BUTTON +type: NORMAL_BUTTON +box: 310 10 220 30 +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 spellchecking|#S +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: start +callback: C_FormBaseInputCB +argument: 0 + +-------------------- +class: FL_BUTTON +type: NORMAL_BUTTON +box: 310 50 220 30 +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: Insert in personal dictionary|#I +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: insert +callback: C_FormBaseInputCB +argument: 0 + +-------------------- +class: FL_BUTTON +type: NORMAL_BUTTON +box: 310 110 220 30 +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: Ignore word|#g +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: ignore +callback: C_FormBaseInputCB +argument: 0 + +-------------------- +class: FL_BUTTON +type: NORMAL_BUTTON +box: 310 80 220 30 +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: Accept word in this session|#A +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: accept +callback: C_FormBaseInputCB +argument: 0 + +-------------------- +class: FL_BUTTON +type: NORMAL_BUTTON +box: 310 180 220 30 +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: Stop spellchecking|#T +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: stop +callback: C_FormBaseInputCB +argument: 0 + +-------------------- +class: FL_BUTTON +type: NORMAL_BUTTON +box: 310 240 220 30 +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: Close Spellchecker|#C^[ +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: done +callback: C_FormBaseInputCB +argument: 0 + +-------------------- +class: FL_BOX +type: NO_BOX +box: 10 250 50 20 +boxtype: FL_NO_BOX +colors: FL_COL1 FL_COL1 +alignment: FL_ALIGN_LEFT|FL_ALIGN_INSIDE +style: FL_NORMAL_STYLE +size: FL_NORMAL_SIZE +lcol: FL_BLACK +label: 0 % +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: +callback: +argument: + +-------------------- +class: FL_BOX +type: NO_BOX +box: 250 250 50 20 +boxtype: FL_NO_BOX +colors: FL_COL1 FL_COL1 +alignment: FL_ALIGN_RIGHT|FL_ALIGN_INSIDE +style: FL_NORMAL_STYLE +size: FL_NORMAL_SIZE +lcol: FL_BLACK +label: 100 % +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: +callback: +argument: + +-------------------- +class: FL_BUTTON +type: NORMAL_BUTTON +box: 310 140 220 30 +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: Replace word|#R +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: replace +callback: C_FormBaseInputCB +argument: 0 + +-------------------- +class: FL_SLIDER +type: HOR_FILL_SLIDER +box: 10 230 290 20 +boxtype: FL_DOWN_BOX +colors: FL_BLUE FL_COL1 +alignment: FL_ALIGN_LEFT +style: FL_NORMAL_STYLE +size: 0 +lcol: FL_BLACK +label: +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: slider +callback: +argument: + +============================== +create_the_forms diff --git a/src/frontends/xforms/forms/makefile b/src/frontends/xforms/forms/makefile index 220c07cb06..dbec489886 100644 --- a/src/frontends/xforms/forms/makefile +++ b/src/frontends/xforms/forms/makefile @@ -43,6 +43,7 @@ SRCS = form_bibitem.fd \ form_print.fd \ form_ref.fd \ form_search.fd \ + form_spellchecker.fd \ form_splash.fd \ form_tabular.fd \ form_tabular_create.fd \ diff --git a/src/lyx_gui_misc.C b/src/lyx_gui_misc.C index f6bd2605d5..479c2c394e 100644 --- a/src/lyx_gui_misc.C +++ b/src/lyx_gui_misc.C @@ -23,7 +23,6 @@ #include "lyx_cb.h" #include "lyx_main.h" #include "print_form.h" -#include "sp_form.h" #include "LyXView.h" #include "bufferview_funcs.h" #include "support/filetools.h" @@ -37,7 +36,6 @@ extern BufferView * current_view; extern FD_form_figure * fd_form_figure; extern FD_form_sendto * fd_form_sendto; -extern FD_form_spell_check * fd_form_spell_check; extern void HideFiguresPopups(); @@ -56,10 +54,6 @@ void RedrawAllBufferRelatedDialogs() if (fd_form_sendto->form_sendto->visible) { fl_redraw_form(fd_form_sendto->form_sendto); } - if (fd_form_spell_check && - fd_form_spell_check->form_spell_check->visible) { - fl_redraw_form(fd_form_spell_check->form_spell_check); - } } // Prevents LyX from crashing when no buffers available @@ -78,11 +72,6 @@ void CloseAllBufferRelatedDialogs() if (fd_form_sendto->form_sendto->visible) { fl_hide_form(fd_form_sendto->form_sendto); } - if (fd_form_spell_check) { - if (fd_form_spell_check->form_spell_check->visible) { - fl_trigger_object(fd_form_spell_check->done); - } - } HideFiguresPopups(); } diff --git a/src/lyxfunc.C b/src/lyxfunc.C index 57b5ac205c..adaa469981 100644 --- a/src/lyxfunc.C +++ b/src/lyxfunc.C @@ -60,7 +60,6 @@ #include "mathed/formulamacro.h" #include "mathed/math_cursor.h" #include "mathed/math_inset.h" -#include "spellchecker.h" #include "minibuffer.h" #include "vspace.h" #include "LyXView.h" @@ -1268,8 +1267,8 @@ string const LyXFunc::Dispatch(int ac, case LFUN_SPELLCHECK: if (lyxrc.isp_command != "none") - ShowSpellChecker(owner->view()); - break; // RVDK_PATCH_5 + owner->getDialogs()->showSpellchecker(); + break; // --- lyxserver commands ---------------------------- diff --git a/src/sp_base.h b/src/sp_base.h new file mode 100644 index 0000000000..413251d333 --- /dev/null +++ b/src/sp_base.h @@ -0,0 +1,47 @@ +#ifndef SP_BASE_H +#define SP_BASE_H + +class BufferParams; + +class SpellBase +{ + public: + + /// status + enum spellStatus { + ISP_OK = 1, + ISP_ROOT, + ISP_COMPOUNDWORD, + ISP_UNKNOWN, + ISP_MISSED, + ISP_IGNORE + }; + + virtual ~SpellBase() {} + + virtual void initialize(BufferParams const & , string const & ) = 0; + + virtual bool alive() = 0; + + virtual void cleanUp() = 0; + + virtual enum spellStatus check(string const &) = 0; + + virtual void close() = 0; + + virtual void insert(string const & ) = 0; + + virtual void accept(string const & ) = 0; + + virtual void store(string const & , string const & ) = 0; + + virtual char const * error() = 0; + + virtual char const * nextMiss() = 0; + + virtual void sigchldhandler(pid_t pid, int *) = 0; + +}; + +#endif + diff --git a/src/sp_ispell.h b/src/sp_ispell.h new file mode 100644 index 0000000000..aad831cb0f --- /dev/null +++ b/src/sp_ispell.h @@ -0,0 +1,81 @@ +#ifndef SP_ISPELL_H +#define SP_ISPELL_H + +#include "sp_base.h" + +class BufferParams; + + +class ISpell : public SpellBase +{ + public: + + enum ActualSpellChecker { + ASC_ISPELL, + ASC_ASPELL + }; + + ISpell(); + + ISpell(BufferParams const & params, string const & lang); + + ~ISpell(); + + + /// initialize spell checker + void initialize(BufferParams const & params, string const & lang); + + bool alive(); + + /// clean up after error + void cleanUp(); + + /// check word + enum spellStatus check(string const & word); + + /// close spellchecker + void close(); + + void insert(string const & word); + + void accept(string const & word); + + /// store replacement + void store(string const & mis, string const & cor); + + void sigchldhandler(pid_t pid, int *status); + + char const * nextMiss(); + + char const * error(); + + private: + + ActualSpellChecker actual_spell_checker; + + /// instream to communicate with ispell + FILE * in; + + /// outstream to communicate with ispell + FILE * out; + + /// spell error + char const * error_; + + /// ? + int isp_fd; + + /// + char * str; + /// + spellStatus flag; + /// + char * b; + /// + char * e; + +}; + +#endif + + diff --git a/src/sp_pspell.h b/src/sp_pspell.h new file mode 100644 index 0000000000..0833c8945e --- /dev/null +++ b/src/sp_pspell.h @@ -0,0 +1,66 @@ +#ifndef SP_PSPELL_H +#define SP_PSPELL_H + +#include "sp_base.h" + +class PspellManager; +class PspellStringEmulation; +class PspellCanHaveError; + +class BufferParams; + + +class PSpell : public SpellBase +{ + public: + + PSpell(); + + PSpell(BufferParams const & params, string const & lang); + + ~PSpell(); + + /// initialize spell checker + void initialize(BufferParams const & params, string const & lang); + + bool alive() { return true; } + + /// clean up after error + void cleanUp(); + + /// check word + enum spellStatus check(string const & word); + + /// close spellchecker + void close(); + + void insert(string const & word); + + void accept(string const & word); + + /// store replacement + void store(string const & mis, string const & cor); + + void sigchldhandler(pid_t pid, int *status); + + char const * nextMiss(); + + char const * error(); + + private: + + PspellManager * sc; + + PspellStringEmulation * els; + + PspellCanHaveError * spell_error_object; + + spellStatus flag; + + const char * error_; + +}; + +#endif + + diff --git a/src/sp_spell.C b/src/sp_spell.C new file mode 100644 index 0000000000..e10adc3f51 --- /dev/null +++ b/src/sp_spell.C @@ -0,0 +1,580 @@ +/* This file is part of + * ====================================================== + * + * LyX, The Document Processor + * + * Copyright 2001 The LyX Team. + * + * ====================================================== + * + * \file sp_pspell.C + * \author Kevin Atkinson + */ + +#include + +#ifdef __GNUG__ +#pragma implementation +#endif + +#ifdef USE_PSPELL + +#include +#include +#include + +#ifdef HAVE_SYS_SELECT_H +# ifdef HAVE_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 +# endif +# endif +#include +#endif + +#include "LString.h" +#include "support/lstrings.h" +#include "support/LAssert.h" + +#define USE_ORIGINAL_MANAGER_FUNCS 1 +# include + +#include "sp_pspell.h" + +extern void sigchldchecker(pid_t pid, int *status); + + +PSpell::PSpell() +{ + els = 0; + sc = 0; + spell_error_object = 0; + flag = ISP_UNKNOWN; +} + +PSpell::PSpell(BufferParams const & params, string const & lang) +{ + els = 0; + sc = 0; + spell_error_object = 0; + flag = ISP_UNKNOWN; + initialize(params, lang); +} + +PSpell::~PSpell() +{ + cleanUp(); + close(); + if (els) + delete_pspell_string_emulation(els); +} + + +void PSpell::initialize(BufferParams const &, string const & lang) +{ + PspellConfig * config = new_pspell_config(); + string code; + split(lang, code, '_'); + config->replace("language-tag", code.c_str()); + spell_error_object = new_pspell_manager(config); + if (pspell_error_number(spell_error_object) != 0) { + error_ = pspell_error_message(spell_error_object); + } else { + error_ = 0; + sc = to_pspell_manager(spell_error_object); + spell_error_object = 0; + } +} + + +void PSpell::cleanUp() +{ + if (spell_error_object) { + delete_pspell_can_have_error(spell_error_object); + spell_error_object = 0; + } +} + + +enum PSpell::spellStatus PSpell::check(string const & word) +{ + if (!sc) + return flag; + + int word_ok = pspell_manager_check(sc, word.c_str()); + lyx::Assert(word_ok != -1); + + if (word_ok) { + flag = ISP_OK; + } else { + PspellWordList const * sugs = + pspell_manager_suggest(sc, word.c_str()); + lyx::Assert(sugs != 0); + els = pspell_word_list_elements(sugs); + if (pspell_word_list_empty(sugs)) + flag = ISP_UNKNOWN; + else + flag = ISP_MISSED; + } + return flag; +} + + +void PSpell::close() +{ + if (sc) + pspell_manager_save_all_word_lists(sc); +} + + +void PSpell::insert(string const & word) +{ + if (sc) + pspell_manager_add_to_personal(sc, word.c_str()); +} + + +void PSpell::accept(string const & word) +{ + if (sc) + pspell_manager_add_to_session(sc, word.c_str()); +} + + +void PSpell::store(string const & mis, string const & cor) +{ + if (sc) + pspell_manager_store_replacement(sc, mis.c_str(), cor.c_str()); +} + + +char const * PSpell::nextMiss() +{ + if (els) + return pspell_string_emulation_next(els); +} + +char const * PSpell::error() +{ + return error_; +} + +void PSpell::sigchldhandler(pid_t pid, int * status) +{ + sigchldchecker(pid, status); +} + + + +#else + +/* + *This file is part of + * ====================================================== + * + * LyX, The Document Processor + * + * Copyright 1995 Matthias Ettrich + * Copyright 1995-1998 The LyX Team + * + * ====================================================== + */ + +#include +#include +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#ifdef HAVE_SYS_SELECT_H +# ifdef HAVE_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 +# endif +# endif +#include +#endif + +#include "LString.h" +#include "support/lstrings.h" +#include "lyxrc.h" +#include "debug.h" +#include "encoding.h" +#include "sp_ispell.h" + +using std::endl; + +/// can be found in src/insets/figinset.C +extern void sigchldchecker(pid_t pid, int * status); + +namespace { +/// pid for the `ispell' process. +pid_t isp_pid = -1; +} + + +ISpell::ISpell() +{ + str = 0; + flag = ISP_UNKNOWN; +} + + +ISpell::ISpell(BufferParams const & params, string const & lang) +{ + str = 0; + flag = ISP_UNKNOWN; + initialize(params, lang); +} + + +ISpell::~ISpell() +{ + delete[] str; +} + + +char const * ISpell::nextMiss() +{ + if (str == 0 || *(e+1) == '\0') return 0; + b = e + 2; + e = strpbrk(b, ",\n"); + *e = '\0'; + return b; +} + + +void ISpell::initialize(BufferParams const & params, string const & lang) +{ + static char o_buf[BUFSIZ]; // jc: it could be smaller + int pipein[2], pipeout[2]; + char * argv[14]; + int argc; + + isp_pid = -1; + + if (pipe(pipein) == -1 || pipe(pipeout) == -1) { + lyxerr << "LyX: Can't create pipe for spellchecker!" << endl; + goto END; + } + + if ((out = fdopen(pipein[1], "w")) == 0) { + lyxerr << "LyX: Can't create stream for pipe for spellchecker!" + << endl; + goto END; + } + + if ((in = fdopen(pipeout[0], "r")) == 0) { + lyxerr <<"LyX: Can't create stream for pipe for spellchecker!" + << endl; + goto END; + } + + setvbuf(out, o_buf, _IOLBF, BUFSIZ); + + isp_fd = pipeout[0]; + + isp_pid = fork(); + + if (isp_pid == -1) { + lyxerr << "LyX: Can't create child process for spellchecker!" + << endl; + goto END; + } + + if (isp_pid == 0) { + /* child process */ + dup2(pipein[0], STDIN_FILENO); + dup2(pipeout[1], STDOUT_FILENO); + ::close(pipein[0]); + ::close(pipein[1]); + ::close(pipeout[0]); + ::close(pipeout[1]); + + argc = 0; + char * tmp = new char[lyxrc.isp_command.length() + 1]; + lyxrc.isp_command.copy(tmp, lyxrc.isp_command.length()); + tmp[lyxrc.isp_command.length()] = '\0'; + argv[argc++] = tmp; + tmp = new char[3]; + string("-a").copy(tmp, 2); tmp[2] = '\0'; // pipe mode + argv[argc++] = tmp; + + if (lang != "default") { + tmp = new char[3]; + string("-d").copy(tmp, 2); tmp[2] = '\0'; // Dictionary file + argv[argc++] = tmp; + tmp = new char[lang.length() + 1]; + lang.copy(tmp, lang.length()); tmp[lang.length()] = '\0'; + argv[argc++] = tmp; + } + + if (lyxrc.isp_accept_compound) { + // Consider run-together words as legal compounds + tmp = new char[3]; + string("-C").copy(tmp, 2); tmp[2] = '\0'; + argv[argc++] = tmp; + } else { + // Report run-together words with + // missing blanks as errors + tmp = new char[3]; + string("-B").copy(tmp, 2); tmp[2] = '\0'; + argv[argc++] = tmp; + } + if (lyxrc.isp_use_esc_chars) { + // Specify additional characters that + // can be part of a word + tmp = new char[3]; + string("-w").copy(tmp, 2); tmp[2] = '\0'; + argv[argc++] = tmp; + // Put the escape chars in ""s + string tms = "\"" + lyxrc.isp_esc_chars + "\""; + tmp = new char[tms.length() + 1]; + tms.copy(tmp, tms.length()); tmp[tms.length()] = '\0'; + argv[argc++] = tmp; + } + if (lyxrc.isp_use_pers_dict) { + // Specify an alternate personal dictionary + tmp = new char[3]; + string("-p").copy(tmp, 2); + tmp[2]= '\0'; + argv[argc++] = tmp; + tmp = new char[lyxrc.isp_pers_dict.length() + 1]; + lyxrc.isp_pers_dict.copy(tmp, lyxrc.isp_pers_dict.length()); + tmp[lyxrc.isp_pers_dict.length()] = '\0'; + argv[argc++] = tmp; + } + if (lyxrc.isp_use_input_encoding && + params.inputenc != "default") { + string enc = (params.inputenc == "auto") + ? params.language->encoding()->LatexName() + : params.inputenc; + string::size_type n = enc.length(); + tmp = new char[3]; + string("-T").copy(tmp, 2); tmp[2] = '\0'; + argv[argc++] = tmp; // Input encoding + tmp = new char[n + 1]; + enc.copy(tmp, n); + tmp[n] = '\0'; + argv[argc++] = tmp; + } + + argv[argc++] = 0; + + execvp(argv[0], const_cast(argv)); + + // free the memory used by string::copy in the + // setup of argv + for (int i= 0; i < argc -1; ++i) + delete[] argv[i]; + + lyxerr << "LyX: Failed to start ispell!" << endl; + _exit(0); + } + { + /* 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 -- (kevinatk@home.com) + 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)); + + 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); + + // determine if the spell checker is really Aspell + if (strstr(buf, "Aspell")) + actual_spell_checker = ASC_ASPELL; + else + actual_spell_checker = ASC_ISPELL; + + 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; + } else { + // Select returned error + lyxerr << "Select on ispell returned error, what now?" << endl; + } + } + END: + if (isp_pid == -1) { + error_ = + "\n\n" + "The ispell-process has died for some reason. *One* possible reason\n" + "could be that you do not have a dictionary file\n" + "for the language of this document installed.\n" + "Check /usr/lib/ispell or set another\n" + "dictionary in the Spellchecker Options menu."; + } else { + error_ = 0; + } +} + + +bool ISpell::alive() +{ + return isp_pid != -1; +} + + +void ISpell::cleanUp() +{ + ::fclose(out); +} + + +enum ISpell::spellStatus ISpell::check(string const & word) +{ + //Please rewrite to use string. + + ::fputs(word.c_str(), out); + ::fputc('\n', out); + + char buf[1024]; + ::fgets(buf, 1024, in); + + /* I think we have to check if ispell is still alive here because + the signal-handler could have disabled blocking on the fd */ + if (!alive()) return ISP_UNKNOWN; + + switch (*buf) { + case '*': // Word found + flag = ISP_OK; + break; + case '+': // Word found through affix removal + flag = ISP_ROOT; + break; + case '-': // Word found through compound formation + flag = ISP_COMPOUNDWORD; + break; + case '\n': // Number or when in terse mode: no problems + flag = ISP_IGNORE; + break; + case '#': // Not found, no near misses and guesses + flag = ISP_UNKNOWN; + break; + case '?': // Not found, and no near misses, but guesses (guesses are ignored) + case '&': // Not found, but we have near misses + { + flag = ISP_MISSED; + char * p = strpbrk(buf, ":"); + str = new char[strlen(p) + 1]; + e = str; + strcpy(str, p); + break; + } + default: // This shouldn't happend, but you know Murphy + flag = ISP_UNKNOWN; + } + + *buf = 0; + if (flag!= ISP_IGNORE) { + while (*buf!= '\n') fgets(buf, 255, in); /* wait for ispell to finish */ + } + return flag; +} + + +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 (kevinatk@home.com) + + fputs("#\n", out); // Save personal dictionary + + fflush(out); + fclose(out); +} + + +void ISpell::insert(string const & word) +{ + ::fputc('*', out); // Insert word in personal dictionary + ::fputs(word.c_str(), out); + ::fputc('\n', out); +} + + +void ISpell::accept(string const & word) +{ + ::fputc('@', out); // Accept in this session + ::fputs(word.c_str(), out); + ::fputc('\n', out); +} + + +void ISpell::store(string const & mis, string const & cor) +{ + if (actual_spell_checker == ASC_ASPELL) { + ::fputs("$$ra ", out); + ::fputs(mis.c_str(), out); + ::fputc(',', out); + ::fputs(cor.c_str(), out); + ::fputc('\n', out); + } +} + + +void ISpell::sigchldhandler(pid_t pid, int * status) +{ + if (isp_pid > 0) { + if (pid == isp_pid) { + isp_pid= -1; + fcntl(isp_fd, F_SETFL, O_NONBLOCK); /* set the file descriptor + to nonblocking so we can + continue */ + } + } + sigchldchecker(pid, status); +} + +char const * ISpell::error() +{ + return error_; +} + + + +#endif diff --git a/src/spellchecker.C b/src/spellchecker.C deleted file mode 100644 index 34759911e9..0000000000 --- a/src/spellchecker.C +++ /dev/null @@ -1,875 +0,0 @@ -/* - *This file is part of - * ====================================================== - * - * LyX, The Document Processor - * - * Copyright 1995 Matthias Ettrich - * Copyright 1995-1998 The LyX Team - * - * ====================================================== - */ - -#include - -#ifdef __GNUG__ -#pragma implementation -#endif - -#include -#include -#include -#include -#include -#include -#include -#include FORMS_H_LOCATION - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -#ifdef HAVE_SYS_SELECT_H -# ifdef HAVE_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 -# endif -# endif -#include -#endif - -#include - -#include "LString.h" -#include "sp_form.h" -#include "spellchecker.h" -#include "lyx_main.h" -#include "buffer.h" -#include "lyxrc.h" -#include "BufferView.h" -#include "LyXView.h" -#include "frontends/Dialogs.h" -#include "gettext.h" -#include "lyx_gui_misc.h" -#include "debug.h" -#include "support/lstrings.h" -#include "language.h" -#include "encoding.h" -#include "support/lstrings.h" - -#ifdef USE_PSPELL -#define USE_ORIGINAL_MANAGER_FUNCS 1 -# include -#endif - -using std::reverse; -using std::endl; - -namespace { - -// Spellchecker status -enum { - ISP_OK = 1, - ISP_ROOT, - ISP_COMPOUNDWORD, - ISP_UNKNOWN, - ISP_MISSED, - ISP_IGNORE -}; - -bool RunSpellChecker(BufferView * bv); - -#ifndef USE_PSPELL - -FILE * in; -FILE * out; /* streams to communicate with ispell */ -pid_t isp_pid = -1; // pid for the `ispell' process. Also used (RO) in - // lyx_cb.C - -// the true spell checker program being used -enum ActualSpellChecker {ASC_ISPELL, ASC_ASPELL}; -ActualSpellChecker actual_spell_checker; - -int isp_fd; - -#else - -PspellManager * sc; - -#endif - -} // namespace anon - - -// Non-static so that it can be redrawn if the xforms colors are re-mapped -FD_form_spell_check *fd_form_spell_check = 0; - -void sigchldhandler(pid_t pid, int *status); - -extern void sigchldchecker(pid_t pid, int *status); - -#ifndef USE_PSPELL - -struct isp_result { - int flag; - char * str; - char * b; - char * e; - const char * next_miss(); - isp_result() { - flag = ISP_UNKNOWN; - str = 0; - } - ~isp_result() { - delete[] str; - } -}; - -const char * isp_result::next_miss() { - if (str == 0 || *(e+1) == '\0') return 0; - b = e + 2; - e = strpbrk(b, ",\n"); - *e = '\0'; - return b; -} - -#else - -struct isp_result { - int flag; - PspellStringEmulation * els; - - const char * next_miss(); - isp_result() { - flag = ISP_UNKNOWN; - els = 0; - } - ~isp_result() { - delete_pspell_string_emulation(els); - } -}; - -const char * isp_result::next_miss() -{ - return pspell_string_emulation_next(els); -} - -#endif - -namespace { - -const char * spell_error; - -#ifndef USE_PSPELL - -/***** Spellchecker *****/ - -// Could also use a clean up. (Asger Alstrup) - -void init_spell_checker(BufferParams const & params, string const & lang) -{ - static char o_buf[BUFSIZ]; // jc: it could be smaller - int pipein[2], pipeout[2]; - char * argv[14]; - int argc; - - isp_pid = -1; - - if (pipe(pipein) == -1 || pipe(pipeout) == -1) { - lyxerr << "LyX: Can't create pipe for spellchecker!" << endl; - goto END; - } - - if ((out = fdopen(pipein[1], "w")) == 0) { - lyxerr << "LyX: Can't create stream for pipe for spellchecker!" - << endl; - goto END; - } - - if ((in = fdopen(pipeout[0], "r")) == 0) { - lyxerr <<"LyX: Can't create stream for pipe for spellchecker!" - << endl; - goto END; - } - - setvbuf(out, o_buf, _IOLBF, BUFSIZ); - - isp_fd = pipeout[0]; - - isp_pid = fork(); - - if (isp_pid == -1) { - lyxerr << "LyX: Can't create child process for spellchecker!" - << endl; - goto END; - } - - if (isp_pid == 0) { - /* child process */ - dup2(pipein[0], STDIN_FILENO); - dup2(pipeout[1], STDOUT_FILENO); - close(pipein[0]); - close(pipein[1]); - close(pipeout[0]); - close(pipeout[1]); - - argc = 0; - char * tmp = new char[lyxrc.isp_command.length() + 1]; - lyxrc.isp_command.copy(tmp, lyxrc.isp_command.length()); - tmp[lyxrc.isp_command.length()] = '\0'; - argv[argc++] = tmp; - tmp = new char[3]; - string("-a").copy(tmp, 2); tmp[2] = '\0'; // pipe mode - argv[argc++] = tmp; - - if (lang != "default") { - tmp = new char[3]; - string("-d").copy(tmp, 2); tmp[2] = '\0'; // Dictionary file - argv[argc++] = tmp; - tmp = new char[lang.length() + 1]; - lang.copy(tmp, lang.length()); tmp[lang.length()] = '\0'; - argv[argc++] = tmp; - } - - if (lyxrc.isp_accept_compound) { - // Consider run-together words as legal compounds - tmp = new char[3]; - string("-C").copy(tmp, 2); tmp[2] = '\0'; - argv[argc++] = tmp; - } else { - // Report run-together words with - // missing blanks as errors - tmp = new char[3]; - string("-B").copy(tmp, 2); tmp[2] = '\0'; - argv[argc++] = tmp; - } - if (lyxrc.isp_use_esc_chars) { - // Specify additional characters that - // can be part of a word - tmp = new char[3]; - string("-w").copy(tmp, 2); tmp[2] = '\0'; - argv[argc++] = tmp; - // Put the escape chars in ""s - string tms = "\"" + lyxrc.isp_esc_chars + "\""; - tmp = new char[tms.length() + 1]; - tms.copy(tmp, tms.length()); tmp[tms.length()] = '\0'; - argv[argc++] = tmp; - } - if (lyxrc.isp_use_pers_dict) { - // Specify an alternate personal dictionary - tmp = new char[3]; - string("-p").copy(tmp, 2); - tmp[2]= '\0'; - argv[argc++] = tmp; - tmp = new char[lyxrc.isp_pers_dict.length() + 1]; - lyxrc.isp_pers_dict.copy(tmp, lyxrc.isp_pers_dict.length()); - tmp[lyxrc.isp_pers_dict.length()] = '\0'; - argv[argc++] = tmp; - } - if (lyxrc.isp_use_input_encoding && - params.inputenc != "default") { - string enc = (params.inputenc == "auto") - ? params.language->encoding()->LatexName() - : params.inputenc; - string::size_type n = enc.length(); - tmp = new char[3]; - string("-T").copy(tmp, 2); tmp[2] = '\0'; - argv[argc++] = tmp; // Input encoding - tmp = new char[n + 1]; - enc.copy(tmp, n); - tmp[n] = '\0'; - argv[argc++] = tmp; - } - - argv[argc++] = 0; - - execvp(argv[0], const_cast(argv)); - - // free the memory used by string::copy in the - // setup of argv - for (int i= 0; i < argc -1; ++i) - delete[] argv[i]; - - lyxerr << "LyX: Failed to start ispell!" << endl; - _exit(0); - } - { - /* 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 -- (kevinatk@home.com) - 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)); - - 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); - - // determine if the spell checker is really Aspell - if (strstr(buf, "Aspell")) - actual_spell_checker = ASC_ASPELL; - else - actual_spell_checker = ASC_ISPELL; - - 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; - } else { - // Select returned error - lyxerr << "Select on ispell returned error, what now?" << endl; - } - } - END: - if (isp_pid == -1) { - spell_error = - "\n\n" - "The ispell-process has died for some reason. *One* possible reason\n" - "could be that you do not have a dictionary file\n" - "for the language of this document installed.\n" - "Check /usr/lib/ispell or set another\n" - "dictionary in the spellchecker preferences."; - } else { - spell_error = 0; - } -} - - -bool sc_still_alive() { - return isp_pid != -1; -} - - -void sc_clean_up_after_error() -{ - ::fclose(out); -} - - -// Send word to ispell and get reply -isp_result * sc_check_word(string const & word) -{ - //Please rewrite to use string. - - ::fputs(word.c_str(), out); - ::fputc('\n', out); - - char buf[1024]; - ::fgets(buf, 1024, in); - - /* I think we have to check if ispell is still alive here because - the signal-handler could have disabled blocking on the fd */ - if (!sc_still_alive()) return 0; - - isp_result * result = new isp_result; - - switch (*buf) { - case '*': // Word found - result->flag = ISP_OK; - break; - case '+': // Word found through affix removal - result->flag = ISP_ROOT; - break; - case '-': // Word found through compound formation - result->flag = ISP_COMPOUNDWORD; - break; - case '\n': // Number or when in terse mode: no problems - result->flag = ISP_IGNORE; - break; - case '#': // Not found, no near misses and guesses - result->flag = ISP_UNKNOWN; - break; - case '?': // Not found, and no near misses, but guesses (guesses are ignored) - case '&': // Not found, but we have near misses - { - result->flag = ISP_MISSED; - char * p = strpbrk(buf, ":"); - result->str = new char[strlen(p) + 1]; - result->e = result->str; - strcpy(result->str, p); - break; - } - default: // This shouldn't happend, but you know Murphy - result->flag = ISP_UNKNOWN; - } - - *buf = 0; - if (result->flag!= ISP_IGNORE) { - while (*buf!= '\n') fgets(buf, 255, in); /* wait for ispell to finish */ - } - return result; -} - - -inline -void close_spell_checker() -{ - // 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 (kevinatk@home.com) - - fputs("#\n", out); // Save personal dictionary - - fflush(out); - fclose(out); -} - - -inline -void sc_insert_word(string const & word) -{ - ::fputc('*', out); // Insert word in personal dictionary - ::fputs(word.c_str(), out); - ::fputc('\n', out); -} - - -inline -void sc_accept_word(string const & word) -{ - ::fputc('@', out); // Accept in this session - ::fputs(word.c_str(), out); - ::fputc('\n', out); -} - - -inline -void sc_store_replacement(string const & mis, string const & cor) { - if (actual_spell_checker == ASC_ASPELL) { - ::fputs("$$ra ", out); - ::fputs(mis.c_str(), out); - ::fputc(',', out); - ::fputs(cor.c_str(), out); - ::fputc('\n', out); - } -} - -#else - -PspellCanHaveError * spell_error_object; - -void init_spell_checker(BufferParams const &, string const & lang) -{ - PspellConfig * config = new_pspell_config(); - string code; - split(lang, code, '_'); - config->replace("language-tag", code.c_str()); - spell_error_object = new_pspell_manager(config); - if (pspell_error_number(spell_error_object) != 0) { - spell_error = pspell_error_message(spell_error_object); - } else { - spell_error = 0; - sc = to_pspell_manager(spell_error_object); - spell_error_object = 0; - } -} - - -bool sc_still_alive() { - return true; -} - - -void sc_clean_up_after_error() -{ - delete_pspell_can_have_error(spell_error_object); -} - - - -// Send word to pspell and get reply -isp_result * sc_check_word(string const & word) -{ - isp_result * result = new isp_result; -#ifdef WITH_WARNINGS -#warning Why isnt word_ok a bool? (Lgb) -#endif - int word_ok = pspell_manager_check(sc, word.c_str()); - lyx::Assert(word_ok != -1); - - if (word_ok) { - result->flag = ISP_OK; - } else { - PspellWordList const * sugs = - pspell_manager_suggest(sc, word.c_str()); - lyx::Assert(sugs != 0); - result->els = pspell_word_list_elements(sugs); - if (pspell_word_list_empty(sugs)) - result->flag = ISP_UNKNOWN; - else - result->flag = ISP_MISSED; - } - return result; -} - - -inline -void close_spell_checker() -{ - pspell_manager_save_all_word_lists(sc); -} - - -inline -void sc_insert_word(string const & word) -{ - pspell_manager_add_to_personal(sc, word.c_str()); -} - - -inline -void sc_accept_word(string const & word) -{ - pspell_manager_add_to_session(sc, word.c_str()); -} - - -inline -void sc_store_replacement(string const & mis, string const & cor) -{ - pspell_manager_store_replacement(sc, mis.c_str(), cor.c_str()); -} - -#endif - -} // namespace anon - - -void ShowSpellChecker(BufferView * bv) -{ - FL_OBJECT * obj; - int ret; - - // Exit if we don't have a document open - if (!bv->available()) - return; - - if (fd_form_spell_check == 0) { - fd_form_spell_check = create_form_form_spell_check(); - // Make sure pressing the close box does not kill LyX. (RvdK) - fl_set_form_atclose(fd_form_spell_check->form_spell_check, - CancelCloseBoxCB, 0); - } - - // Clear form - fl_set_slider_value(fd_form_spell_check->slider, 0); - fl_set_slider_bounds(fd_form_spell_check->slider, 0, 100); - fl_set_object_label(fd_form_spell_check->text, ""); - fl_set_input(fd_form_spell_check->input, ""); - fl_clear_browser(fd_form_spell_check->browser); - - // Show form - if (fd_form_spell_check->form_spell_check->visible) { - fl_raise_form(fd_form_spell_check->form_spell_check); - } else { - fl_show_form(fd_form_spell_check->form_spell_check, - FL_PLACE_MOUSE | FL_FREE_SIZE, FL_TRANSIENT, - _("Spellchecker")); - } - fl_deactivate_object(fd_form_spell_check->slider); - - // deactivate insert, accept, replace, and stop - fl_deactivate_object(fd_form_spell_check->insert); - fl_deactivate_object(fd_form_spell_check->accept); - fl_deactivate_object(fd_form_spell_check->ignore); - fl_deactivate_object(fd_form_spell_check->replace); - fl_deactivate_object(fd_form_spell_check->stop); - fl_deactivate_object(fd_form_spell_check->input); - fl_deactivate_object(fd_form_spell_check->browser); - fl_set_object_lcol(fd_form_spell_check->insert, FL_INACTIVE); - fl_set_object_lcol(fd_form_spell_check->accept, FL_INACTIVE); - fl_set_object_lcol(fd_form_spell_check->ignore, FL_INACTIVE); - fl_set_object_lcol(fd_form_spell_check->replace, FL_INACTIVE); - fl_set_object_lcol(fd_form_spell_check->stop, FL_INACTIVE); - fl_set_object_lcol(fd_form_spell_check->input, FL_INACTIVE); - fl_set_object_lcol(fd_form_spell_check->browser, FL_INACTIVE); - - while (true) { - obj = fl_do_forms(); - if (obj == fd_form_spell_check->options) { - bv->owner()->getDialogs()->showSpellcheckerPreferences(); - } - if (obj == fd_form_spell_check->start) { - // activate insert, accept, and stop - fl_activate_object(fd_form_spell_check->insert); - fl_activate_object(fd_form_spell_check->accept); - fl_activate_object(fd_form_spell_check->ignore); - fl_activate_object(fd_form_spell_check->stop); - fl_activate_object(fd_form_spell_check->input); - fl_activate_object(fd_form_spell_check->browser); - fl_set_object_lcol(fd_form_spell_check->insert, FL_BLACK); - fl_set_object_lcol(fd_form_spell_check->accept, FL_BLACK); - fl_set_object_lcol(fd_form_spell_check->ignore, FL_BLACK); - fl_set_object_lcol(fd_form_spell_check->stop, FL_BLACK); - fl_set_object_lcol(fd_form_spell_check->input, FL_BLACK); - fl_set_object_lcol(fd_form_spell_check->browser, FL_BLACK); - // activate replace only if the file is not read-only - if (!bv->buffer()->isReadonly()) { - fl_activate_object(fd_form_spell_check->replace); - fl_set_object_lcol(fd_form_spell_check->replace, FL_BLACK); - } - - // deactivate options and start - fl_deactivate_object(fd_form_spell_check->options); - fl_deactivate_object(fd_form_spell_check->start); - fl_set_object_lcol(fd_form_spell_check->options, FL_INACTIVE); - fl_set_object_lcol(fd_form_spell_check->start, FL_INACTIVE); - - ret = RunSpellChecker(bv); - - // deactivate insert, accept, replace, and stop - fl_deactivate_object(fd_form_spell_check->insert); - fl_deactivate_object(fd_form_spell_check->accept); - fl_deactivate_object(fd_form_spell_check->ignore); - fl_deactivate_object(fd_form_spell_check->replace); - fl_deactivate_object(fd_form_spell_check->stop); - fl_deactivate_object(fd_form_spell_check->input); - fl_deactivate_object(fd_form_spell_check->browser); - fl_set_object_lcol(fd_form_spell_check->insert, FL_INACTIVE); - fl_set_object_lcol(fd_form_spell_check->accept, FL_INACTIVE); - fl_set_object_lcol(fd_form_spell_check->ignore, FL_INACTIVE); - fl_set_object_lcol(fd_form_spell_check->replace, FL_INACTIVE); - fl_set_object_lcol(fd_form_spell_check->stop, FL_INACTIVE); - fl_set_object_lcol(fd_form_spell_check->input, FL_INACTIVE); - fl_set_object_lcol(fd_form_spell_check->browser, FL_INACTIVE); - - // activate options and start - fl_activate_object(fd_form_spell_check->options); - fl_activate_object(fd_form_spell_check->start); - fl_set_object_lcol(fd_form_spell_check->options, FL_BLACK); - fl_set_object_lcol(fd_form_spell_check->start, FL_BLACK); - - // if RunSpellChecker returns false quit spellchecker - if (!ret) break; - } - if (obj == fd_form_spell_check->done) break; - } - fl_hide_form(fd_form_spell_check->form_spell_check); - bv->endOfSpellCheck(); - return; -} - - -// Perform a spell session -namespace { - -bool RunSpellChecker(BufferView * bv) -{ - isp_result * result; - int newvalue; - FL_OBJECT * obj; - -#ifdef USE_PSPELL - string tmp = (lyxrc.isp_use_alt_lang) ? - lyxrc.isp_alt_lang : bv->buffer()->params.language->code(); -#else - string tmp = (lyxrc.isp_use_alt_lang) ? - lyxrc.isp_alt_lang : bv->buffer()->params.language->lang(); -#endif - bool rtl = false; - if (lyxrc.isp_use_alt_lang) { - Language const * lang = languages.getLanguage(tmp); - if (lang) - rtl = lang->RightToLeft(); - } else - rtl = bv->buffer()->params.language->RightToLeft(); - - int oldval = 0; /* used for updating slider only when needed */ - float newval = 0.0; - - /* create ispell process */ - init_spell_checker(bv->buffer()->params, tmp); - - if (spell_error != 0) { - fl_show_message(_(spell_error), "", ""); - sc_clean_up_after_error(); - return false; - } - - unsigned int word_count = 0; - - while (true) { - string const word = bv->nextWord(newval); - if (word.empty()) break; - ++word_count; - - // Update slider if and only if value has changed - newvalue = int(100.0*newval); - if (newvalue!= oldval) { - oldval = newvalue; - fl_set_slider_value(fd_form_spell_check->slider, oldval); - } - - if (word_count%1000 == 0) { - obj = fl_check_forms(); - if (obj == fd_form_spell_check->stop) { - close_spell_checker(); - return true; - } - if (obj == fd_form_spell_check->done) { - close_spell_checker(); - return false; - } - } - - result = sc_check_word(word); - if (!sc_still_alive()) { - delete result; - break; - } - - switch (result->flag) { - case ISP_UNKNOWN: - case ISP_MISSED: - { - bv->selectLastWord(); - if (rtl) { - string tmp = word; - reverse(tmp.begin(),tmp.end()); - fl_set_object_label(fd_form_spell_check->text, tmp.c_str()); - } else - fl_set_object_label(fd_form_spell_check->text, word.c_str()); - fl_set_input(fd_form_spell_check->input, word.c_str()); - fl_clear_browser(fd_form_spell_check->browser); - const char * w; - while ((w = result->next_miss()) != 0) { - if (rtl) { - string tmp = w; - reverse(tmp.begin(),tmp.end()); - fl_add_browser_line(fd_form_spell_check->browser, tmp.c_str()); - } else - fl_add_browser_line(fd_form_spell_check->browser, w); - } - - int clickline = -1; - while (true) { - obj = fl_do_forms(); - if (obj == fd_form_spell_check->insert) { - sc_insert_word(word); - break; - } - if (obj == fd_form_spell_check->accept) { - sc_accept_word(word); - break; - } - if (obj == fd_form_spell_check->ignore) { - break; - } - if (obj == fd_form_spell_check->replace || - obj == fd_form_spell_check->input) { - sc_store_replacement(word, fl_get_input(fd_form_spell_check->input)); - bv->replaceWord(fl_get_input(fd_form_spell_check->input)); - break; - } - if (obj == fd_form_spell_check->browser) { - // implements double click in the browser window. - // sent to lyx@via by Mark Burton - if (clickline == - fl_get_browser(fd_form_spell_check->browser)) { - sc_store_replacement(word, fl_get_input(fd_form_spell_check->input)); - bv->replaceWord(fl_get_input(fd_form_spell_check->input)); - break; - } - clickline = fl_get_browser(fd_form_spell_check->browser); - /// Why not use - /// fl_set_input(fd_form_spell_check->input, result->misses[clickline-1]); ? - if (rtl) { - string tmp = fl_get_browser_line(fd_form_spell_check->browser, - clickline); - reverse(tmp.begin(),tmp.end()); - fl_set_input(fd_form_spell_check->input, tmp.c_str()); - } else - fl_set_input(fd_form_spell_check->input, - fl_get_browser_line(fd_form_spell_check->browser, - clickline)); - } - if (obj == fd_form_spell_check->stop) { - delete result; - close_spell_checker(); - return true; - } - - if (obj == fd_form_spell_check->done) { - delete result; - close_spell_checker(); - return false; - } - } - } - default: - delete result; - } - } - - if (sc_still_alive()) { - close_spell_checker(); - string word_msg(tostr(word_count)); - if (word_count != 1) { - word_msg += _(" words checked."); - } else { - word_msg += _(" word checked."); - } - fl_show_message("", _("Spellchecking completed!"), - word_msg.c_str()); - return false; - } else { - fl_show_message(_("The spell checker has died for some reason.\n" - "Maybe it has been killed."), "", ""); - sc_clean_up_after_error(); - return true; - } -} - -} // namespace anon - -#ifdef WITH_WARNINGS -#warning should go somewhere more sensible -#endif -void sigchldhandler(pid_t pid, int * status) -{ -#ifndef USE_PSPELL - if (isp_pid > 0) - if (pid == isp_pid) { - isp_pid= -1; - fcntl(isp_fd, F_SETFL, O_NONBLOCK); /* set the file descriptor - to nonblocking so we can - continue */ - } -#endif - sigchldchecker(pid, status); -} - - diff --git a/src/spellchecker.h b/src/spellchecker.h deleted file mode 100644 index e8de0f4461..0000000000 --- a/src/spellchecker.h +++ /dev/null @@ -1,27 +0,0 @@ -// -*- C++ -*- -/* This file is part of - * ====================================================== - * - * LyX, The Document Processor - * - * Copyright 1995 Matthias Ettrich - * Copyright 1995-2001 The LyX Team. - * - * ====================================================== */ - -#ifndef SPELLCHECKER_H -#define SPELLCHECKER_H - -#ifdef __GNUG__ -#pragma interface -#endif - -/* These functions are defined in lyx_cb.C */ - -class BufferView; - -/** This function has to be implemented by the spell checker. - It will show the spellcheker form*/ -void ShowSpellChecker(BufferView *); - -#endif -- 2.39.5