1 /*
2 * This file is part of Poedit (http://poedit.net)
3 *
4 * Copyright (C) 2014-2015 Vaclav Slavik
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 */
25
26 #include "spellchecking.h"
27
28 #include "str_helpers.h"
29
30 #ifdef __WXGTK__
31 #include <gtk/gtk.h>
32 extern "C" {
33 #include <gtkspell/gtkspell.h>
34 }
35 #endif
36
37 #ifdef __WXMSW__
38 #include <wx/msw/wrapwin.h>
39 #include <Richedit.h>
40 #ifndef IMF_SPELLCHECKING
41 #define IMF_SPELLCHECKING 0x0800
42 #endif
43 #endif
44
45 #include "edapp.h"
46
47
48 #ifdef __WXGTK__
49 // helper functions that finds GtkTextView of wxTextCtrl:
GetTextView(wxTextCtrl * ctrl)50 static GtkTextView *GetTextView(wxTextCtrl *ctrl)
51 {
52 GtkWidget *parent = ctrl->m_widget;
53 GList *child = gtk_container_get_children(GTK_CONTAINER(parent));
54 while (child)
55 {
56 if (GTK_IS_TEXT_VIEW(child->data))
57 {
58 return GTK_TEXT_VIEW(child->data);
59 }
60 child = child->next;
61 }
62
63 wxFAIL_MSG( "couldn't find GtkTextView for text control" );
64 return NULL;
65 }
66
67 #if GTK_CHECK_VERSION(3,0,0)
68
InitTextCtrlSpellchecker(wxTextCtrl * text,bool enable,const Language & lang)69 bool InitTextCtrlSpellchecker(wxTextCtrl *text, bool enable, const Language& lang)
70 {
71 GtkTextView *textview = GetTextView(text);
72 wxASSERT_MSG( textview, "wxTextCtrl is supposed to use GtkTextView" );
73
74 GtkSpellChecker *spell = gtk_spell_checker_get_from_text_view(textview);
75
76 if (enable)
77 {
78 if (!spell)
79 {
80 spell = gtk_spell_checker_new();
81 gtk_spell_checker_attach(spell, textview);
82 }
83
84 return gtk_spell_checker_set_language(spell, lang.Code().c_str(), nullptr);
85 }
86 else
87 {
88 if (spell)
89 gtk_spell_checker_detach(spell);
90 return true;
91 }
92 }
93
94 #else // GTK+ 2.x
95
InitTextCtrlSpellchecker(wxTextCtrl * text,bool enable,const Language & lang)96 bool InitTextCtrlSpellchecker(wxTextCtrl *text, bool enable, const Language& lang)
97 {
98 GtkTextView *textview = GetTextView(text);
99 wxASSERT_MSG( textview, "wxTextCtrl is supposed to use GtkTextView" );
100 GtkSpell *spell = gtkspell_get_from_text_view(textview);
101
102 GError *err = NULL;
103
104 if (enable)
105 {
106 if (spell)
107 gtkspell_set_language(spell, lang.Code().c_str(), &err);
108 else
109 gtkspell_new_attach(textview, lang.Code().c_str(), &err);
110 }
111 else // !enable
112 {
113 // GtkSpell when used with Zemberek Enchant module doesn't work
114 // correctly if you repeatedly attach and detach a speller to text
115 // view. See http://poedit.net/trac/ticket/276 for details.
116 //
117 // To work around this, we set the language to a non-existent one
118 // instead of detaching GtkSpell -- this has the same effect as
119 // detaching the speller as far as the UI is concerned.
120 if (spell)
121 gtkspell_set_language(spell, "unknown_language", &err);
122 }
123
124 if (err)
125 g_error_free(err);
126
127 return err == NULL;
128 }
129
130 #endif // GTK+ 2.x
131
132 #endif // __WXGTK__
133
134 #ifdef __WXOSX__
SetSpellcheckerLang(const wxString & lang)135 bool SetSpellcheckerLang(const wxString& lang)
136 {
137 NSString *nslang = str::to_NS(lang);
138 NSSpellChecker *sc = [NSSpellChecker sharedSpellChecker];
139 [sc setAutomaticallyIdentifiesLanguages:NO];
140 return [sc setLanguage: nslang];
141 }
142
InitTextCtrlSpellchecker(wxTextCtrl * text,bool enable,const Language &)143 bool InitTextCtrlSpellchecker(wxTextCtrl *text, bool enable, const Language& /*lang*/)
144 {
145 NSScrollView *scroll = (NSScrollView*)text->GetHandle();
146 NSTextView *view = [scroll documentView];
147
148 [view setContinuousSpellCheckingEnabled:enable];
149 [view setGrammarCheckingEnabled:enable];
150
151 return true;
152 }
153 #endif // __WXOSX__
154
155 #ifdef __WXMSW__
PrepareTextCtrlForSpellchecker(wxTextCtrl * text)156 void PrepareTextCtrlForSpellchecker(wxTextCtrl *text)
157 {
158 // Set spellchecking-friendly style on the text control. Enabling spellchecking
159 // itself is done with EM_SETLANGOPTIONS in InitTextCtrlSpellchecker()
160 HWND hwnd = (HWND)text->GetHWND();
161 auto editStyle = SES_USECTF | SES_CTFALLOWEMBED | SES_CTFALLOWSMARTTAG | SES_CTFALLOWPROOFING;
162 ::SendMessage(hwnd, EM_SETEDITSTYLE, editStyle, editStyle);
163 }
164
InitTextCtrlSpellchecker(wxTextCtrl * text,bool enable,const Language &)165 bool InitTextCtrlSpellchecker(wxTextCtrl *text, bool enable, const Language& /*lang*/)
166 {
167 HWND hwnd = (HWND) text->GetHWND();
168 auto langOptions = ::SendMessage(hwnd, EM_GETLANGOPTIONS, 0, 0);
169 if (enable)
170 langOptions |= IMF_SPELLCHECKING;
171 else
172 langOptions &= ~IMF_SPELLCHECKING;
173 ::SendMessage(hwnd, EM_SETLANGOPTIONS, 0, langOptions);
174 return true;
175 }
176 #endif // __WXMSW__
177
178
179 #ifndef __WXMSW__
ShowSpellcheckerHelp()180 void ShowSpellcheckerHelp()
181 {
182 #if defined(__WXOSX__)
183 #define SPELL_HELP_PAGE "SpellcheckerMac"
184 #elif defined(__UNIX__)
185 #define SPELL_HELP_PAGE "SpellcheckerLinux"
186 #else
187 #error "missing spellchecker instructions for platform"
188 #endif
189 wxGetApp().OpenPoeditWeb("/trac/wiki/Doc/" SPELL_HELP_PAGE);
190 }
191 #endif // !__WXMSW__
192