OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/api/language_settings_private/language_setti ngs_private_delegate.h" | 5 #include "chrome/browser/extensions/api/language_settings_private/language_setti ngs_private_delegate.h" |
6 | 6 |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/bind_helpers.h" | |
12 #include "base/memory/linked_ptr.h" | |
13 #include "base/memory/scoped_ptr.h" | |
14 #include "base/memory/scoped_vector.h" | |
15 #include "base/prefs/pref_service.h" | |
16 #include "base/strings/utf_string_conversions.h" | |
17 #include "chrome/browser/browser_process.h" | |
18 #include "chrome/browser/chrome_notification_types.h" | |
19 #include "chrome/browser/profiles/profile.h" | |
20 #include "chrome/browser/spellchecker/spellcheck_factory.h" | |
21 #include "chrome/browser/spellchecker/spellcheck_service.h" | |
22 #include "chrome/common/pref_names.h" | |
7 #include "content/public/browser/browser_context.h" | 23 #include "content/public/browser/browser_context.h" |
24 #include "content/public/browser/notification_source.h" | |
8 | 25 |
9 namespace extensions { | 26 namespace extensions { |
10 | 27 |
11 namespace language_settings_private = api::language_settings_private; | 28 namespace language_settings_private = api::language_settings_private; |
12 | 29 |
13 LanguageSettingsPrivateDelegate::LanguageSettingsPrivateDelegate( | 30 LanguageSettingsPrivateDelegate::LanguageSettingsPrivateDelegate( |
14 content::BrowserContext* context) | 31 content::BrowserContext* context) |
15 : context_(context), | 32 : custom_dictionary_(nullptr), |
16 listening_spellcheck_(false) { | 33 context_(context), |
34 listening_spellcheck_(false), | |
35 profile_added_(false) { | |
17 // Register with the event router so we know when renderers are listening to | 36 // Register with the event router so we know when renderers are listening to |
18 // our events. We first check and see if there *is* an event router, because | 37 // our events. We first check and see if there *is* an event router, because |
19 // some unit tests try to create all context services, but don't initialize | 38 // some unit tests try to create all context services, but don't initialize |
20 // the event router first. | 39 // the event router first. |
21 EventRouter* event_router = EventRouter::Get(context_); | 40 EventRouter* event_router = EventRouter::Get(context_); |
22 if (!event_router) | 41 if (!event_router) |
23 return; | 42 return; |
24 | 43 |
25 event_router->RegisterObserver(this, | 44 event_router->RegisterObserver(this, |
26 language_settings_private::OnSpellcheckDictionariesChanged::kEventName); | 45 language_settings_private::OnSpellcheckDictionariesChanged::kEventName); |
27 event_router->RegisterObserver(this, | 46 event_router->RegisterObserver(this, |
28 language_settings_private::OnCustomDictionaryChanged::kEventName); | 47 language_settings_private::OnCustomDictionaryChanged::kEventName); |
29 | 48 |
49 // SpellcheckService cannot be created until Profile::DoFinalInit() has been | |
50 // called. http://crbug.com/171406 | |
51 notification_registrar_.Add(this, | |
52 chrome::NOTIFICATION_PROFILE_ADDED, | |
53 content::Source<Profile>(Profile::FromBrowserContext(context_))); | |
54 | |
55 pref_change_registrar_.Init(Profile::FromBrowserContext(context_)-> | |
56 GetPrefs()); | |
57 | |
30 StartOrStopListeningForSpellcheckChanges(); | 58 StartOrStopListeningForSpellcheckChanges(); |
31 } | 59 } |
32 | 60 |
33 LanguageSettingsPrivateDelegate::~LanguageSettingsPrivateDelegate() { | 61 LanguageSettingsPrivateDelegate::~LanguageSettingsPrivateDelegate() { |
34 DCHECK(!listening_spellcheck_); | 62 DCHECK(!listening_spellcheck_); |
63 pref_change_registrar_.RemoveAll(); | |
64 notification_registrar_.RemoveAll(); | |
35 } | 65 } |
36 | 66 |
37 LanguageSettingsPrivateDelegate* LanguageSettingsPrivateDelegate::Create( | 67 LanguageSettingsPrivateDelegate* LanguageSettingsPrivateDelegate::Create( |
38 content::BrowserContext* context) { | 68 content::BrowserContext* context) { |
39 return new LanguageSettingsPrivateDelegate(context); | 69 return new LanguageSettingsPrivateDelegate(context); |
40 } | 70 } |
41 | 71 |
42 void LanguageSettingsPrivateDelegate::Shutdown() { | 72 void LanguageSettingsPrivateDelegate::Shutdown() { |
43 // Unregister with the event router. We first check and see if there *is* an | 73 // Unregister with the event router. We first check and see if there *is* an |
44 // event router, because some unit tests try to shutdown all context services, | 74 // event router, because some unit tests try to shutdown all context services, |
45 // but didn't initialize the event router first. | 75 // but didn't initialize the event router first. |
46 EventRouter* event_router = EventRouter::Get(context_); | 76 EventRouter* event_router = EventRouter::Get(context_); |
47 if (event_router) | 77 if (event_router) |
48 event_router->UnregisterObserver(this); | 78 event_router->UnregisterObserver(this); |
49 | 79 |
50 if (listening_spellcheck_) { | 80 if (listening_spellcheck_) { |
51 // TODO(michaelpg): unregister observers. | 81 for (auto& dictionary : hunspell_dictionaries_) { |
82 if (dictionary) | |
83 dictionary->RemoveObserver(this); | |
84 } | |
85 listening_spellcheck_ = false; | |
52 } | 86 } |
53 | |
54 listening_spellcheck_ = false; | |
55 } | 87 } |
56 | 88 |
57 void LanguageSettingsPrivateDelegate::OnListenerAdded( | 89 void LanguageSettingsPrivateDelegate::OnListenerAdded( |
58 const EventListenerInfo& details) { | 90 const EventListenerInfo& details) { |
59 // Start listening to spellcheck change events. | 91 // Start listening to spellcheck change events. |
60 if (details.event_name == | 92 if (details.event_name == |
61 language_settings_private::OnSpellcheckDictionariesChanged::kEventName || | 93 language_settings_private::OnSpellcheckDictionariesChanged::kEventName || |
62 details.event_name == | 94 details.event_name == |
63 language_settings_private::OnCustomDictionaryChanged::kEventName) { | 95 language_settings_private::OnCustomDictionaryChanged::kEventName) { |
64 StartOrStopListeningForSpellcheckChanges(); | 96 StartOrStopListeningForSpellcheckChanges(); |
65 } | 97 } |
66 } | 98 } |
67 | 99 |
68 void LanguageSettingsPrivateDelegate::OnListenerRemoved( | 100 void LanguageSettingsPrivateDelegate::OnListenerRemoved( |
69 const EventListenerInfo& details) { | 101 const EventListenerInfo& details) { |
70 // Stop listening to events if there are no more listeners. | 102 // Stop listening to events if there are no more listeners. |
71 StartOrStopListeningForSpellcheckChanges(); | 103 StartOrStopListeningForSpellcheckChanges(); |
72 } | 104 } |
73 | 105 |
106 void LanguageSettingsPrivateDelegate::Observe( | |
107 int type, | |
108 const content::NotificationSource& source, | |
109 const content::NotificationDetails& details) { | |
110 profile_added_ = true; | |
111 StartOrStopListeningForSpellcheckChanges(); | |
112 } | |
113 | |
114 void LanguageSettingsPrivateDelegate::OnHunspellDictionaryInitialized() { | |
115 BroadcastDictionariesChangedEvent(); | |
116 } | |
117 | |
118 void LanguageSettingsPrivateDelegate::OnHunspellDictionaryDownloadBegin() { | |
119 BroadcastDictionariesChangedEvent(); | |
120 } | |
121 | |
122 void LanguageSettingsPrivateDelegate::OnHunspellDictionaryDownloadSuccess() { | |
123 BroadcastDictionariesChangedEvent(); | |
124 } | |
125 | |
126 void LanguageSettingsPrivateDelegate::OnHunspellDictionaryDownloadFailure() { | |
127 BroadcastDictionariesChangedEvent(); | |
128 } | |
129 | |
130 void LanguageSettingsPrivateDelegate::OnCustomDictionaryLoaded() { | |
131 } | |
132 | |
133 void LanguageSettingsPrivateDelegate::OnCustomDictionaryChanged( | |
134 const SpellcheckCustomDictionary::Change& change) { | |
135 std::vector<std::string> to_add(change.to_add().begin(), | |
136 change.to_add().end()); | |
137 std::vector<std::string> to_remove(change.to_remove().begin(), | |
138 change.to_remove().end()); | |
139 scoped_ptr<base::ListValue> args( | |
140 language_settings_private::OnCustomDictionaryChanged::Create( | |
141 to_add, to_remove)); | |
142 scoped_ptr<Event> extension_event(new Event( | |
143 events::LANGUAGE_SETTINGS_PRIVATE_ON_CUSTOM_DICTIONARY_CHANGED, | |
144 language_settings_private::OnCustomDictionaryChanged::kEventName, | |
145 args.Pass())); | |
146 EventRouter::Get(context_)->BroadcastEvent(extension_event.Pass()); | |
147 } | |
148 | |
149 void LanguageSettingsPrivateDelegate::RefreshDictionaries( | |
150 bool was_listening, bool should_listen) { | |
151 if (!profile_added_) | |
152 return; | |
153 if (was_listening) { | |
154 // Remove observers if the dictionaries still exist. | |
155 for (const auto& dictionary : hunspell_dictionaries_) { | |
156 if (dictionary) | |
157 dictionary->RemoveObserver(this); | |
158 } | |
stevenjb
2015/08/11 19:30:19
This code is duplicated in Shutdown, we should mov
michaelpg
2015/08/14 00:10:49
Done.
| |
159 } | |
160 hunspell_dictionaries_.clear(); | |
161 SpellcheckService* service = SpellcheckServiceFactory::GetForContext( | |
162 context_); | |
163 if (!custom_dictionary_) | |
164 custom_dictionary_ = service->GetCustomDictionary(); | |
165 | |
166 const ScopedVector<SpellcheckHunspellDictionary>& dictionaries( | |
167 service->GetHunspellDictionaries()); | |
168 for (const auto& dictionary: dictionaries) { | |
169 hunspell_dictionaries_.push_back(dictionary->AsWeakPtr()); | |
170 if (should_listen) | |
171 dictionary->AddObserver(this); | |
172 } | |
173 } | |
174 | |
175 ScopedVector<language_settings_private::SpellcheckDictionaryStatus> | |
176 LanguageSettingsPrivateDelegate::GetHunspellDictionaryStatuses() { | |
hajimehoshi
2015/08/12 05:34:49
nit: indent
michaelpg
2015/08/14 00:10:49
Done.
| |
177 ScopedVector<language_settings_private::SpellcheckDictionaryStatus> statuses; | |
178 for (const auto& dictionary : GetHunspellDictionaries()) { | |
179 if (!dictionary) | |
180 continue; | |
181 scoped_ptr<language_settings_private::SpellcheckDictionaryStatus> status( | |
182 new language_settings_private::SpellcheckDictionaryStatus()); | |
183 status->language_code = dictionary->GetLanguage(); | |
184 status->is_ready = dictionary->IsReady(); | |
185 if (!status->is_ready) { | |
186 if (dictionary->IsDownloadInProgress()) | |
187 status->is_downloading.reset(new bool(true)); | |
188 if (dictionary->IsDownloadFailure()) | |
189 status->download_failed.reset(new bool(true)); | |
190 } | |
191 statuses.push_back(status.Pass()); | |
192 } | |
193 return statuses.Pass(); | |
194 } | |
195 | |
196 const std::vector<base::WeakPtr<SpellcheckHunspellDictionary>>& | |
197 LanguageSettingsPrivateDelegate::GetHunspellDictionaries() { | |
hajimehoshi
2015/08/12 05:34:49
nit: indent
michaelpg
2015/08/14 00:10:49
Done.
| |
198 // If there are no hunspell dictionaries, or the first is invalid, refresh. | |
199 if (!hunspell_dictionaries_.size() || !hunspell_dictionaries_.front()) | |
200 RefreshDictionaries(listening_spellcheck_, listening_spellcheck_); | |
201 return hunspell_dictionaries_; | |
202 } | |
203 | |
74 void LanguageSettingsPrivateDelegate:: | 204 void LanguageSettingsPrivateDelegate:: |
75 StartOrStopListeningForSpellcheckChanges() { | 205 StartOrStopListeningForSpellcheckChanges() { |
76 EventRouter* event_router = EventRouter::Get(context_); | 206 EventRouter* event_router = EventRouter::Get(context_); |
77 bool should_listen = | 207 bool should_listen = |
78 event_router->HasEventListener(language_settings_private:: | 208 event_router->HasEventListener(language_settings_private:: |
79 OnSpellcheckDictionariesChanged::kEventName) || | 209 OnSpellcheckDictionariesChanged::kEventName) || |
80 event_router->HasEventListener(language_settings_private:: | 210 event_router->HasEventListener(language_settings_private:: |
81 OnCustomDictionaryChanged::kEventName); | 211 OnCustomDictionaryChanged::kEventName); |
82 | 212 |
83 if (should_listen && !listening_spellcheck_) { | 213 if (should_listen && !listening_spellcheck_) { |
84 // TODO: register observers. | 214 // Update and observe the hunspell dictionaries. |
215 RefreshDictionaries(listening_spellcheck_, should_listen); | |
216 // Observe the dictionaries preference. | |
217 pref_change_registrar_.Add(prefs::kSpellCheckDictionaries, base::Bind( | |
218 &LanguageSettingsPrivateDelegate::OnSpellcheckDictionariesChanged, | |
219 base::Unretained(this))); | |
220 // Observe the dictionary of custom words. | |
221 if (custom_dictionary_) | |
222 custom_dictionary_->AddObserver(this); | |
85 } else if (!should_listen && listening_spellcheck_) { | 223 } else if (!should_listen && listening_spellcheck_) { |
86 // TODO(michaelpg): unregister observers. | 224 // Stop observing any dictionaries that still exist. |
225 for (const auto& dictionary : hunspell_dictionaries_) { | |
226 if (dictionary) | |
227 dictionary->RemoveObserver(this); | |
228 } | |
229 hunspell_dictionaries_.clear(); | |
230 pref_change_registrar_.Remove(prefs::kSpellCheckDictionaries); | |
231 if (custom_dictionary_) | |
232 custom_dictionary_->RemoveObserver(this); | |
87 } | 233 } |
88 | 234 |
89 listening_spellcheck_ = should_listen; | 235 listening_spellcheck_ = should_listen; |
90 } | 236 } |
91 | 237 |
238 void LanguageSettingsPrivateDelegate::OnSpellcheckDictionariesChanged() { | |
239 RefreshDictionaries(listening_spellcheck_, listening_spellcheck_); | |
240 BroadcastDictionariesChangedEvent(); | |
241 } | |
242 | |
243 void LanguageSettingsPrivateDelegate::BroadcastDictionariesChangedEvent() { | |
244 std::vector<linked_ptr<language_settings_private::SpellcheckDictionaryStatus>> | |
245 ret; | |
stevenjb
2015/08/11 19:30:19
s/ret/result/ (or something more clear... short fo
michaelpg
2015/08/14 00:10:49
Done.
| |
246 ScopedVector<language_settings_private::SpellcheckDictionaryStatus> statuses = | |
247 GetHunspellDictionaryStatuses(); | |
248 | |
249 for (language_settings_private::SpellcheckDictionaryStatus* status : statuses) | |
250 ret.push_back(make_linked_ptr(status)); | |
251 statuses.weak_clear(); | |
252 | |
253 scoped_ptr<base::ListValue> args( | |
254 language_settings_private::OnSpellcheckDictionariesChanged::Create( | |
255 ret)); | |
256 scoped_ptr<extensions::Event> extension_event(new extensions::Event( | |
257 events::LANGUAGE_SETTINGS_PRIVATE_ON_SPELLCHECK_DICTIONARIES_CHANGED, | |
258 language_settings_private::OnSpellcheckDictionariesChanged::kEventName, | |
259 args.Pass())); | |
260 EventRouter::Get(context_)->BroadcastEvent(extension_event.Pass()); | |
261 } | |
262 | |
92 } // namespace extensions | 263 } // namespace extensions |
OLD | NEW |