1 /*
2 * This file is part of SpellChecker plugin for Code::Blocks Studio
3 * Copyright (C) 2009 Daniel Anselmi
4 *
5 * SpellChecker plugin is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * SpellChecker plugin is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with SpellChecker. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19 #include "SpellCheckerConfig.h"
20 #include "SpellCheckerPlugin.h"
21 #include <sdk.h> // Code::Blocks SDK
22 #ifndef CB_PRECOMP
23 #include <wx/dir.h>
24 #include <logmanager.h>
25 #include <macrosmanager.h>
26 #endif
27
28 #include <configmanager.h>
29
30 #define CFG_SPELLCHECK_ENABLE_ONLINE_CHECK _T("/SpellChecker/EnableOnlineChecker")
31 #define CFG_SPELLCHECK_SPELL_TOOLTIPS_CHECK _T("/SpellChecker/SpellTooltips")
32 #define CFG_SPELLCHECK_THESAURUS_TOOLTIPS_CHECK _T("/SpellChecker/ThesTooltips")
33 #define CFG_SPELLCHECK_DICTIONARY_NAME _T("/SpellChecker/Dictionary")
34 #define CFG_SPELLCHECK_DICTIONARY_PATH _T("/SpellChecker/DictPath")
35 #define CFG_SPELLCHECK_THESAURI_PATH _T("/SpellChecker/ThesPath")
36 #define CFG_SPELLCHECK_BITMAPS_PATH _T("/SpellChecker/BitmPath")
37
SpellCheckerConfig(SpellCheckerPlugin * plugin)38 SpellCheckerConfig::SpellCheckerConfig(SpellCheckerPlugin *plugin)
39 ://m_DictionaryPath(plugin->GetDic),
40 selectedDictionary(-1),
41 m_pPlugin(plugin)
42 {
43 Load();
44 ScanForDictionaries();
45 PopulateLanguageNamesMap();
46 }
47
~SpellCheckerConfig()48 SpellCheckerConfig::~SpellCheckerConfig()
49 {
50 //dtor
51 }
52
GetEnableOnlineChecker()53 bool SpellCheckerConfig::GetEnableOnlineChecker()
54 {
55 return m_EnableOnlineChecker;
56 }
57
SetEnableOnlineChecker(bool val)58 void SpellCheckerConfig::SetEnableOnlineChecker(bool val)
59 {
60 m_EnableOnlineChecker = val;
61 }
62
GetEnableSpellTooltips()63 bool SpellCheckerConfig::GetEnableSpellTooltips()
64 {
65 return m_EnableSpellTooltips;
66 }
67
SetEnableSpellTooltips(bool val)68 void SpellCheckerConfig::SetEnableSpellTooltips(bool val)
69 {
70 m_EnableSpellTooltips = val;
71 }
72
GetEnableThesaurusTooltips()73 bool SpellCheckerConfig::GetEnableThesaurusTooltips()
74 {
75 return m_EnableThesaurusTooltips;
76 }
77
SetEnableThesaurusTooltips(bool val)78 void SpellCheckerConfig::SetEnableThesaurusTooltips(bool val)
79 {
80 m_EnableThesaurusTooltips = val;
81 }
82
GetDictionaryName() const83 const wxString SpellCheckerConfig::GetDictionaryName()const
84 {
85 return m_strDictionaryName;
86 }
87
SetDictionaryName(wxString val)88 void SpellCheckerConfig::SetDictionaryName(wxString val)
89 {
90 m_strDictionaryName = val;
91 }
92
GetSelectedDictionaryNumber() const93 int SpellCheckerConfig::GetSelectedDictionaryNumber()const
94 {
95 return selectedDictionary;
96 }
97
ScanForDictionaries()98 void SpellCheckerConfig::ScanForDictionaries()
99 {
100 ScanForDictionaries(GetDictionaryPath());
101 }
102
ScanForDictionaries(const wxString & path)103 void SpellCheckerConfig::ScanForDictionaries(const wxString &path)
104 {
105 m_dictionaries.clear();
106 selectedDictionary = wxNOT_FOUND;
107 //wxString filespec(_T("??_??.dic"));
108 wxString filespec(_T("*.dic"));
109
110 wxDir dir;
111 if ( dir.Open(path) )
112 {
113 wxString strfilename;
114 bool cont = dir.GetFirst(&strfilename, filespec, wxDIR_FILES);
115 while ( cont )
116 {
117 wxFileName fname(strfilename);
118 wxString afffilename = path + wxFileName::GetPathSeparator() + fname.GetName() + _T(".aff");
119 if ( wxFileName::FileExists(afffilename) )
120 {
121 if ( fname.GetName() == m_strDictionaryName )
122 {
123 Manager::Get()->GetLogManager()->DebugLog(_T("Selected dictionary: ") + fname.GetName());
124 selectedDictionary = m_dictionaries.size();
125 }
126 Manager::Get()->GetLogManager()->DebugLog(_T("Found dictionary: ") + fname.GetName());
127 m_dictionaries.push_back(fname.GetName());
128
129 }
130 cont = dir.GetNext(&strfilename);
131 }
132 }
133 else
134 Manager::Get()->GetLogManager()->DebugLog(_T("Could not open path to dictionaries: ") + path);
135
136 // disable online checker if there are no dictionaries found
137 if (selectedDictionary == wxNOT_FOUND)
138 {
139 m_EnableOnlineChecker = false;
140 }
141 }
142
GetPossibleDictionaries() const143 const std::vector<wxString> &SpellCheckerConfig::GetPossibleDictionaries()const
144 {
145 return m_dictionaries;
146 }
147
GetDictionaryPath() const148 const wxString SpellCheckerConfig::GetDictionaryPath()const
149 {
150 wxString dictPath = m_DictPath;
151 Manager::Get()->GetMacrosManager()->ReplaceEnvVars(dictPath);
152 return dictPath;
153 }
154
GetThesaurusPath() const155 const wxString SpellCheckerConfig::GetThesaurusPath()const
156 {
157 wxString thesPath = m_ThesPath;
158 Manager::Get()->GetMacrosManager()->ReplaceEnvVars(thesPath);
159 return thesPath;
160 }
161
DetectDictionaryPath()162 void SpellCheckerConfig::DetectDictionaryPath()
163 {
164 wxArrayString dictPaths;
165 dictPaths.Add(m_DictPath);
166 Manager::Get()->GetMacrosManager()->ReplaceEnvVars(dictPaths[0]);
167 if (platform::windows)
168 {
169 wxString programs = wxT("C:\\Program Files");
170 wxGetEnv(wxT("ProgramFiles"), &programs);
171 dictPaths.Add(programs + wxT("\\Mozilla Firefox\\dictionaries"));
172 dictPaths.Add(programs + wxT("\\Mozilla\\Firefox\\dictionaries"));
173 dictPaths.Add(programs + wxT("\\Mozilla Thunderbird\\dictionaries"));
174 dictPaths.Add(programs + wxT("\\Mozilla\\Thunderbird\\dictionaries"));
175 wxString libreOffice = wxFindFirstFile(programs + wxT("\\*LibreOffice*"), wxDIR);
176 wxString openOffice = wxFindFirstFile(programs + wxT("\\*OpenOffice*"), wxDIR);
177 wxArrayString langs = GetArrayFromString(wxT("en;fr;es;de"));
178 for (size_t i = 0; i < langs.GetCount(); ++i)
179 {
180 if (!libreOffice.IsEmpty())
181 dictPaths.Add(libreOffice + wxT("\\share\\extensions\\dict-") + langs[i]);
182 if (!openOffice.IsEmpty())
183 dictPaths.Add(openOffice + wxT("\\share\\extensions\\dict-") + langs[i]);
184 }
185 }
186 else
187 {
188 dictPaths.Add(wxT("/usr/share/hunspell"));
189 dictPaths.Add(wxT("/usr/share/myspell/dicts"));
190 dictPaths.Add(wxT("/usr/share/myspell"));
191 }
192 dictPaths.Add(m_pPlugin->GetOnlineCheckerConfigPath());
193 for (size_t i = 0; i < dictPaths.GetCount(); ++i)
194 {
195 if ( wxDirExists(dictPaths[i])
196 && !wxFindFirstFile(dictPaths[i] + wxFILE_SEP_PATH + wxT("*.dic"), wxFILE).IsEmpty() )
197 {
198 if (i != 0)
199 m_DictPath = dictPaths[i];
200 Manager::Get()->GetLogManager()->DebugLog(_T("Detected dict path: ") + m_DictPath);
201 break;
202 }
203 }
204 }
205
DetectThesaurusPath()206 void SpellCheckerConfig::DetectThesaurusPath()
207 {
208 wxArrayString thesPaths;
209 thesPaths.Add(m_ThesPath);
210 Manager::Get()->GetMacrosManager()->ReplaceEnvVars(thesPaths[0]);
211 if (platform::windows)
212 {
213 wxString programs = wxT("C:\\Program Files");
214 wxGetEnv(wxT("ProgramFiles"), &programs);
215 wxString libreOffice = wxFindFirstFile(programs + wxT("\\*LibreOffice*"), wxDIR);
216 wxString openOffice = wxFindFirstFile(programs + wxT("\\*OpenOffice*"), wxDIR);
217 wxArrayString langs = GetArrayFromString(wxT("en;fr;es;de"));
218 for (size_t i = 0; i < langs.GetCount(); ++i)
219 {
220 if (!libreOffice.IsEmpty())
221 thesPaths.Add(libreOffice + wxT("\\share\\extensions\\dict-") + langs[i]);
222 if (!openOffice.IsEmpty())
223 thesPaths.Add(openOffice + wxT("\\share\\extensions\\dict-") + langs[i]);
224 }
225 }
226 else
227 {
228 thesPaths.Add(wxT("/usr/share/myspell/dicts"));
229 thesPaths.Add(wxT("/usr/share/mythes"));
230 }
231 thesPaths.Add(m_pPlugin->GetOnlineCheckerConfigPath());
232 for (size_t i = 0; i < thesPaths.GetCount(); ++i)
233 {
234 if ( wxDirExists(thesPaths[i])
235 && !wxFindFirstFile(thesPaths[i] + wxFILE_SEP_PATH + wxT("th*.dat"), wxFILE).IsEmpty() )
236 {
237 if (i != 0)
238 m_ThesPath = thesPaths[i];
239 Manager::Get()->GetLogManager()->DebugLog(_T("Detected thes path: ") + m_ThesPath);
240 break;
241 }
242 }
243 }
244
GetRawDictionaryPath() const245 const wxString SpellCheckerConfig::GetRawDictionaryPath()const
246 {
247 return m_DictPath;
248 }
249
GetRawThesaurusPath() const250 const wxString SpellCheckerConfig::GetRawThesaurusPath()const
251 {
252 return m_ThesPath;
253 }
254
GetRawBitmapPath() const255 const wxString SpellCheckerConfig::GetRawBitmapPath()const
256 {
257 return m_BitmPath;
258 }
259
SetDictionaryPath(const wxString & path)260 void SpellCheckerConfig::SetDictionaryPath(const wxString &path)
261 {
262 m_DictPath = path;
263 }
264
SetThesaurusPath(const wxString & path)265 void SpellCheckerConfig::SetThesaurusPath(const wxString &path)
266 {
267 m_ThesPath = path;
268 }
269
SetBitmapPath(const wxString & path)270 void SpellCheckerConfig::SetBitmapPath(const wxString &path)
271 {
272 m_BitmPath = path;
273 }
274
GetPersonalDictionaryFilename() const275 const wxString SpellCheckerConfig::GetPersonalDictionaryFilename()const
276 {
277 wxString dfile = ConfigManager::LocateDataFile(GetDictionaryName() + _T("_personaldictionary.dic"), sdConfig );
278 if (dfile == _T(""))
279 dfile = ConfigManager::GetFolder(sdConfig) + wxFILE_SEP_PATH + GetDictionaryName() + _T("_personaldictionary.dic");
280 return dfile;
281 }
282
Load()283 void SpellCheckerConfig::Load()
284 {
285 m_EnableOnlineChecker = true;
286 const wxLanguageInfo* langInfo = wxLocale::GetLanguageInfo(wxLANGUAGE_DEFAULT); // current system locale
287 if (langInfo)
288 m_strDictionaryName = langInfo->CanonicalName;
289 if (!m_strDictionaryName.StartsWith(_T("en"))) // default language is English (system designation preferred)
290 m_strDictionaryName = _T("en_US");
291 m_DictPath = m_pPlugin->GetOnlineCheckerConfigPath();
292 m_ThesPath = m_pPlugin->GetOnlineCheckerConfigPath();
293 m_BitmPath = m_pPlugin->GetOnlineCheckerConfigPath();
294 if (ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("editor")))
295 {
296 m_EnableOnlineChecker = cfg->ReadBool(CFG_SPELLCHECK_ENABLE_ONLINE_CHECK, true);
297 m_EnableSpellTooltips = cfg->ReadBool(CFG_SPELLCHECK_SPELL_TOOLTIPS_CHECK, true);
298 m_EnableThesaurusTooltips = cfg->ReadBool(CFG_SPELLCHECK_THESAURUS_TOOLTIPS_CHECK, true);
299 m_strDictionaryName = cfg->Read(CFG_SPELLCHECK_DICTIONARY_NAME, m_strDictionaryName);
300 m_DictPath = cfg->Read(CFG_SPELLCHECK_DICTIONARY_PATH, m_pPlugin->GetOnlineCheckerConfigPath());
301 m_ThesPath = cfg->Read(CFG_SPELLCHECK_THESAURI_PATH, m_pPlugin->GetOnlineCheckerConfigPath());
302 m_BitmPath = cfg->Read(CFG_SPELLCHECK_BITMAPS_PATH, m_pPlugin->GetOnlineCheckerConfigPath());
303 }
304 DetectDictionaryPath();
305 DetectThesaurusPath();
306 }
307
Save()308 void SpellCheckerConfig::Save()
309 {
310 if(ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("editor")))
311 {
312 cfg->Write(CFG_SPELLCHECK_ENABLE_ONLINE_CHECK, m_EnableOnlineChecker);
313 cfg->Write(CFG_SPELLCHECK_SPELL_TOOLTIPS_CHECK, m_EnableSpellTooltips);
314 cfg->Write(CFG_SPELLCHECK_THESAURUS_TOOLTIPS_CHECK, m_EnableThesaurusTooltips);
315 cfg->Write(CFG_SPELLCHECK_DICTIONARY_NAME, m_strDictionaryName);
316 cfg->Write(CFG_SPELLCHECK_DICTIONARY_PATH, m_DictPath);
317 cfg->Write(CFG_SPELLCHECK_THESAURI_PATH, m_ThesPath);
318 cfg->Write(CFG_SPELLCHECK_BITMAPS_PATH, m_BitmPath);
319 }
320 m_pPlugin->ReloadSettings();
321 }
322
PopulateLanguageNamesMap()323 void SpellCheckerConfig::PopulateLanguageNamesMap()
324 {
325 m_LanguageNamesMap[_T("af_ZA")] = _T("Afrikaans (South Africa)");
326 m_LanguageNamesMap[_T("bg_BG")] = _T("Bulgarian (Bulgaria)");
327 m_LanguageNamesMap[_T("ca_ES")] = _T("Catalan (Spain)");
328 m_LanguageNamesMap[_T("cz_CZ")] = _T("Czech (Czech Republic)");
329 m_LanguageNamesMap[_T("cy_GB")] = _T("Welsh (Wales)");
330 m_LanguageNamesMap[_T("da_DK")] = _T("Danish (Denmark)");
331 m_LanguageNamesMap[_T("de_AT")] = _T("German (Austria)");
332 m_LanguageNamesMap[_T("de_CH")] = _T("German (Switzerland)");
333 m_LanguageNamesMap[_T("de_DE")] = _T("German (Germany-orig dict)");
334 m_LanguageNamesMap[_T("de_DE_comb")] =_T("German (Germany-old & neu ortho)");
335 m_LanguageNamesMap[_T("de_DE_neu")] =_T("German (Germany-neu ortho)");
336 m_LanguageNamesMap[_T("el_GR")] = _T("Greek (Greece)");
337 m_LanguageNamesMap[_T("en")] = _T("English");
338 m_LanguageNamesMap[_T("en_AU")] = _T("English (Australia)");
339 m_LanguageNamesMap[_T("en_CA")] = _T("English (Canada)");
340 m_LanguageNamesMap[_T("en_GB")] = _T("English (United Kingdom)");
341 m_LanguageNamesMap[_T("en_NZ")] = _T("English (New Zealand)");
342 m_LanguageNamesMap[_T("en_US")] = _T("English (United States)");
343 m_LanguageNamesMap[_T("en_ZA")] = _T("English (South Africa)");
344 m_LanguageNamesMap[_T("eo_l3")] = _T("Esperanto (Anywhere)");
345 m_LanguageNamesMap[_T("es_ES")] = _T("Spanish (Spain-etal)");
346 m_LanguageNamesMap[_T("es_MX")] = _T("Spanish (Mexico)");
347 m_LanguageNamesMap[_T("fo_FO")] = _T("Faroese (Faroese Islands)");
348 m_LanguageNamesMap[_T("fr_FR")] = _T("French (France)");
349 m_LanguageNamesMap[_T("ga_IE")] = _T("Irish (Ireland)");
350 m_LanguageNamesMap[_T("gd_GB")] = _T("Scottish Gaelic (Scotland)");
351 m_LanguageNamesMap[_T("gl_ES")] = _T("Galician (Spain)");
352 m_LanguageNamesMap[_T("he_IL")] = _T("Hebrew (Israel)");
353 m_LanguageNamesMap[_T("hr_HR")] = _T("Croatian (Croatia)");
354 m_LanguageNamesMap[_T("hu_HU")] = _T("Hungarian (Hungaria)");
355 m_LanguageNamesMap[_T("ia")] =_T("Interligua (x-register)");
356 m_LanguageNamesMap[_T("id_ID")] = _T("Indonesian (Indonesia)");
357 m_LanguageNamesMap[_T("it_IT")] = _T("Italian (Italy)");
358 m_LanguageNamesMap[_T("la")] =_T("Latin (x-register)");
359 m_LanguageNamesMap[_T("lt_LT")] = _T("Lithuanian (Lithuania)");
360 m_LanguageNamesMap[_T("lv_LV")] = _T("Latvian (Latvia)");
361 m_LanguageNamesMap[_T("mg_MG")] = _T("Malagasy (Madagascar)");
362 m_LanguageNamesMap[_T("mi_NZ")] = _T("Maori (New Zealand)");
363 m_LanguageNamesMap[_T("ms_MY")] = _T("Malay (Malaysia)");
364 m_LanguageNamesMap[_T("nb_NO")] = _T("Norwegian Bokmaal (Norway)");
365 m_LanguageNamesMap[_T("nl_NL")] = _T("Dutch (Nederlands)");
366 m_LanguageNamesMap[_T("nn_NO")] = _T("Norwegian Nynorsk (Norway)");
367 m_LanguageNamesMap[_T("ny_MW")] = _T("Chichewa (Malawi)");
368 m_LanguageNamesMap[_T("pl_PL")] = _T("Polish (Poland)");
369 m_LanguageNamesMap[_T("pt_BR")] = _T("Portuguese (Brazil)");
370 m_LanguageNamesMap[_T("pt_PT")] = _T("Portuguese (Portugal)");
371 m_LanguageNamesMap[_T("ro_RO")] = _T("Romanian (Romania)");
372 m_LanguageNamesMap[_T("ru_RU")] = _T("Russian (Russia)");
373 m_LanguageNamesMap[_T("ru_RU_ye")] =_T("Russian ye (Russia)");
374 m_LanguageNamesMap[_T("ru_RU_yo")] =_T("Russian yo (Russia)");
375 m_LanguageNamesMap[_T("rw_RW")] = _T("Kinyarwanda (Rwanda)");
376 m_LanguageNamesMap[_T("sk_SK")] = _T("Slovak (Slovakia)");
377 m_LanguageNamesMap[_T("sl_SI")] = _T("Slovenian (Slovenia)");
378 m_LanguageNamesMap[_T("sv_SW")] = _T("Swedish (Sweden)");
379 m_LanguageNamesMap[_T("sw_KE")] = _T("Swahili (Kenya)");
380 m_LanguageNamesMap[_T("tet_ID")] = _T("Tetum (Indonesia)");
381 m_LanguageNamesMap[_T("tl_PH")] = _T("Tagalog (Philippines)");
382 m_LanguageNamesMap[_T("tn_ZA")] = _T("Tswana (South Africa)");
383 m_LanguageNamesMap[_T("uk_UA")] = _T("Ukrainian (Ukraine)");
384 m_LanguageNamesMap[_T("zu_ZA")] = _T("Zulu (South Africa)");
385 }
386
GetLanguageName(const wxString & language_id)387 wxString SpellCheckerConfig::GetLanguageName(const wxString& language_id)
388 {
389 if(language_id.empty())
390 return language_id;
391
392 std::map<wxString, wxString>::iterator it;
393 // m_LanguageNamesMap[] is probably obsolete because of FindLanguageInfo()... consider removing m_LanguageNamesMap[]
394 it = m_LanguageNamesMap.find(language_id);
395 if (it != m_LanguageNamesMap.end() )
396 return it->second;
397
398 wxString id_fix = language_id;
399 id_fix.Replace(wxT("-"), wxT("_")); // some dictionaries are distributed with hyphens
400
401 it = m_LanguageNamesMap.find(id_fix);
402 if (it != m_LanguageNamesMap.end() )
403 return it->second;
404
405 const wxLanguageInfo* langInfo = wxLocale::FindLanguageInfo(language_id); // ask wxWidgets if it knows the name
406 if (langInfo)
407 return langInfo->Description;
408 langInfo = wxLocale::FindLanguageInfo(id_fix);
409 if (langInfo)
410 return langInfo->Description;
411
412 id_fix = id_fix.BeforeLast(wxT('_')); // may be "*_v2", or root language may be known even if this specification is not
413
414 it = m_LanguageNamesMap.find(id_fix);
415 if (it != m_LanguageNamesMap.end() )
416 return it->second + wxT(" (") + language_id + wxT(")"); // but may be incorrect, so specify the original name
417
418 langInfo = wxLocale::FindLanguageInfo(id_fix);
419 if (langInfo)
420 return langInfo->Description + wxT(" (") + language_id + wxT(")");
421
422 return language_id;
423 }
424