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 |
72 ScopedVector<language_settings_private::SpellcheckDictionaryStatus> | |
73 LanguageSettingsPrivateDelegate::GetHunspellDictionaryStatuses() { | |
74 ScopedVector<language_settings_private::SpellcheckDictionaryStatus> statuses; | |
75 for (const auto& dictionary : GetHunspellDictionaries()) { | |
76 if (!dictionary) | |
77 continue; | |
78 scoped_ptr<language_settings_private::SpellcheckDictionaryStatus> status( | |
79 new language_settings_private::SpellcheckDictionaryStatus()); | |
80 status->language_code = dictionary->GetLanguage(); | |
81 status->is_ready = dictionary->IsReady(); | |
82 if (!status->is_ready) { | |
83 if (dictionary->IsDownloadInProgress()) | |
84 status->is_downloading.reset(new bool(true)); | |
85 if (dictionary->IsDownloadFailure()) | |
86 status->download_failed.reset(new bool(true)); | |
87 } | |
88 statuses.push_back(status.Pass()); | |
89 } | |
90 return statuses.Pass(); | |
91 } | |
92 | |
42 void LanguageSettingsPrivateDelegate::Shutdown() { | 93 void LanguageSettingsPrivateDelegate::Shutdown() { |
michaelpg
2015/08/14 00:10:49
Well I moved one function to match the .h order, a
| |
43 // Unregister with the event router. We first check and see if there *is* an | 94 // 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, | 95 // event router, because some unit tests try to shutdown all context services, |
45 // but didn't initialize the event router first. | 96 // but didn't initialize the event router first. |
46 EventRouter* event_router = EventRouter::Get(context_); | 97 EventRouter* event_router = EventRouter::Get(context_); |
47 if (event_router) | 98 if (event_router) |
48 event_router->UnregisterObserver(this); | 99 event_router->UnregisterObserver(this); |
49 | 100 |
50 if (listening_spellcheck_) { | 101 if (listening_spellcheck_) { |
51 // TODO(michaelpg): unregister observers. | 102 RemoveDictionaryObservers(); |
103 listening_spellcheck_ = false; | |
52 } | 104 } |
53 | |
54 listening_spellcheck_ = false; | |
55 } | 105 } |
56 | 106 |
57 void LanguageSettingsPrivateDelegate::OnListenerAdded( | 107 void LanguageSettingsPrivateDelegate::OnListenerAdded( |
58 const EventListenerInfo& details) { | 108 const EventListenerInfo& details) { |
59 // Start listening to spellcheck change events. | 109 // Start listening to spellcheck change events. |
60 if (details.event_name == | 110 if (details.event_name == |
61 language_settings_private::OnSpellcheckDictionariesChanged::kEventName || | 111 language_settings_private::OnSpellcheckDictionariesChanged::kEventName || |
62 details.event_name == | 112 details.event_name == |
63 language_settings_private::OnCustomDictionaryChanged::kEventName) { | 113 language_settings_private::OnCustomDictionaryChanged::kEventName) { |
64 StartOrStopListeningForSpellcheckChanges(); | 114 StartOrStopListeningForSpellcheckChanges(); |
65 } | 115 } |
66 } | 116 } |
67 | 117 |
68 void LanguageSettingsPrivateDelegate::OnListenerRemoved( | 118 void LanguageSettingsPrivateDelegate::OnListenerRemoved( |
69 const EventListenerInfo& details) { | 119 const EventListenerInfo& details) { |
70 // Stop listening to events if there are no more listeners. | 120 // Stop listening to events if there are no more listeners. |
71 StartOrStopListeningForSpellcheckChanges(); | 121 StartOrStopListeningForSpellcheckChanges(); |
72 } | 122 } |
73 | 123 |
124 void LanguageSettingsPrivateDelegate::Observe( | |
125 int type, | |
126 const content::NotificationSource& source, | |
127 const content::NotificationDetails& details) { | |
128 profile_added_ = true; | |
129 StartOrStopListeningForSpellcheckChanges(); | |
130 } | |
131 | |
132 void LanguageSettingsPrivateDelegate::OnHunspellDictionaryInitialized() { | |
133 BroadcastDictionariesChangedEvent(); | |
134 } | |
135 | |
136 void LanguageSettingsPrivateDelegate::OnHunspellDictionaryDownloadBegin() { | |
137 BroadcastDictionariesChangedEvent(); | |
138 } | |
139 | |
140 void LanguageSettingsPrivateDelegate::OnHunspellDictionaryDownloadSuccess() { | |
141 BroadcastDictionariesChangedEvent(); | |
142 } | |
143 | |
144 void LanguageSettingsPrivateDelegate::OnHunspellDictionaryDownloadFailure() { | |
145 BroadcastDictionariesChangedEvent(); | |
146 } | |
147 | |
148 void LanguageSettingsPrivateDelegate::OnCustomDictionaryLoaded() { | |
149 } | |
150 | |
151 void LanguageSettingsPrivateDelegate::OnCustomDictionaryChanged( | |
152 const SpellcheckCustomDictionary::Change& change) { | |
153 std::vector<std::string> to_add(change.to_add().begin(), | |
154 change.to_add().end()); | |
155 std::vector<std::string> to_remove(change.to_remove().begin(), | |
156 change.to_remove().end()); | |
157 scoped_ptr<base::ListValue> args( | |
158 language_settings_private::OnCustomDictionaryChanged::Create( | |
159 to_add, to_remove)); | |
160 scoped_ptr<Event> extension_event(new Event( | |
161 events::LANGUAGE_SETTINGS_PRIVATE_ON_CUSTOM_DICTIONARY_CHANGED, | |
162 language_settings_private::OnCustomDictionaryChanged::kEventName, | |
163 args.Pass())); | |
164 EventRouter::Get(context_)->BroadcastEvent(extension_event.Pass()); | |
165 } | |
166 | |
167 void LanguageSettingsPrivateDelegate::RefreshDictionaries( | |
168 bool was_listening, bool should_listen) { | |
169 if (!profile_added_) | |
170 return; | |
171 if (was_listening) | |
172 RemoveDictionaryObservers(); | |
173 hunspell_dictionaries_.clear(); | |
174 SpellcheckService* service = SpellcheckServiceFactory::GetForContext( | |
175 context_); | |
176 if (!custom_dictionary_) | |
177 custom_dictionary_ = service->GetCustomDictionary(); | |
178 | |
179 const ScopedVector<SpellcheckHunspellDictionary>& dictionaries( | |
180 service->GetHunspellDictionaries()); | |
181 for (const auto& dictionary: dictionaries) { | |
182 hunspell_dictionaries_.push_back(dictionary->AsWeakPtr()); | |
183 if (should_listen) | |
184 dictionary->AddObserver(this); | |
185 } | |
186 } | |
187 | |
188 const LanguageSettingsPrivateDelegate::WeakDictionaries& | |
189 LanguageSettingsPrivateDelegate::GetHunspellDictionaries() { | |
190 // If there are no hunspell dictionaries, or the first is invalid, refresh. | |
191 if (!hunspell_dictionaries_.size() || !hunspell_dictionaries_.front()) | |
192 RefreshDictionaries(listening_spellcheck_, listening_spellcheck_); | |
193 return hunspell_dictionaries_; | |
194 } | |
195 | |
74 void LanguageSettingsPrivateDelegate:: | 196 void LanguageSettingsPrivateDelegate:: |
75 StartOrStopListeningForSpellcheckChanges() { | 197 StartOrStopListeningForSpellcheckChanges() { |
76 EventRouter* event_router = EventRouter::Get(context_); | 198 EventRouter* event_router = EventRouter::Get(context_); |
77 bool should_listen = | 199 bool should_listen = |
78 event_router->HasEventListener(language_settings_private:: | 200 event_router->HasEventListener(language_settings_private:: |
79 OnSpellcheckDictionariesChanged::kEventName) || | 201 OnSpellcheckDictionariesChanged::kEventName) || |
80 event_router->HasEventListener(language_settings_private:: | 202 event_router->HasEventListener(language_settings_private:: |
81 OnCustomDictionaryChanged::kEventName); | 203 OnCustomDictionaryChanged::kEventName); |
82 | 204 |
83 if (should_listen && !listening_spellcheck_) { | 205 if (should_listen && !listening_spellcheck_) { |
84 // TODO: register observers. | 206 // Update and observe the hunspell dictionaries. |
207 RefreshDictionaries(listening_spellcheck_, should_listen); | |
208 // Observe the dictionaries preference. | |
209 pref_change_registrar_.Add(prefs::kSpellCheckDictionaries, base::Bind( | |
210 &LanguageSettingsPrivateDelegate::OnSpellcheckDictionariesChanged, | |
211 base::Unretained(this))); | |
212 // Observe the dictionary of custom words. | |
213 if (custom_dictionary_) | |
214 custom_dictionary_->AddObserver(this); | |
85 } else if (!should_listen && listening_spellcheck_) { | 215 } else if (!should_listen && listening_spellcheck_) { |
86 // TODO(michaelpg): unregister observers. | 216 // Stop observing any dictionaries that still exist. |
217 RemoveDictionaryObservers(); | |
218 hunspell_dictionaries_.clear(); | |
219 pref_change_registrar_.Remove(prefs::kSpellCheckDictionaries); | |
220 if (custom_dictionary_) | |
221 custom_dictionary_->RemoveObserver(this); | |
87 } | 222 } |
88 | 223 |
89 listening_spellcheck_ = should_listen; | 224 listening_spellcheck_ = should_listen; |
90 } | 225 } |
91 | 226 |
227 void LanguageSettingsPrivateDelegate::OnSpellcheckDictionariesChanged() { | |
228 RefreshDictionaries(listening_spellcheck_, listening_spellcheck_); | |
229 BroadcastDictionariesChangedEvent(); | |
230 } | |
231 | |
232 void LanguageSettingsPrivateDelegate::BroadcastDictionariesChangedEvent() { | |
233 std::vector<linked_ptr<language_settings_private::SpellcheckDictionaryStatus>> | |
234 broadcast_statuses; | |
235 ScopedVector<language_settings_private::SpellcheckDictionaryStatus> statuses = | |
236 GetHunspellDictionaryStatuses(); | |
237 | |
238 for (language_settings_private::SpellcheckDictionaryStatus* status : statuses) | |
239 broadcast_statuses.push_back(make_linked_ptr(status)); | |
240 statuses.weak_clear(); | |
241 | |
242 scoped_ptr<base::ListValue> args( | |
243 language_settings_private::OnSpellcheckDictionariesChanged::Create( | |
244 broadcast_statuses)); | |
245 scoped_ptr<extensions::Event> extension_event(new extensions::Event( | |
246 events::LANGUAGE_SETTINGS_PRIVATE_ON_SPELLCHECK_DICTIONARIES_CHANGED, | |
247 language_settings_private::OnSpellcheckDictionariesChanged::kEventName, | |
248 args.Pass())); | |
249 EventRouter::Get(context_)->BroadcastEvent(extension_event.Pass()); | |
250 } | |
251 | |
252 void LanguageSettingsPrivateDelegate::RemoveDictionaryObservers() { | |
253 for (const auto& dictionary : hunspell_dictionaries_) { | |
254 if (dictionary) | |
255 dictionary->RemoveObserver(this); | |
256 } | |
257 } | |
258 | |
92 } // namespace extensions | 259 } // namespace extensions |
OLD | NEW |