Index: chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.cc |
diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.cc |
index 2f0d4c3c448f0c6bc8fcbd1ba6e36fb95d1bd541..13b8940ad716bfff75a46e88e109ed125b7b4d75 100644 |
--- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.cc |
+++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.cc |
@@ -4,7 +4,24 @@ |
#include "chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.h" |
+#include <string> |
+#include <vector> |
+ |
+#include "base/bind.h" |
+#include "base/bind_helpers.h" |
+#include "base/memory/linked_ptr.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "base/memory/scoped_vector.h" |
+#include "base/prefs/pref_service.h" |
+#include "base/strings/utf_string_conversions.h" |
+#include "chrome/browser/browser_process.h" |
+#include "chrome/browser/chrome_notification_types.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/spellchecker/spellcheck_factory.h" |
+#include "chrome/browser/spellchecker/spellcheck_service.h" |
+#include "chrome/common/pref_names.h" |
#include "content/public/browser/browser_context.h" |
+#include "content/public/browser/notification_source.h" |
namespace extensions { |
@@ -12,8 +29,10 @@ namespace language_settings_private = api::language_settings_private; |
LanguageSettingsPrivateDelegate::LanguageSettingsPrivateDelegate( |
content::BrowserContext* context) |
- : context_(context), |
- listening_spellcheck_(false) { |
+ : custom_dictionary_(nullptr), |
+ context_(context), |
+ listening_spellcheck_(false), |
+ profile_added_(false) { |
// Register with the event router so we know when renderers are listening to |
// our events. We first check and see if there *is* an event router, because |
// some unit tests try to create all context services, but don't initialize |
@@ -27,11 +46,22 @@ LanguageSettingsPrivateDelegate::LanguageSettingsPrivateDelegate( |
event_router->RegisterObserver(this, |
language_settings_private::OnCustomDictionaryChanged::kEventName); |
+ // SpellcheckService cannot be created until Profile::DoFinalInit() has been |
+ // called. http://crbug.com/171406 |
+ notification_registrar_.Add(this, |
+ chrome::NOTIFICATION_PROFILE_ADDED, |
+ content::Source<Profile>(Profile::FromBrowserContext(context_))); |
+ |
+ pref_change_registrar_.Init(Profile::FromBrowserContext(context_)-> |
+ GetPrefs()); |
+ |
StartOrStopListeningForSpellcheckChanges(); |
} |
LanguageSettingsPrivateDelegate::~LanguageSettingsPrivateDelegate() { |
DCHECK(!listening_spellcheck_); |
+ pref_change_registrar_.RemoveAll(); |
+ notification_registrar_.RemoveAll(); |
} |
LanguageSettingsPrivateDelegate* LanguageSettingsPrivateDelegate::Create( |
@@ -39,6 +69,27 @@ LanguageSettingsPrivateDelegate* LanguageSettingsPrivateDelegate::Create( |
return new LanguageSettingsPrivateDelegate(context); |
} |
+ScopedVector<language_settings_private::SpellcheckDictionaryStatus> |
+LanguageSettingsPrivateDelegate::GetHunspellDictionaryStatuses() { |
+ ScopedVector<language_settings_private::SpellcheckDictionaryStatus> statuses; |
+ for (const auto& dictionary : GetHunspellDictionaries()) { |
+ if (!dictionary) |
+ continue; |
+ scoped_ptr<language_settings_private::SpellcheckDictionaryStatus> status( |
+ new language_settings_private::SpellcheckDictionaryStatus()); |
+ status->language_code = dictionary->GetLanguage(); |
+ status->is_ready = dictionary->IsReady(); |
+ if (!status->is_ready) { |
+ if (dictionary->IsDownloadInProgress()) |
+ status->is_downloading.reset(new bool(true)); |
+ if (dictionary->IsDownloadFailure()) |
+ status->download_failed.reset(new bool(true)); |
+ } |
+ statuses.push_back(status.Pass()); |
+ } |
+ return statuses.Pass(); |
+} |
+ |
void LanguageSettingsPrivateDelegate::Shutdown() { |
// Unregister with the event router. We first check and see if there *is* an |
// event router, because some unit tests try to shutdown all context services, |
@@ -48,10 +99,9 @@ void LanguageSettingsPrivateDelegate::Shutdown() { |
event_router->UnregisterObserver(this); |
if (listening_spellcheck_) { |
- // TODO(michaelpg): unregister observers. |
+ RemoveDictionaryObservers(); |
+ listening_spellcheck_ = false; |
} |
- |
- listening_spellcheck_ = false; |
} |
void LanguageSettingsPrivateDelegate::OnListenerAdded( |
@@ -71,6 +121,78 @@ void LanguageSettingsPrivateDelegate::OnListenerRemoved( |
StartOrStopListeningForSpellcheckChanges(); |
} |
+void LanguageSettingsPrivateDelegate::Observe( |
+ int type, |
+ const content::NotificationSource& source, |
+ const content::NotificationDetails& details) { |
+ profile_added_ = true; |
+ StartOrStopListeningForSpellcheckChanges(); |
+} |
+ |
+void LanguageSettingsPrivateDelegate::OnHunspellDictionaryInitialized() { |
+ BroadcastDictionariesChangedEvent(); |
+} |
+ |
+void LanguageSettingsPrivateDelegate::OnHunspellDictionaryDownloadBegin() { |
+ BroadcastDictionariesChangedEvent(); |
+} |
+ |
+void LanguageSettingsPrivateDelegate::OnHunspellDictionaryDownloadSuccess() { |
+ BroadcastDictionariesChangedEvent(); |
+} |
+ |
+void LanguageSettingsPrivateDelegate::OnHunspellDictionaryDownloadFailure() { |
+ BroadcastDictionariesChangedEvent(); |
+} |
+ |
+void LanguageSettingsPrivateDelegate::OnCustomDictionaryLoaded() { |
+} |
+ |
+void LanguageSettingsPrivateDelegate::OnCustomDictionaryChanged( |
+ const SpellcheckCustomDictionary::Change& change) { |
+ std::vector<std::string> to_add(change.to_add().begin(), |
+ change.to_add().end()); |
+ std::vector<std::string> to_remove(change.to_remove().begin(), |
+ change.to_remove().end()); |
+ scoped_ptr<base::ListValue> args( |
+ language_settings_private::OnCustomDictionaryChanged::Create( |
+ to_add, to_remove)); |
+ scoped_ptr<Event> extension_event(new Event( |
+ events::LANGUAGE_SETTINGS_PRIVATE_ON_CUSTOM_DICTIONARY_CHANGED, |
+ language_settings_private::OnCustomDictionaryChanged::kEventName, |
+ args.Pass())); |
+ EventRouter::Get(context_)->BroadcastEvent(extension_event.Pass()); |
+} |
+ |
+void LanguageSettingsPrivateDelegate::RefreshDictionaries( |
+ bool was_listening, bool should_listen) { |
+ if (!profile_added_) |
+ return; |
+ if (was_listening) |
+ RemoveDictionaryObservers(); |
+ hunspell_dictionaries_.clear(); |
+ SpellcheckService* service = SpellcheckServiceFactory::GetForContext( |
+ context_); |
+ if (!custom_dictionary_) |
+ custom_dictionary_ = service->GetCustomDictionary(); |
+ |
+ const ScopedVector<SpellcheckHunspellDictionary>& dictionaries( |
+ service->GetHunspellDictionaries()); |
+ for (const auto& dictionary: dictionaries) { |
+ hunspell_dictionaries_.push_back(dictionary->AsWeakPtr()); |
+ if (should_listen) |
+ dictionary->AddObserver(this); |
+ } |
+} |
+ |
+const LanguageSettingsPrivateDelegate::WeakDictionaries& |
+LanguageSettingsPrivateDelegate::GetHunspellDictionaries() { |
+ // If there are no hunspell dictionaries, or the first is invalid, refresh. |
+ if (!hunspell_dictionaries_.size() || !hunspell_dictionaries_.front()) |
+ RefreshDictionaries(listening_spellcheck_, listening_spellcheck_); |
+ return hunspell_dictionaries_; |
+} |
+ |
void LanguageSettingsPrivateDelegate:: |
StartOrStopListeningForSpellcheckChanges() { |
EventRouter* event_router = EventRouter::Get(context_); |
@@ -81,12 +203,57 @@ void LanguageSettingsPrivateDelegate:: |
OnCustomDictionaryChanged::kEventName); |
if (should_listen && !listening_spellcheck_) { |
- // TODO: register observers. |
+ // Update and observe the hunspell dictionaries. |
+ RefreshDictionaries(listening_spellcheck_, should_listen); |
+ // Observe the dictionaries preference. |
+ pref_change_registrar_.Add(prefs::kSpellCheckDictionaries, base::Bind( |
+ &LanguageSettingsPrivateDelegate::OnSpellcheckDictionariesChanged, |
+ base::Unretained(this))); |
+ // Observe the dictionary of custom words. |
+ if (custom_dictionary_) |
+ custom_dictionary_->AddObserver(this); |
} else if (!should_listen && listening_spellcheck_) { |
- // TODO(michaelpg): unregister observers. |
+ // Stop observing any dictionaries that still exist. |
+ RemoveDictionaryObservers(); |
+ hunspell_dictionaries_.clear(); |
+ pref_change_registrar_.Remove(prefs::kSpellCheckDictionaries); |
+ if (custom_dictionary_) |
+ custom_dictionary_->RemoveObserver(this); |
} |
listening_spellcheck_ = should_listen; |
} |
+void LanguageSettingsPrivateDelegate::OnSpellcheckDictionariesChanged() { |
+ RefreshDictionaries(listening_spellcheck_, listening_spellcheck_); |
+ BroadcastDictionariesChangedEvent(); |
+} |
+ |
+void LanguageSettingsPrivateDelegate::BroadcastDictionariesChangedEvent() { |
+ std::vector<linked_ptr<language_settings_private::SpellcheckDictionaryStatus>> |
+ broadcast_statuses; |
+ ScopedVector<language_settings_private::SpellcheckDictionaryStatus> statuses = |
+ GetHunspellDictionaryStatuses(); |
+ |
+ for (language_settings_private::SpellcheckDictionaryStatus* status : statuses) |
+ broadcast_statuses.push_back(make_linked_ptr(status)); |
+ statuses.weak_clear(); |
+ |
+ scoped_ptr<base::ListValue> args( |
+ language_settings_private::OnSpellcheckDictionariesChanged::Create( |
+ broadcast_statuses)); |
+ scoped_ptr<extensions::Event> extension_event(new extensions::Event( |
+ events::LANGUAGE_SETTINGS_PRIVATE_ON_SPELLCHECK_DICTIONARIES_CHANGED, |
+ language_settings_private::OnSpellcheckDictionariesChanged::kEventName, |
+ args.Pass())); |
+ EventRouter::Get(context_)->BroadcastEvent(extension_event.Pass()); |
+} |
+ |
+void LanguageSettingsPrivateDelegate::RemoveDictionaryObservers() { |
+ for (const auto& dictionary : hunspell_dictionaries_) { |
+ if (dictionary) |
+ dictionary->RemoveObserver(this); |
+ } |
+} |
+ |
} // namespace extensions |