]> git.lyx.org Git - features.git/blob - src/frontends/controllers/ControlSpellchecker.C
non-templated tostr in separate files
[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 std::endl;
37
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::error(_("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::error(_("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         if (count_ != 1)
225                 message = bformat(_("%1$s words checked."), tostr(count_));
226         else
227                 message = _("One word checked.");
228
229         view().hide();
230         Alert::information(_("Spell-checking is complete"), message);
231 }
232
233
234 void ControlSpellchecker::replace(string const & replacement)
235 {
236         bufferview()->replaceWord(replacement);
237         // fix up the count
238         --count_;
239         check();
240 }
241
242
243 void ControlSpellchecker::replaceAll(string const & replacement)
244 {
245         // TODO: add to list
246         replace(replacement);
247 }
248
249
250 void ControlSpellchecker::insert()
251 {
252         speller_->insert(word_);
253         check();
254 }
255
256
257 string const ControlSpellchecker::getSuggestion() const
258 {
259         return speller_->nextMiss();
260 }
261
262
263 string const ControlSpellchecker::getWord() const
264 {
265         return word_.word();
266 }
267
268
269 void ControlSpellchecker::ignoreAll()
270 {
271         speller_->accept(word_);
272         check();
273 }
274
275