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