Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / language_settings_private / language_settings_private_delegate.cc
blob6204394c5701573c429e74b4342f4f474571834b
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
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.h"
7 #include <string>
8 #include <vector>
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"
23 #include "content/public/browser/browser_context.h"
24 #include "content/public/browser/notification_source.h"
26 namespace extensions {
28 namespace language_settings_private = api::language_settings_private;
30 LanguageSettingsPrivateDelegate::LanguageSettingsPrivateDelegate(
31 content::BrowserContext* context)
32 : custom_dictionary_(nullptr),
33 context_(context),
34 listening_spellcheck_(false),
35 profile_added_(false) {
36 // Register with the event router so we know when renderers are listening to
37 // our events. We first check and see if there *is* an event router, because
38 // some unit tests try to create all context services, but don't initialize
39 // the event router first.
40 EventRouter* event_router = EventRouter::Get(context_);
41 if (!event_router)
42 return;
44 event_router->RegisterObserver(this,
45 language_settings_private::OnSpellcheckDictionariesChanged::kEventName);
46 event_router->RegisterObserver(this,
47 language_settings_private::OnCustomDictionaryChanged::kEventName);
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_)));
55 pref_change_registrar_.Init(Profile::FromBrowserContext(context_)->
56 GetPrefs());
58 StartOrStopListeningForSpellcheckChanges();
61 LanguageSettingsPrivateDelegate::~LanguageSettingsPrivateDelegate() {
62 DCHECK(!listening_spellcheck_);
63 pref_change_registrar_.RemoveAll();
64 notification_registrar_.RemoveAll();
67 LanguageSettingsPrivateDelegate* LanguageSettingsPrivateDelegate::Create(
68 content::BrowserContext* context) {
69 return new LanguageSettingsPrivateDelegate(context);
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));
88 statuses.push_back(status.Pass());
90 return statuses.Pass();
93 void LanguageSettingsPrivateDelegate::Shutdown() {
94 // Unregister with the event router. We first check and see if there *is* an
95 // event router, because some unit tests try to shutdown all context services,
96 // but didn't initialize the event router first.
97 EventRouter* event_router = EventRouter::Get(context_);
98 if (event_router)
99 event_router->UnregisterObserver(this);
101 if (listening_spellcheck_) {
102 RemoveDictionaryObservers();
103 listening_spellcheck_ = false;
107 void LanguageSettingsPrivateDelegate::OnListenerAdded(
108 const EventListenerInfo& details) {
109 // Start listening to spellcheck change events.
110 if (details.event_name ==
111 language_settings_private::OnSpellcheckDictionariesChanged::kEventName ||
112 details.event_name ==
113 language_settings_private::OnCustomDictionaryChanged::kEventName) {
114 StartOrStopListeningForSpellcheckChanges();
118 void LanguageSettingsPrivateDelegate::OnListenerRemoved(
119 const EventListenerInfo& details) {
120 // Stop listening to events if there are no more listeners.
121 StartOrStopListeningForSpellcheckChanges();
124 void LanguageSettingsPrivateDelegate::Observe(
125 int type,
126 const content::NotificationSource& source,
127 const content::NotificationDetails& details) {
128 profile_added_ = true;
129 StartOrStopListeningForSpellcheckChanges();
132 void LanguageSettingsPrivateDelegate::OnHunspellDictionaryInitialized(
133 const std::string& language) {
134 BroadcastDictionariesChangedEvent();
137 void LanguageSettingsPrivateDelegate::OnHunspellDictionaryDownloadBegin(
138 const std::string& language) {
139 BroadcastDictionariesChangedEvent();
142 void LanguageSettingsPrivateDelegate::OnHunspellDictionaryDownloadSuccess(
143 const std::string& language) {
144 BroadcastDictionariesChangedEvent();
147 void LanguageSettingsPrivateDelegate::OnHunspellDictionaryDownloadFailure(
148 const std::string& language) {
149 BroadcastDictionariesChangedEvent();
152 void LanguageSettingsPrivateDelegate::OnCustomDictionaryLoaded() {
155 void LanguageSettingsPrivateDelegate::OnCustomDictionaryChanged(
156 const SpellcheckCustomDictionary::Change& change) {
157 std::vector<std::string> to_add(change.to_add().begin(),
158 change.to_add().end());
159 std::vector<std::string> to_remove(change.to_remove().begin(),
160 change.to_remove().end());
161 scoped_ptr<base::ListValue> args(
162 language_settings_private::OnCustomDictionaryChanged::Create(
163 to_add, to_remove));
164 scoped_ptr<Event> extension_event(new Event(
165 events::LANGUAGE_SETTINGS_PRIVATE_ON_CUSTOM_DICTIONARY_CHANGED,
166 language_settings_private::OnCustomDictionaryChanged::kEventName,
167 args.Pass()));
168 EventRouter::Get(context_)->BroadcastEvent(extension_event.Pass());
171 void LanguageSettingsPrivateDelegate::RefreshDictionaries(
172 bool was_listening, bool should_listen) {
173 if (!profile_added_)
174 return;
175 if (was_listening)
176 RemoveDictionaryObservers();
177 hunspell_dictionaries_.clear();
178 SpellcheckService* service = SpellcheckServiceFactory::GetForContext(
179 context_);
180 if (!custom_dictionary_)
181 custom_dictionary_ = service->GetCustomDictionary();
183 const ScopedVector<SpellcheckHunspellDictionary>& dictionaries(
184 service->GetHunspellDictionaries());
185 for (const auto& dictionary: dictionaries) {
186 hunspell_dictionaries_.push_back(dictionary->AsWeakPtr());
187 if (should_listen)
188 dictionary->AddObserver(this);
192 const LanguageSettingsPrivateDelegate::WeakDictionaries&
193 LanguageSettingsPrivateDelegate::GetHunspellDictionaries() {
194 // If there are no hunspell dictionaries, or the first is invalid, refresh.
195 if (!hunspell_dictionaries_.size() || !hunspell_dictionaries_.front())
196 RefreshDictionaries(listening_spellcheck_, listening_spellcheck_);
197 return hunspell_dictionaries_;
200 void LanguageSettingsPrivateDelegate::
201 StartOrStopListeningForSpellcheckChanges() {
202 EventRouter* event_router = EventRouter::Get(context_);
203 bool should_listen =
204 event_router->HasEventListener(language_settings_private::
205 OnSpellcheckDictionariesChanged::kEventName) ||
206 event_router->HasEventListener(language_settings_private::
207 OnCustomDictionaryChanged::kEventName);
209 if (should_listen && !listening_spellcheck_) {
210 // Update and observe the hunspell dictionaries.
211 RefreshDictionaries(listening_spellcheck_, should_listen);
212 // Observe the dictionaries preference.
213 pref_change_registrar_.Add(prefs::kSpellCheckDictionaries, base::Bind(
214 &LanguageSettingsPrivateDelegate::OnSpellcheckDictionariesChanged,
215 base::Unretained(this)));
216 // Observe the dictionary of custom words.
217 if (custom_dictionary_)
218 custom_dictionary_->AddObserver(this);
219 } else if (!should_listen && listening_spellcheck_) {
220 // Stop observing any dictionaries that still exist.
221 RemoveDictionaryObservers();
222 hunspell_dictionaries_.clear();
223 pref_change_registrar_.Remove(prefs::kSpellCheckDictionaries);
224 if (custom_dictionary_)
225 custom_dictionary_->RemoveObserver(this);
228 listening_spellcheck_ = should_listen;
231 void LanguageSettingsPrivateDelegate::OnSpellcheckDictionariesChanged() {
232 RefreshDictionaries(listening_spellcheck_, listening_spellcheck_);
233 BroadcastDictionariesChangedEvent();
236 void LanguageSettingsPrivateDelegate::BroadcastDictionariesChangedEvent() {
237 std::vector<linked_ptr<language_settings_private::SpellcheckDictionaryStatus>>
238 broadcast_statuses;
239 ScopedVector<language_settings_private::SpellcheckDictionaryStatus> statuses =
240 GetHunspellDictionaryStatuses();
242 for (language_settings_private::SpellcheckDictionaryStatus* status : statuses)
243 broadcast_statuses.push_back(make_linked_ptr(status));
244 statuses.weak_clear();
246 scoped_ptr<base::ListValue> args(
247 language_settings_private::OnSpellcheckDictionariesChanged::Create(
248 broadcast_statuses));
249 scoped_ptr<extensions::Event> extension_event(new extensions::Event(
250 events::LANGUAGE_SETTINGS_PRIVATE_ON_SPELLCHECK_DICTIONARIES_CHANGED,
251 language_settings_private::OnSpellcheckDictionariesChanged::kEventName,
252 args.Pass()));
253 EventRouter::Get(context_)->BroadcastEvent(extension_event.Pass());
256 void LanguageSettingsPrivateDelegate::RemoveDictionaryObservers() {
257 for (const auto& dictionary : hunspell_dictionaries_) {
258 if (dictionary)
259 dictionary->RemoveObserver(this);
263 } // namespace extensions