Chromium Code Reviews| 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 |