]> git.lyx.org Git - lyx.git/blob - src/EnchantChecker.cpp
Avoid full metrics computation with Update:FitCursor
[lyx.git] / src / EnchantChecker.cpp
1 /**
2  * \file EnchantChecker.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Caolán McNamara
7  * \author Jürgen Spitzmüller
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include <enchant++.h>
15
16 #include "EnchantChecker.h"
17 #include "LyXRC.h"
18 #include "WordLangTuple.h"
19
20 #include "support/lassert.h"
21 #include "support/debug.h"
22 #include "support/docstring_list.h"
23
24 #include <map>
25 #include <string>
26
27 using namespace std;
28
29 namespace lyx {
30
31 namespace {
32
33 enchant::Broker & broker()
34 {
35 #ifdef HAVE_ENCHANT2
36         static enchant::Broker thebroker;
37         return thebroker;
38 #else
39         return *enchant::Broker::instance();
40 #endif
41 }
42
43
44 struct Speller {
45         enchant::Dict * speller;
46 };
47
48 typedef map<string, Speller> Spellers;
49
50 } // namespace
51
52 struct EnchantChecker::Private
53 {
54         Private()
55         {}
56
57         ~Private();
58
59         /// add a speller of the given language
60         enchant::Dict * addSpeller(string const & lang);
61
62         ///
63         enchant::Dict * speller(string const & lang);
64
65         /// the spellers
66         Spellers spellers_;
67 };
68
69
70 EnchantChecker::Private::~Private()
71 {
72         Spellers::iterator it = spellers_.begin();
73         Spellers::iterator end = spellers_.end();
74
75         for (; it != end; ++it)
76                 delete it->second.speller;
77 }
78
79
80 enchant::Dict * EnchantChecker::Private::addSpeller(string const & lang)
81 {
82         Speller m;
83
84         try {
85                 LYXERR(Debug::FILES, "request enchant speller for language " << lang);
86                 m.speller = broker().request_dict(lang);
87         }
88         catch (enchant::Exception & e) {
89                 // FIXME error handling?
90                 const char * what = e.what();
91                 LYXERR(Debug::FILES, "cannot add enchant speller: " <<
92                            ((what && *what) ? what : "unspecified enchant exception in request_dict()"));
93                 m.speller = nullptr;
94         }
95         spellers_[lang] = m;
96         return m.speller;
97 }
98
99
100 enchant::Dict * EnchantChecker::Private::speller(string const & lang)
101 {
102         Spellers::iterator it = spellers_.find(lang);
103         if (it != spellers_.end())
104                 return it->second.speller;
105
106         return addSpeller(lang);
107 }
108
109
110 EnchantChecker::EnchantChecker()
111         : d(new Private)
112 {}
113
114
115 EnchantChecker::~EnchantChecker()
116 {
117         delete d;
118 }
119
120
121 SpellChecker::Result EnchantChecker::check(WordLangTuple const & word,
122         std::vector<WordLangTuple> const & docdict)
123 {
124         enchant::Dict * m = d->speller(word.lang()->code());
125
126         if (!m)
127                 return NO_DICTIONARY;
128
129         if (word.word().empty())
130                 return WORD_OK;
131
132         string utf8word = to_utf8(word.word());
133
134         if (m->check(utf8word))
135                 return WORD_OK;
136
137         vector<WordLangTuple>::const_iterator it = docdict.begin();
138         for (; it != docdict.end(); ++it) {
139                 if (it->lang()->code() != word.lang()->code())
140                         continue;
141                 if (it->word() == word.word())
142                         return DOCUMENT_LEARNED_WORD;
143         }
144
145         return UNKNOWN_WORD;
146 }
147
148
149 void EnchantChecker::advanceChangeNumber()
150 {
151         nextChangeNumber();
152 }
153
154
155 void EnchantChecker::insert(WordLangTuple const & word)
156 {
157         enchant::Dict * m = d->speller(word.lang()->code());
158         if (m) {
159                 m->add(to_utf8(word.word()));
160                 advanceChangeNumber();
161         }
162 }
163
164
165 void EnchantChecker::remove(WordLangTuple const & word)
166 {
167         enchant::Dict * m = d->speller(word.lang()->code());
168         if (m) {
169                 m->remove(to_utf8(word.word()));
170                 advanceChangeNumber();
171         }
172 }
173
174
175 void EnchantChecker::accept(WordLangTuple const & word)
176 {
177         enchant::Dict * m = d->speller(word.lang()->code());
178         if (m) {
179                 m->add_to_session(to_utf8(word.word()));
180                 advanceChangeNumber();
181         }
182 }
183
184
185 void EnchantChecker::suggest(WordLangTuple const & wl,
186         docstring_list & suggestions)
187 {
188         suggestions.clear();
189         enchant::Dict * m = d->speller(wl.lang()->code());
190
191         if (!m)
192                 return;
193
194         string utf8word = to_utf8(wl.word());
195
196         vector<string> suggs = m->suggest(utf8word);
197         vector<string>::const_iterator it = suggs.begin();
198
199         for (; it != suggs.end(); ++it)
200                 suggestions.push_back(from_utf8(*it));
201 }
202
203
204 bool EnchantChecker::hasDictionary(Language const * lang) const
205 {
206         if (!lang)
207                 return false;
208         return broker().dict_exists(lang->code());
209 }
210
211
212 int EnchantChecker::numDictionaries() const
213 {
214         return d->spellers_.size();
215 }
216
217
218 docstring const EnchantChecker::error()
219 {
220         return docstring();
221 }
222
223
224 } // namespace lyx