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/prefs/pref_service.h" | |
15 #include "base/strings/utf_string_conversions.h" | |
16 #include "chrome/browser/browser_process.h" | |
17 #include "chrome/browser/chrome_notification_types.h" | |
18 #include "chrome/browser/profiles/profile.h" | |
19 #include "chrome/browser/spellchecker/spellcheck_factory.h" | |
20 #include "chrome/browser/spellchecker/spellcheck_service.h" | |
21 #include "chrome/common/pref_names.h" | |
7 #include "content/public/browser/browser_context.h" | 22 #include "content/public/browser/browser_context.h" |
23 #include "content/public/browser/notification_source.h" | |
8 | 24 |
9 namespace extensions { | 25 namespace extensions { |
10 | 26 |
11 namespace language_settings_private = api::language_settings_private; | 27 namespace language_settings_private = api::language_settings_private; |
12 | 28 |
13 LanguageSettingsPrivateDelegate::LanguageSettingsPrivateDelegate( | 29 LanguageSettingsPrivateDelegate::LanguageSettingsPrivateDelegate( |
14 content::BrowserContext* context) | 30 content::BrowserContext* context) |
15 : context_(context), | 31 : custom_dictionary_(nullptr), |
16 listening_spellcheck_(false) { | 32 context_(context), |
33 listening_spellcheck_(false), | |
34 profile_added_(false) { | |
17 // Register with the event router so we know when renderers are listening to | 35 // 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 | 36 // 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 | 37 // some unit tests try to create all context services, but don't initialize |
20 // the event router first. | 38 // the event router first. |
21 EventRouter* event_router = EventRouter::Get(context_); | 39 EventRouter* event_router = EventRouter::Get(context_); |
22 if (!event_router) | 40 if (!event_router) |
23 return; | 41 return; |
24 | 42 |
25 event_router->RegisterObserver(this, | 43 event_router->RegisterObserver(this, |
26 language_settings_private::OnSpellcheckDictionariesChanged::kEventName); | 44 language_settings_private::OnSpellcheckDictionariesChanged::kEventName); |
27 event_router->RegisterObserver(this, | 45 event_router->RegisterObserver(this, |
28 language_settings_private::OnCustomDictionaryChanged::kEventName); | 46 language_settings_private::OnCustomDictionaryChanged::kEventName); |
29 | 47 |
48 // SpellcheckService cannot be created until Profile::DoFinalInit() has been | |
49 // called. http://crbug.com/171406 | |
50 notification_registrar_.Add(this, | |
51 chrome::NOTIFICATION_PROFILE_ADDED, | |
52 content::Source<Profile>(Profile::FromBrowserContext(context_))); | |
53 | |
54 pref_change_registrar_.Init(Profile::FromBrowserContext(context_)-> | |
55 GetPrefs()); | |
56 | |
30 StartOrStopListeningForSpellcheckChanges(); | 57 StartOrStopListeningForSpellcheckChanges(); |
31 } | 58 } |
32 | 59 |
33 LanguageSettingsPrivateDelegate::~LanguageSettingsPrivateDelegate() { | 60 LanguageSettingsPrivateDelegate::~LanguageSettingsPrivateDelegate() { |
34 DCHECK(!listening_spellcheck_); | 61 DCHECK(!listening_spellcheck_); |
62 pref_change_registrar_.RemoveAll(); | |
63 notification_registrar_.RemoveAll(); | |
35 } | 64 } |
36 | 65 |
37 LanguageSettingsPrivateDelegate* LanguageSettingsPrivateDelegate::Create( | 66 LanguageSettingsPrivateDelegate* LanguageSettingsPrivateDelegate::Create( |
38 content::BrowserContext* context) { | 67 content::BrowserContext* context) { |
39 return new LanguageSettingsPrivateDelegate(context); | 68 return new LanguageSettingsPrivateDelegate(context); |
40 } | 69 } |
41 | 70 |
42 void LanguageSettingsPrivateDelegate::Shutdown() { | 71 void LanguageSettingsPrivateDelegate::Shutdown() { |
43 // Unregister with the event router. We first check and see if there *is* an | 72 // 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, | 73 // event router, because some unit tests try to shutdown all context services, |
45 // but didn't initialize the event router first. | 74 // but didn't initialize the event router first. |
46 EventRouter* event_router = EventRouter::Get(context_); | 75 EventRouter* event_router = EventRouter::Get(context_); |
47 if (event_router) | 76 if (event_router) |
48 event_router->UnregisterObserver(this); | 77 event_router->UnregisterObserver(this); |
49 | 78 |
50 if (listening_spellcheck_) { | 79 if (listening_spellcheck_) { |
51 // TODO(michaelpg): unregister observers. | 80 for (auto& dictionary : hunspell_dictionaries_) { |
81 if (dictionary) | |
82 dictionary->RemoveObserver(this); | |
83 } | |
52 } | 84 } |
53 | 85 |
54 listening_spellcheck_ = false; | 86 listening_spellcheck_ = false; |
stevenjb
2015/08/10 16:13:54
nit: This would be more clear inside the if() body
michaelpg
2015/08/10 23:31:51
Done.
| |
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 } | |
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 std::vector<scoped_ptr<language_settings_private::SpellcheckDictionaryStatus>> | |
176 LanguageSettingsPrivateDelegate::GetHunspellDictionaryStatuses() { | |
177 std::vector<scoped_ptr<language_settings_private::SpellcheckDictionaryStatus>> | |
178 statuses; | |
179 for (const auto& dictionary : GetHunspellDictionaries()) { | |
180 if (!dictionary) | |
181 continue; | |
182 scoped_ptr<language_settings_private::SpellcheckDictionaryStatus> status( | |
183 new language_settings_private::SpellcheckDictionaryStatus()); | |
184 status->language_code = dictionary->GetLanguage(); | |
185 status->is_ready = dictionary->IsReady(); | |
186 if (!status->is_ready) { | |
187 if (dictionary->IsDownloadInProgress()) | |
188 status->is_downloading.reset(new bool(true)); | |
189 if (dictionary->IsDownloadFailure()) | |
190 status->download_failed.reset(new bool(true)); | |
191 } | |
192 statuses.push_back(status.Pass()); | |
193 } | |
194 return statuses; | |
195 } | |
196 | |
197 const std::vector<base::WeakPtr<SpellcheckHunspellDictionary>>& | |
198 LanguageSettingsPrivateDelegate::GetHunspellDictionaries() { | |
199 // If there are no hunspell dictionaries, or the first is invalid, refresh. | |
200 if (!hunspell_dictionaries_.size() || !hunspell_dictionaries_.front()) | |
201 RefreshDictionaries(listening_spellcheck_, listening_spellcheck_); | |
202 return hunspell_dictionaries_; | |
203 } | |
204 | |
74 void LanguageSettingsPrivateDelegate:: | 205 void LanguageSettingsPrivateDelegate:: |
75 StartOrStopListeningForSpellcheckChanges() { | 206 StartOrStopListeningForSpellcheckChanges() { |
76 EventRouter* event_router = EventRouter::Get(context_); | 207 EventRouter* event_router = EventRouter::Get(context_); |
77 bool should_listen = | 208 bool should_listen = |
78 event_router->HasEventListener(language_settings_private:: | 209 event_router->HasEventListener(language_settings_private:: |
79 OnSpellcheckDictionariesChanged::kEventName) || | 210 OnSpellcheckDictionariesChanged::kEventName) || |
80 event_router->HasEventListener(language_settings_private:: | 211 event_router->HasEventListener(language_settings_private:: |
81 OnCustomDictionaryChanged::kEventName); | 212 OnCustomDictionaryChanged::kEventName); |
82 | 213 |
83 if (should_listen && !listening_spellcheck_) { | 214 if (should_listen && !listening_spellcheck_) { |
84 // TODO: register observers. | 215 // Update and observe the hunspell dictionaries. |
216 RefreshDictionaries(listening_spellcheck_, should_listen); | |
217 // Observe the dictionaries preference. | |
218 pref_change_registrar_.Add(prefs::kSpellCheckDictionaries, base::Bind( | |
219 &LanguageSettingsPrivateDelegate::OnSpellcheckDictionariesChanged, | |
220 base::Unretained(this))); | |
221 // Observe the dictionary of custom words. | |
222 if (custom_dictionary_) | |
223 custom_dictionary_->AddObserver(this); | |
85 } else if (!should_listen && listening_spellcheck_) { | 224 } else if (!should_listen && listening_spellcheck_) { |
86 // TODO(michaelpg): unregister observers. | 225 // Stop observing any dictionaries that still exist. |
226 for (const auto& dictionary : hunspell_dictionaries_) { | |
227 if (dictionary) | |
228 dictionary->RemoveObserver(this); | |
229 } | |
230 hunspell_dictionaries_.clear(); | |
231 pref_change_registrar_.Remove(prefs::kSpellCheckDictionaries); | |
232 if (custom_dictionary_) | |
233 custom_dictionary_->RemoveObserver(this); | |
87 } | 234 } |
88 | 235 |
89 listening_spellcheck_ = should_listen; | 236 listening_spellcheck_ = should_listen; |
90 } | 237 } |
91 | 238 |
239 void LanguageSettingsPrivateDelegate::OnSpellcheckDictionariesChanged() { | |
240 RefreshDictionaries(listening_spellcheck_, listening_spellcheck_); | |
241 BroadcastDictionariesChangedEvent(); | |
242 } | |
243 | |
244 void LanguageSettingsPrivateDelegate::BroadcastDictionariesChangedEvent() { | |
245 std::vector<linked_ptr<language_settings_private::SpellcheckDictionaryStatus>> | |
246 statuses; | |
247 for (scoped_ptr<language_settings_private::SpellcheckDictionaryStatus>& status | |
248 : GetHunspellDictionaryStatuses()) { | |
249 statuses.push_back(make_linked_ptr(status.release())); | |
250 } | |
251 | |
252 scoped_ptr<base::ListValue> args( | |
253 language_settings_private::OnSpellcheckDictionariesChanged::Create( | |
254 statuses)); | |
255 scoped_ptr<extensions::Event> extension_event(new extensions::Event( | |
256 events::LANGUAGE_SETTINGS_PRIVATE_ON_SPELLCHECK_DICTIONARIES_CHANGED, | |
257 language_settings_private::OnSpellcheckDictionariesChanged::kEventName, | |
258 args.Pass())); | |
259 EventRouter::Get(context_)->BroadcastEvent(extension_event.Pass()); | |
260 } | |
261 | |
92 } // namespace extensions | 262 } // namespace extensions |
OLD | NEW |