]> git.lyx.org Git - lyx.git/blob - src/frontends/controllers/ControlSpellchecker.C
Support for new GNU aspell library. Final pspell fix ups.
[lyx.git] / src / frontends / controllers / ControlSpellchecker.C
1 /**
2  * \file ControlSpellchecker.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Edwin Leuven
7  *
8  * Full author contact details are available in file CREDITS
9  */
10
11 #include <config.h>
12
13
14 #include "ControlSpellchecker.h"
15 #include "ViewBase.h"
16 #include "buffer.h"
17 #include "BufferView.h"
18 #include "gettext.h"
19 #include "language.h"
20 #include "lyxrc.h"
21 #include "lyxtext.h"
22 #include "debug.h"
23
24 #include "ispell.h"
25 #ifdef USE_PSPELL
26 # include "pspell.h"
27 #else
28 #ifdef USE_ASPELL
29 # include "aspell_local.h"
30 #endif
31 #endif
32
33 #include "frontends/Alert.h"
34
35 #include "BoostFormat.h"
36
37 using std::endl;
38
39 ControlSpellchecker::ControlSpellchecker(LyXView & lv, Dialogs & d)
40         : ControlDialogBD(lv, d),
41           newval_(0.0), oldval_(0), newvalue_(0), count_(0)
42 {}
43
44
45 ControlSpellchecker::~ControlSpellchecker()
46 {}
47
48
49 void ControlSpellchecker::setParams()
50 {
51         lyxerr[Debug::GUI] << "spell setParams" << endl;
52         startSession();
53 }
54
55
56 void ControlSpellchecker::clearParams()
57 {
58         lyxerr[Debug::GUI] << "spell clearParams" << endl;
59         endSession();
60 }
61
62 namespace {
63
64 SpellBase * getSpeller(BufferParams const & bp)
65 {
66         string lang = (lyxrc.isp_use_alt_lang)
67                       ? lyxrc.isp_alt_lang
68                       : bp.language->code();
69
70 #ifdef USE_ASPELL
71         if (lyxrc.use_spell_lib)
72                 return new ASpell(bp, lang);
73 #endif
74 #ifdef USE_PSPELL
75         if (lyxrc.use_spell_lib)
76                 return new PSpell(bp, lang);
77 #endif
78
79         lang = (lyxrc.isp_use_alt_lang) ?
80                 lyxrc.isp_alt_lang : bp.language->lang();
81
82         return new ISpell(bp, lang);
83 }
84
85 }
86
87 void ControlSpellchecker::startSession()
88 {
89         lyxerr[Debug::GUI] << "spell startSession" << endl;
90
91         if (speller_.get()) {
92                 lyxerr[Debug::GUI] << "startSession: speller exists" << endl;
93                 speller_.reset(0);
94                 return;
95         }
96
97         speller_.reset(getSpeller(buffer()->params));
98
99         // reset values to initial
100         newval_ = 0.0;
101         oldval_ = 0;
102         newvalue_ = 0;
103         count_ = 0;
104         emergency_exit_ = false;
105
106         // start off the check
107         if (speller_->error().empty()) {
108                 check();
109                 return;
110         }
111
112         emergency_exit_ = true;
113         string message = speller_->error();
114         if (message.empty())
115                 message = _("The spell-checker could not be started.\n"
116                          "Maybe it is mis-configured.");
117
118         Alert::alert(_("The spell-checker has failed"), message);
119         speller_.reset(0);
120 }
121
122
123 void ControlSpellchecker::endSession()
124 {
125         lyxerr[Debug::GUI] << "spell endSession" << endl;
126
127         bufferview()->endOfSpellCheck();
128
129         emergency_exit_ = true;
130
131         if (!speller_.get()) {
132                 lyxerr[Debug::GUI] << "endSession with no speller" << endl;
133                 return;
134         }
135
136         speller_.reset(0);
137 }
138
139
140 void ControlSpellchecker::check()
141 {
142         lyxerr[Debug::GUI] << "spell check a word" << endl;
143
144         SpellBase::Result res = SpellBase::OK;
145
146         // clear any old selection
147         LyXText * text = bufferview()->getLyXText();
148         bufferview()->toggleSelection(true);
149         bufferview()->update(text, BufferView::SELECT);
150
151         while ((res == SpellBase::OK || res == SpellBase::IGNORE)) {
152                 word_ = bufferview()->nextWord(newval_);
153
154                 // end of document
155                 if (word_.word().empty())
156                         break;
157
158                 ++count_;
159
160                 // Update slider if and only if value has changed
161                 newvalue_ = int(100.0 * newval_);
162                 if (newvalue_!= oldval_) {
163                         lyxerr[Debug::GUI] << "Updating spell progress." << endl;
164                         oldval_ = newvalue_;
165                         // set progress bar
166                         view().partialUpdate(SPELL_PROGRESSED);
167                 }
168
169                 // speller might be dead ...
170                 if (!checkAlive())
171                         return;
172
173                 res = speller_->check(word_);
174
175                 // ... or it might just be reporting an error
176                 if (!checkAlive())
177                         return;
178         }
179
180         lyxerr[Debug::GUI] << "Found word \"" << word_.word() << "\"" << endl;
181
182         if (!word_.word().empty()) {
183                 bufferview()->selectLastWord();
184         } else {
185                 showSummary();
186                 endSession();
187                 return;
188         }
189
190         // set suggestions
191         if (res != SpellBase::OK && res != SpellBase::IGNORE) {
192                 lyxerr[Debug::GUI] << "Found a word needing checking." << endl;
193                 view().partialUpdate(SPELL_FOUND_WORD);
194         }
195 }
196
197
198 bool ControlSpellchecker::checkAlive()
199 {
200         if (speller_->alive() && speller_->error().empty())
201                 return true;
202
203         string message = speller_->error();
204         if (message.empty())
205                 message = _("The spell-checker has died for some reason.\n"
206                          "Maybe it has been killed.");
207
208         view().hide();
209         speller_.reset(0);
210
211         Alert::alert(_("The spell-checker has failed"), message);
212         return false;
213 }
214
215
216 void ControlSpellchecker::showSummary()
217 {
218         if (!checkAlive() || count_ == 0) {
219                 view().hide();
220                 return;
221         }
222
223         string message;
224
225 #if USE_BOOST_FORMAT
226         if (count_ != 1) {
227                 boost::format fmter(_("%1$d words checked."));
228                 fmter % count_;
229                 message += fmter.str();
230         } else {
231                 message += _("One word checked.");
232         }
233 #else
234         if (count_ != 1) {
235                 message += tostr(count_) + _(" words checked.");
236         } else {
237                 message = _("One word checked.");
238         }
239 #endif
240
241         view().hide();
242         Alert::alert(_("Spell-checking is complete"), message);
243 }
244
245
246 void ControlSpellchecker::replace(string const & replacement)
247 {
248         bufferview()->replaceWord(replacement);
249         // fix up the count
250         --count_;
251         check();
252 }
253
254
255 void ControlSpellchecker::replaceAll(string const & replacement)
256 {
257         // TODO: add to list
258         replace(replacement);
259 }
260
261
262 void ControlSpellchecker::insert()
263 {
264         speller_->insert(word_);
265         check();
266 }
267
268
269 string const ControlSpellchecker::getSuggestion() const
270 {
271         return speller_->nextMiss();
272 }
273
274
275 string const ControlSpellchecker::getWord() const
276 {
277         return word_.word();
278 }
279
280
281 void ControlSpellchecker::ignoreAll()
282 {
283         speller_->accept(word_);
284         check();
285 }
286
287