diff options
author | sidchat@google.com <sidchat@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-15 19:30:41 +0000 |
---|---|---|
committer | sidchat@google.com <sidchat@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-15 19:30:41 +0000 |
commit | 209308572c06cc9d0a7c38e37928d6765ef9f4c7 (patch) | |
tree | 294a02a68af2475e624e7a8490525c7198ac521f /chrome | |
parent | ece541a4d861b2fd0d83ea32dec75d233e217d5c (diff) | |
download | chromium_src-209308572c06cc9d0a7c38e37928d6765ef9f4c7.zip chromium_src-209308572c06cc9d0a7c38e37928d6765ef9f4c7.tar.gz chromium_src-209308572c06cc9d0a7c38e37928d6765ef9f4c7.tar.bz2 |
Change SpellChecker language without restarting the browser.
Review URL: http://codereview.chromium.org/7056
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3407 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/profile.cc | 89 | ||||
-rw-r--r-- | chrome/browser/profile.h | 18 | ||||
-rw-r--r-- | chrome/browser/resource_message_filter.cc | 22 | ||||
-rw-r--r-- | chrome/browser/resource_message_filter.h | 14 | ||||
-rw-r--r-- | chrome/browser/views/options/languages_page_view.cc | 21 | ||||
-rw-r--r-- | chrome/browser/views/options/languages_page_view.h | 4 | ||||
-rw-r--r-- | chrome/common/notification_types.h | 5 | ||||
-rw-r--r-- | chrome/test/testing_profile.h | 2 |
8 files changed, 150 insertions, 25 deletions
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index ad2ddb1..bf40016 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -479,6 +479,10 @@ class OffTheRecordProfileImpl : public Profile, return NULL; } + virtual void InitializeSpellChecker() { + profile_->InitializeSpellChecker(); + } + virtual void ResetTabRestoreService() { } @@ -837,24 +841,79 @@ void ProfileImpl::ResetTabRestoreService() { tab_restore_service_.reset(NULL); } +// To be run in the IO thread to notify all resource message filters that the +// spellchecker has changed. +class NotifySpellcheckerChangeTask : public Task { + public: + NotifySpellcheckerChangeTask( + Profile* profile, const SpellcheckerReinitializedDetails& spellchecker) + : profile_(profile), + spellchecker_(spellchecker) { + } + + private: + void Run(void) { + NotificationService::current()->Notify( + NOTIFY_SPELLCHECKER_REINITIALIZED, + Source<Profile>(profile_), + Details<SpellcheckerReinitializedDetails>(&spellchecker_)); + } + + Profile* profile_; + SpellcheckerReinitializedDetails spellchecker_; +}; + +void ProfileImpl::InitializeSpellChecker() { + bool need_to_broadcast = false; + + // The I/O thread may be NULL during testing. + base::Thread* io_thread = g_browser_process->io_thread(); + if (spellchecker_) { + // The spellchecker must be deleted on the I/O thread. + // A dummy variable to aid in logical clarity. + SpellChecker* last_spellchecker = spellchecker_; + + if (io_thread) + io_thread->message_loop()->ReleaseSoon(FROM_HERE, last_spellchecker); + else // during testing, we don't have an I/O thread + last_spellchecker->Release(); + + need_to_broadcast = true; + } + + std::wstring dict_dir; + PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); + + // Retrieve the (perhaps updated recently) dictionary name from preferences. + PrefService* prefs = GetPrefs(); + std::wstring language = prefs->GetString(prefs::kSpellCheckDictionary); + + // Note that, as the object pointed to by previously by spellchecker_ + // is being deleted in the io thread, the spellchecker_ can be made to point + // to a new object (RE-initialized) in parallel in this UI thread. + spellchecker_ = new SpellChecker(dict_dir, language, GetRequestContext(), + L""); + spellchecker_->AddRef(); // Manual refcounting. + + if (need_to_broadcast && io_thread) { // Notify resource message filters. + SpellcheckerReinitializedDetails scoped_spellchecker; + scoped_spellchecker.spellchecker = spellchecker_; + io_thread->message_loop()->PostTask( + FROM_HERE, + new NotifySpellcheckerChangeTask(this, scoped_spellchecker)); + } +} + SpellChecker* ProfileImpl::GetSpellChecker() { if (!spellchecker_) { - // Don't check for an error here. In the extremely unlikely case that this - // fails, the spellchecker just won't find the file. This prevents callers - // from having to check for NULL return values from this function. - std::wstring dict_dir; - PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); - - // Retrieve the dictionary name from preferences or the language DLL. - // When we retrieve it from the language DLL. - PrefService* prefs = GetPrefs(); - std::wstring dictionary_name = prefs->GetString( - prefs::kSpellCheckDictionary); - - spellchecker_ = new SpellChecker(dict_dir, dictionary_name, - GetRequestContext(), L""); - spellchecker_->AddRef(); // Manual refcounting. + // This is where spellchecker gets initialized. Note that this is being + // initialized in the ui_thread. However, this is not a problem as long as + // it is *used* in the io thread. + // TODO (sidchat) One day, change everything so that spellchecker gets + // initialized in the IO thread itself. + InitializeSpellChecker(); } + return spellchecker_; } diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index 09b0baf..2edc40c 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -194,6 +194,13 @@ class Profile { virtual void ResetTabRestoreService() = 0; + // Initializes the spellchecker. If the spellchecker already exsts, then + // it is released, and initialized again. This model makes sure that + // spellchecker language can be changed without restarting the browser. + // NOTE: This is being currently called in the UI thread, which is OK as long + // as the spellchecker object is USED in the IO thread. + virtual void InitializeSpellChecker() = 0; + // Returns the spell checker object for this profile. THIS OBJECT MUST ONLY // BE USED ON THE I/O THREAD! This pointer is retrieved from the profile and // sent to the I/O thread where it is actually used. @@ -203,8 +210,7 @@ class Profile { // // NOTE: this is invoked internally on a normal shutdown, but is public so // that it can be invoked when the user logs out/powers down (WM_ENDSESSION). - virtual void MarkAsCleanShutdown() = 0; - + virtual void MarkAsCleanShutdown() = 0; #ifdef UNIT_TEST // Use with caution. GetDefaultRequestContext may be called on any thread! static void set_default_request_context(URLRequestContext* c) { @@ -250,6 +256,7 @@ class ProfileImpl : public Profile { virtual Time GetStartTime() const; virtual TabRestoreService* GetTabRestoreService(); virtual void ResetTabRestoreService(); + virtual void InitializeSpellChecker(); virtual SpellChecker* GetSpellChecker(); virtual void MarkAsCleanShutdown(); #ifdef CHROME_PERSONALIZATION @@ -316,5 +323,12 @@ class ProfileImpl : public Profile { DISALLOW_EVIL_CONSTRUCTORS(ProfileImpl); }; +// This struct is used to pass the spellchecker object through the notification +// NOTIFY_SPELLCHECKER_REINITIALIZED. This is used as the details for the +// notification service. +struct SpellcheckerReinitializedDetails { + scoped_refptr<SpellChecker> spellchecker; +}; + #endif // CHROME_BROWSER_PROFILE_H__ diff --git a/chrome/browser/resource_message_filter.cc b/chrome/browser/resource_message_filter.cc index 4821cfd..5afe628 100644 --- a/chrome/browser/resource_message_filter.cc +++ b/chrome/browser/resource_message_filter.cc @@ -91,6 +91,7 @@ ResourceMessageFilter::ResourceMessageFilter( render_process_host_id_(render_process_host_id), render_handle_(NULL), request_context_(profile->GetRequestContext()), + profile_(profile), render_widget_helper_(render_widget_helper), spellchecker_(spellchecker) { @@ -101,11 +102,23 @@ ResourceMessageFilter::ResourceMessageFilter( ResourceMessageFilter::~ResourceMessageFilter() { if (render_handle_) CloseHandle(render_handle_); + + // This function should be called on the IO thread. + DCHECK(MessageLoop::current() == + ChromeThread::GetMessageLoop(ChromeThread::IO)); + NotificationService::current()->RemoveObserver( + this, NOTIFY_SPELLCHECKER_REINITIALIZED, + Source<Profile>(profile_)); } // Called on the IPC thread: void ResourceMessageFilter::OnFilterAdded(IPC::Channel* channel) { channel_ = channel; + + // Add the observers to intercept + NotificationService::current()->AddObserver( + this, NOTIFY_SPELLCHECKER_REINITIALIZED, + Source<Profile>(profile_)); } // Called on the IPC thread: @@ -738,6 +751,15 @@ void ResourceMessageFilter::OnSpellCheck(const std::wstring& word, } } +void ResourceMessageFilter::Observe(NotificationType type, + const NotificationSource &source, + const NotificationDetails &details) { + if (type == NOTIFY_SPELLCHECKER_REINITIALIZED) { + spellchecker_ = Details<SpellcheckerReinitializedDetails> + (details).ptr()->spellchecker; + } +} + void ResourceMessageFilter::OnDnsPrefetch( const std::vector<std::string>& hostnames) { chrome_browser_net::DnsPrefetchList(hostnames); diff --git a/chrome/browser/resource_message_filter.h b/chrome/browser/resource_message_filter.h index a83a0e9..aee07c1 100644 --- a/chrome/browser/resource_message_filter.h +++ b/chrome/browser/resource_message_filter.h @@ -9,6 +9,7 @@ #include "base/ref_counted.h" #include "chrome/browser/resource_dispatcher_host.h" #include "chrome/common/ipc_channel_proxy.h" +#include "chrome/common/notification_service.h" #include "webkit/glue/cache_manager.h" class ClipboardService; @@ -29,12 +30,13 @@ class PrintJobManager; // will not interfere with browser UI. class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, - public ResourceDispatcherHost::Receiver { + public ResourceDispatcherHost::Receiver, + public NotificationObserver { public: // Create the filter. // Note: because the lifecycle of the ResourceMessageFilter is not // tied to the lifecycle of the object which created it, the - // ResourceMessageFilter is 'given' ownership of the spellcker + // ResourceMessageFilter is 'given' ownership of the spellchecker // object and must clean it up on exit. ResourceMessageFilter(ResourceDispatcherHost* resource_dispatcher_host, PluginService* plugin_service, @@ -60,6 +62,11 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, int render_process_host_id() const { return render_process_host_id_;} HANDLE renderer_handle() const { return render_handle_;} + + // NotificationObserver implementation. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); private: void OnMsgCreateView(int opener_id, bool user_gesture, int* route_id, @@ -176,6 +183,9 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, // Contextual information to be used for requests created here. scoped_refptr<URLRequestContext> request_context_; + // Save the profile pointer so that notification observer can be added. + Profile* profile_; + scoped_refptr<RenderWidgetHelper> render_widget_helper_; }; diff --git a/chrome/browser/views/options/languages_page_view.cc b/chrome/browser/views/options/languages_page_view.cc index 465a2fa..9a22c74 100644 --- a/chrome/browser/views/options/languages_page_view.cc +++ b/chrome/browser/views/options/languages_page_view.cc @@ -681,6 +681,7 @@ void LanguagesPageView::NotifyPrefChanged(const std::wstring* pref_name) { int index = dictionary_language_model_->GetSelectedLanguageIndex( prefs::kSpellCheckDictionary); change_dictionary_language_combobox_->SetSelectedItem(index); + spellcheck_language_index_selected_ = -1; } } @@ -693,11 +694,8 @@ void LanguagesPageView::ItemChanged(ChromeViews::ComboBox* sender, app_locale_.SetValue(ui_language_model_->GetLocaleFromIndex(new_index)); RestartMessageBox::ShowMessageBox(GetRootWindow()); } else if (sender == change_dictionary_language_combobox_) { - UserMetricsRecordAction(L"Options_DictionaryLanguage", - profile()->GetPrefs()); - dictionary_language_.SetValue(dictionary_language_model_-> - GetLocaleFromIndex(new_index)); - RestartMessageBox::ShowMessageBox(GetRootWindow()); + if (new_index != prev_index) + spellcheck_language_index_selected_ = new_index; } } @@ -750,5 +748,16 @@ void LanguagesPageView::OnMoveUpLanguage() { void LanguagesPageView::SaveChanges() { if (language_order_table_model_.get() && language_table_edited_) accept_languages_.SetValue(language_order_table_model_->GetLanguageList()); -} + if (spellcheck_language_index_selected_ != -1) { + UserMetricsRecordAction(L"Options_DictionaryLanguage", + profile()->GetPrefs()); + dictionary_language_.SetValue(dictionary_language_model_-> + GetLocaleFromIndex(spellcheck_language_index_selected_)); + + // Initialize spellchecker. Keeping with the tradition, spellchecker is + // being initialized in this UI thread. However, it must be USED in the IO + // thread. + profile()->InitializeSpellChecker(); + } +} diff --git a/chrome/browser/views/options/languages_page_view.h b/chrome/browser/views/options/languages_page_view.h index 41c362f..fc7d0b0 100644 --- a/chrome/browser/views/options/languages_page_view.h +++ b/chrome/browser/views/options/languages_page_view.h @@ -89,6 +89,10 @@ class LanguagesPageView : public OptionsPageView, // The contents of the "dictionary language" combobox. scoped_ptr<LanguageComboboxModel> dictionary_language_model_; StringPrefMember dictionary_language_; + + // This is assigned the new index of spellcheck language if the language + // is changed. Otherwise, it remains -1, and pref members are not updated. + int spellcheck_language_index_selected_; bool language_table_edited_; diff --git a/chrome/common/notification_types.h b/chrome/common/notification_types.h index 4340c9b..29ba6e1 100644 --- a/chrome/common/notification_types.h +++ b/chrome/common/notification_types.h @@ -397,6 +397,11 @@ enum NotificationType { // Profile, and the details aren't used. NOTIFY_BOOKMARK_MODEL_LOADED, + // Sent when the spellchecker object changes. Note that this is not sent the + // first time the spellchecker gets initialized. The source is the profile, + // the details is SpellcheckerReinitializedDetails defined in profile. + NOTIFY_SPELLCHECKER_REINITIALIZED, + // Sent when the bookmark bubble is shown for a particular URL. The source // is the profile, the details the URL. NOTIFY_BOOKMARK_BUBBLE_SHOWN, diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index c68e9fcb..892d357 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -140,6 +140,8 @@ class TestingProfile : public Profile { } virtual void ResetTabRestoreService() { } + virtual void InitializeSpellChecker() { + } virtual SpellChecker* GetSpellChecker() { return NULL; } |