]> git.lyx.org Git - features.git/blob - src/frontends/controllers/ControlSpellchecker.C
two patches from john
[features.git] / src / frontends / controllers / ControlSpellchecker.C
1 /* This file is part of
2  * ====================================================== 
3  *
4  *           LyX, The Document Processor
5  *
6  *           Copyright 2001 The LyX Team.
7  *
8  * ======================================================
9  *
10  * \file ControlSpellchecker.C
11  * \author Edwin Leuven <leuven@fee.uva.nl>
12  */
13
14 #include <config.h>
15
16 #ifdef __GNUG__
17 #pragma implementation
18 #endif
19
20 #include <sys/types.h> // needed by <sys/select.h> at least on freebsd
21
22 #ifdef HAVE_SYS_SELECT_H
23 # ifdef HAVE_STRINGS_H
24    // <strings.h> is needed at least on AIX because FD_ZERO uses bzero().
25    // BUT we cannot include both string.h and strings.h on Irix 6.5 :(
26 #  ifdef _AIX
27 #   include <strings.h>
28 #  endif
29 # endif
30 #include <sys/select.h>
31 #endif
32
33 #include "buffer.h"
34 #include "lyxrc.h"
35 #include "BufferView.h"
36 #include "LyXView.h" 
37 #include "lyxtext.h"
38 #include "gettext.h"
39 #include "support/lstrings.h"
40 #include "language.h"
41
42 #include "ViewBase.h"
43 #include "ButtonControllerBase.h"
44 #include "ControlSpellchecker.h"
45 #include "Dialogs.h"
46 #include "Liason.h"
47
48 # include "sp_ispell.h"
49 #ifdef USE_PSPELL
50 # include "sp_pspell.h"
51 #endif
52
53 #include "debug.h"
54
55 using SigC::slot;
56
57 ControlSpellchecker::ControlSpellchecker(LyXView & lv, Dialogs & d)
58         : ControlDialogBD(lv, d),
59           rtl_(false), newval_(0.0), oldval_(0), newvalue_(0), count_(0),
60           stop_(false), result_(SpellBase::ISP_OK), speller_(0)
61 {
62         d_.showSpellchecker.connect(SigC::slot(this, &ControlSpellchecker::show));
63 }
64
65
66 void ControlSpellchecker::setParams()
67 {
68         if (!speller_) {
69                 // create spell object
70                 string tmp;
71 #ifdef USE_PSPELL
72                 if (lyxrc.use_pspell) {
73                         tmp = (lyxrc.isp_use_alt_lang) ?
74                                 lyxrc.isp_alt_lang : lv_.buffer()->params.language->code();
75                         
76                         speller_ = new PSpell(lv_.view()->buffer()->params, tmp);
77                 } else {
78 #endif
79                         tmp = (lyxrc.isp_use_alt_lang) ?
80                                 lyxrc.isp_alt_lang : lv_.buffer()->params.language->lang();
81                         
82                         speller_ = new ISpell(lv_.view()->buffer()->params, tmp);
83 #ifdef USE_PSPELL
84                 }
85 #endif
86         
87                 if (lyxrc.isp_use_alt_lang) {
88                         Language const * lang = languages.getLanguage(tmp);
89                         if (lang)
90                                 rtl_ = lang->RightToLeft();
91                 } else {
92                         rtl_ = lv_.buffer()->params.language->RightToLeft();
93                 }
94                 
95                 if (speller_->error() != 0) {
96 #if 0
97                         message_ = speller_->error();
98                         // show error message
99                         view().partialUpdate(2);
100 #endif
101                         clearParams();
102                         return;
103                 }
104         }
105 }
106
107
108 void ControlSpellchecker::check()
109 {
110         result_ = SpellBase::ISP_OK;
111         stop_ = false;
112         
113         // clear any old selection
114         LyXText * text = lv_.view()->getLyXText();
115         lv_.view()->toggleSelection(true);
116         lv_.view()->update(text, BufferView::SELECT);
117  
118         while ((result_==SpellBase::ISP_OK || result_==SpellBase::ISP_IGNORE) &&
119                !stop_) {
120                 word_ = lv_.view()->nextWord(newval_);
121                 
122                 if (word_.empty()) {
123                         clearParams();
124                         break;
125                 }
126                 
127                 ++count_;
128
129                 // Update slider if and only if value has changed
130                 newvalue_ = int(100.0*newval_);
131                 if (newvalue_!= oldval_) {
132                         oldval_ = newvalue_;
133                         // set progress bar
134                         view().partialUpdate(0);
135                 }
136                 
137                 if (!speller_->alive()) clearParams();
138                 
139                 result_ = speller_->check(word_);
140         }
141         
142         if (!stop_ && !word_.empty())
143                 lv_.view()->selectLastWord();
144
145         // set suggestions
146         if (result_!=SpellBase::ISP_OK && result_!=SpellBase::ISP_IGNORE) {
147                 view().partialUpdate(1);
148         }
149 }
150
151
152 void ControlSpellchecker::replace(string const & replacement)
153 {
154         lv_.view()->replaceWord(replacement);
155         check();
156 }
157
158
159 void ControlSpellchecker::replaceAll(string const & replacement)
160 {
161         // TODO: add to list
162         replace(replacement);
163 }
164
165
166 void ControlSpellchecker::insert()
167 {
168         speller_->insert(word_);
169         check();
170 }
171
172
173 string ControlSpellchecker::getSuggestion()
174 {
175         // this is needed because string tmp = nextmiss()
176         // segfaults when nextMiss is 0
177         string tmp;
178         char const * w = speller_->nextMiss();
179         
180         if (w!=0) {
181                 tmp = w;
182                 if (rtl_) std::reverse(tmp.begin(), tmp.end());
183         }
184         
185         return tmp;
186 }
187
188
189 string ControlSpellchecker::getWord()
190 {
191         string tmp = word_;
192         if (rtl_) std::reverse(tmp.begin(), tmp.end());
193         return tmp;
194 }
195
196
197 void ControlSpellchecker::ignoreAll()
198 {
199         speller_->accept(word_);
200         check();
201 }
202
203
204 void ControlSpellchecker::stop()
205 {
206         stop_ = true;
207         lv_.view()->endOfSpellCheck();
208 }
209
210
211 void ControlSpellchecker::clearParams()
212 {
213         if (!speller_) return;
214         
215         if (speller_->alive()) {
216                 speller_->close();
217                 message_ = tostr(count_);
218                 if (count_ != 1) {
219                         message_ += _(" words checked.");
220
221                 } else {
222                         message_ += _(" word checked.");
223                 }
224                 message_ = "\n" + message_;
225                 message_ = _("Spellchecking completed! ") + message_;
226
227         } else {
228                 message_ = speller_->error();
229                 speller_->cleanUp();
230                 if (message_.empty())
231                     message_ = _("The spell checker has died for some reason.\n"
232                                  "Maybe it has been killed.");
233
234                 // make sure that the dialog is not launched
235                 emergency_exit_ = true;
236         }
237         
238         delete speller_;
239         
240         lv_.view()->endOfSpellCheck();
241
242         // show closing message if any words were checked.
243         if (count_ > 0)
244                 view().partialUpdate(2);
245
246         // reset values to initial
247         rtl_ = false;
248         word_.erase();
249         newval_ = 0.0;
250         oldval_ = 0;
251         newvalue_ = 0;
252         count_ = 0;
253         message_.erase();
254         stop_ = false;
255         result_ = SpellBase::ISP_OK;
256         speller_ = 0;
257 }
258
259
260 void ControlSpellchecker::options()
261 {
262         lv_.getDialogs()->showSpellcheckerPreferences();
263 }