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/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 |