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