diff options
author | sidchat@google.com <sidchat@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-17 20:02:04 +0000 |
---|---|---|
committer | sidchat@google.com <sidchat@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-17 20:02:04 +0000 |
commit | 63271da3b3740aadd3bd5d186bf7bd2b33ee6347 (patch) | |
tree | 43ab35878220b56a78a8dda05b775df87ddacc4e /chrome/browser | |
parent | 64b421f984b2dfe04546729f8b35648cac3d0f20 (diff) | |
download | chromium_src-63271da3b3740aadd3bd5d186bf7bd2b33ee6347.zip chromium_src-63271da3b3740aadd3bd5d186bf7bd2b33ee6347.tar.gz chromium_src-63271da3b3740aadd3bd5d186bf7bd2b33ee6347.tar.bz2 |
Add support for "Add to dictionary" in the context menu.
Review URL: http://codereview.chromium.org/2446
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2322 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/profile.cc | 2 | ||||
-rw-r--r-- | chrome/browser/render_process_host.cc | 7 | ||||
-rw-r--r-- | chrome/browser/render_process_host.h | 3 | ||||
-rw-r--r-- | chrome/browser/render_view_context_menu.cc | 8 | ||||
-rw-r--r-- | chrome/browser/render_view_context_menu.h | 2 | ||||
-rw-r--r-- | chrome/browser/render_view_context_menu_controller.cc | 7 | ||||
-rw-r--r-- | chrome/browser/render_view_host.cc | 4 | ||||
-rw-r--r-- | chrome/browser/render_view_host.h | 1 | ||||
-rw-r--r-- | chrome/browser/resource_message_filter.cc | 13 | ||||
-rw-r--r-- | chrome/browser/spellchecker.cc | 84 | ||||
-rw-r--r-- | chrome/browser/spellchecker.h | 18 | ||||
-rw-r--r-- | chrome/browser/web_contents.cc | 12 | ||||
-rw-r--r-- | chrome/browser/web_contents.h | 1 |
13 files changed, 150 insertions, 12 deletions
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index dacbe95..745b1a8 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -853,7 +853,7 @@ SpellChecker* ProfileImpl::GetSpellChecker() { prefs::kSpellCheckDictionary); spellchecker_ = new SpellChecker(dict_dir, dictionary_name, - GetRequestContext()); + GetRequestContext(), L""); spellchecker_->AddRef(); // Manual refcounting. } return spellchecker_; diff --git a/chrome/browser/render_process_host.cc b/chrome/browser/render_process_host.cc index f101fa8..90ff2aa 100644 --- a/chrome/browser/render_process_host.cc +++ b/chrome/browser/render_process_host.cc @@ -35,6 +35,7 @@ #include "chrome/browser/renderer_security_policy.h" #include "chrome/browser/resource_message_filter.h" #include "chrome/browser/sandbox_policy.h" +#include "chrome/browser/spellchecker.h" #include "chrome/browser/visitedlink_master.h" #include "chrome/browser/web_contents.h" #include "chrome/common/chrome_constants.h" @@ -722,6 +723,12 @@ void RenderProcessHost::WidgetHidden() { } } +void RenderProcessHost::AddWord(const std::wstring& word) { + base::Thread* io_thread = g_browser_process->io_thread(); + io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + profile_->GetSpellChecker(), &SpellChecker::AddWord, word)); +} + // NotificationObserver implementation. void RenderProcessHost::Observe(NotificationType type, const NotificationSource& source, diff --git a/chrome/browser/render_process_host.h b/chrome/browser/render_process_host.h index f725544..fd76ad7 100644 --- a/chrome/browser/render_process_host.h +++ b/chrome/browser/render_process_host.h @@ -181,6 +181,9 @@ class RenderProcessHost : public IPC::Channel::Listener, // to register/unregister visibility. void WidgetRestored(); void WidgetHidden(); + + // Add a word in the spellchecker. + void AddWord(const std::wstring& word); // NotificationObserver implementation. virtual void Observe(NotificationType type, diff --git a/chrome/browser/render_view_context_menu.cc b/chrome/browser/render_view_context_menu.cc index e8205af..96a584c 100644 --- a/chrome/browser/render_view_context_menu.cc +++ b/chrome/browser/render_view_context_menu.cc @@ -16,9 +16,11 @@ RenderViewContextMenu::RenderViewContextMenu( Menu::Delegate* delegate, HWND owner, ContextNode::Type type, + const std::wstring& misspelled_word, const std::vector<std::wstring>& misspelled_word_suggestions, Profile* profile) : Menu(delegate, Menu::TOPLEFT, owner), + misspelled_word_(misspelled_word), misspelled_word_suggestions_(misspelled_word_suggestions), profile_(profile) { InitMenu(type); @@ -120,6 +122,12 @@ void RenderViewContextMenu::AppendEditableItems() { } if (misspelled_word_suggestions_.size() > 0) AppendSeparator(); + + // If word is misspelled, give option for "Add to dictionary" + if (!misspelled_word_.empty()) { + AppendDelegateMenuItem(IDS_CONTENT_CONTEXT_ADD_TO_DICTIONARY); + AppendSeparator(); + } AppendDelegateMenuItem(IDS_CONTENT_CONTEXT_UNDO); AppendDelegateMenuItem(IDS_CONTENT_CONTEXT_REDO); diff --git a/chrome/browser/render_view_context_menu.h b/chrome/browser/render_view_context_menu.h index 57e5f63..a306d7f 100644 --- a/chrome/browser/render_view_context_menu.h +++ b/chrome/browser/render_view_context_menu.h @@ -16,6 +16,7 @@ class RenderViewContextMenu : public Menu { Menu::Delegate* delegate, HWND owner, ContextNode::Type type, + const std::wstring& misspelled_word, const std::vector<std::wstring>& misspelled_word_suggestions, Profile* profile); @@ -31,6 +32,7 @@ class RenderViewContextMenu : public Menu { void AppendSelectionItems(); void AppendEditableItems(); + std::wstring misspelled_word_; std::vector<std::wstring> misspelled_word_suggestions_; Profile* profile_; diff --git a/chrome/browser/render_view_context_menu_controller.cc b/chrome/browser/render_view_context_menu_controller.cc index 8ea251e..39f5b9e 100644 --- a/chrome/browser/render_view_context_menu_controller.cc +++ b/chrome/browser/render_view_context_menu_controller.cc @@ -169,7 +169,8 @@ bool RenderViewContextMenuController::IsCommandEnabled(int id) const { case IDC_USESPELLCHECKSUGGESTION_3: case IDC_USESPELLCHECKSUGGESTION_4: return true; - + case IDS_CONTENT_CONTEXT_ADD_TO_DICTIONARY: + return !params_.misspelled_word.empty(); case IDS_CONTENT_CONTEXT_VIEWPAGEINFO: case IDS_CONTENT_CONTEXT_VIEWFRAMEINFO: case IDS_CONTENT_CONTEXT_SAVEFRAMEAS: @@ -368,6 +369,10 @@ void RenderViewContextMenuController::ExecuteCommand(int id) { id - IDC_USESPELLCHECKSUGGESTION_0]); break; + case IDS_CONTENT_CONTEXT_ADD_TO_DICTIONARY: + source_web_contents_->AddToDictionary(params_.misspelled_word); + break; + case IDS_CONTENT_CONTEXT_ADDSEARCHENGINE: // Not implemented. default: break; diff --git a/chrome/browser/render_view_host.cc b/chrome/browser/render_view_host.cc index 4f02aaca..8c95e07 100644 --- a/chrome/browser/render_view_host.cc +++ b/chrome/browser/render_view_host.cc @@ -452,6 +452,10 @@ void RenderViewHost::Replace(const std::wstring& text_to_replace) { Send(new ViewMsg_Replace(routing_id_, text_to_replace)); } +void RenderViewHost::AddToDictionary(const std::wstring& word) { + process_->AddWord(word); +} + void RenderViewHost::Delete() { Send(new ViewMsg_Delete(routing_id_)); } diff --git a/chrome/browser/render_view_host.h b/chrome/browser/render_view_host.h index 5e0543d..b6d968d 100644 --- a/chrome/browser/render_view_host.h +++ b/chrome/browser/render_view_host.h @@ -256,6 +256,7 @@ class RenderViewHost : public RenderWidgetHost { void Copy(); void Paste(); void Replace(const std::wstring& text); + void AddToDictionary(const std::wstring& word); void Delete(); void SelectAll(); diff --git a/chrome/browser/resource_message_filter.cc b/chrome/browser/resource_message_filter.cc index 3c833d8..4821cfd 100644 --- a/chrome/browser/resource_message_filter.cc +++ b/chrome/browser/resource_message_filter.cc @@ -245,10 +245,15 @@ void ResourceMessageFilter::OnReceiveContextMenuMsg(const IPC::Message& msg) { if (!params.misspelled_word.empty() && spellchecker_ != NULL) { int misspell_location, misspell_length; - spellchecker_->SpellCheckWord(params.misspelled_word.c_str(), - static_cast<int>(params.misspelled_word.length()), - &misspell_location, &misspell_length, - ¶ms.dictionary_suggestions); + bool is_misspelled = !spellchecker_->SpellCheckWord( + params.misspelled_word.c_str(), + static_cast<int>(params.misspelled_word.length()), + &misspell_location, &misspell_length, + ¶ms.dictionary_suggestions); + + // If not misspelled, make the misspelled_word param empty. + if (!is_misspelled) + params.misspelled_word.clear(); } // Create a new ViewHostMsg_ContextMenu message. diff --git a/chrome/browser/spellchecker.cc b/chrome/browser/spellchecker.cc index ecb3874..43df962 100644 --- a/chrome/browser/spellchecker.cc +++ b/chrome/browser/spellchecker.cc @@ -5,11 +5,11 @@ #include <io.h> #include "chrome/browser/spellchecker.h" - #include "base/basictypes.h" #include "base/file_util.h" #include "base/histogram.h" #include "base/logging.h" +#include "base/path_service.h" #include "base/string_util.h" #include "base/thread.h" #include "base/win_util.h" @@ -17,7 +17,9 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/profile.h" #include "chrome/browser/url_fetcher.h" +#include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_counters.h" +#include "chrome/common/chrome_paths.h" #include "chrome/common/l10n_util.h" #include "chrome/common/pref_names.h" #include "chrome/common/pref_service.h" @@ -194,8 +196,10 @@ void SpellChecker::RegisterUserPrefs(PrefService* prefs) { SpellChecker::SpellChecker(const std::wstring& dict_dir, const std::wstring& language, - URLRequestContext* request_context) + URLRequestContext* request_context, + const std::wstring& custom_dictionary_file_name) : bdict_file_name_(dict_dir), + custom_dictionary_file_name_(custom_dictionary_file_name), bdict_file_(NULL), bdict_mapping_(NULL), bdict_mapped_data_(NULL), @@ -221,6 +225,15 @@ SpellChecker::SpellChecker(const std::wstring& dict_dir, // Get the path to the spellcheck file. file_util::AppendToPath(&bdict_file_name_, language + L".bdic"); + // Get the path to the custom dictionary file. + if (custom_dictionary_file_name_.empty()) { + std::wstring personal_file_directory; + PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); + custom_dictionary_file_name_ = personal_file_directory; + file_util::AppendToPath(&custom_dictionary_file_name_, + chrome::kCustomDictionaryFileName); + } + // Use this dictionary language as the default one of the // SpecllcheckCharAttribute object. character_attributes_.SetDefaultLanguage(language); @@ -288,8 +301,10 @@ bool SpellChecker::Initialize() { const unsigned char* bdict_data; size_t bdict_length; - if (MapBdictFile(&bdict_data, &bdict_length)) + if (MapBdictFile(&bdict_data, &bdict_length)) { hunspell_ = new Hunspell(bdict_data, bdict_length); + AddCustomWordsToHunspell(); + } TimeTicks end_time = TimeTicks::Now(); DHISTOGRAM_TIMES(L"Spellcheck.InitTime", end_time - begin_time); @@ -298,6 +313,23 @@ bool SpellChecker::Initialize() { return false; } +void SpellChecker::AddCustomWordsToHunspell() { + // Add custom words to Hunspell. + // This should be done in File Loop, but since Hunspell is in this IO Loop, + // this too has to be initialized here. + // TODO (sidchat): Work out a way to initialize Hunspell in the File Loop. + std::string contents; + file_util::ReadFileToString(custom_dictionary_file_name_, &contents); + std::vector<std::string> list_of_words; + SplitString(contents, '\n', &list_of_words); + if (hunspell_) { + for (std::vector<std::string>::iterator it = list_of_words.begin(); + it < list_of_words.end(); ++it) { + hunspell_->put_word((*it).c_str()); + } + } +} + bool SpellChecker::MapBdictFile(const unsigned char** data, size_t* length) { bdict_file_ = CreateFile(bdict_file_name_.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -422,3 +454,49 @@ bool SpellChecker::SpellCheckWord( return true; } +// This task is called in the file loop to write the new word to the custom +// dictionary in disc. +class AddWordToCustomDictionaryTask : public Task { + public: + AddWordToCustomDictionaryTask(const std::wstring& file_name, + const std::wstring& word) + : file_name_(WideToUTF8(file_name)), + word_(WideToUTF8(word)) { + } + + private: + void Run() { + // Add the word with a new line. Note that, although this would mean an + // extra line after the list of words, this is potentially harmless and + // faster, compared to verifying everytime whether to append a new line + // or not. + word_ += "\n"; + const char* file_name_char = file_name_.c_str(); + FILE* f = fopen(file_name_char, "a+"); + fputs(word_.c_str(), f); + fclose(f); + } + + std::string file_name_; + std::string word_; +}; + +void SpellChecker::AddWord(const std::wstring& word) { + // Check if the |hunspell_| has been initialized at all. + Initialize(); + + // Add the word to hunspell. + std::string word_to_add = WideToUTF8(word); + if (!word_to_add.empty()) + hunspell_->put_word(word_to_add.c_str()); + + // Now add the word to the custom dictionary file in the file loop. + if (file_loop_) { + file_loop_->PostTask(FROM_HERE, new AddWordToCustomDictionaryTask( + custom_dictionary_file_name_, word)); + } else { // just run it in this thread. + Task* write_word_task = new AddWordToCustomDictionaryTask( + custom_dictionary_file_name_, word); + write_word_task->Run(); + } +} diff --git a/chrome/browser/spellchecker.h b/chrome/browser/spellchecker.h index da17ee5..932d3c9 100644 --- a/chrome/browser/spellchecker.h +++ b/chrome/browser/spellchecker.h @@ -35,9 +35,13 @@ class SpellChecker : public base::RefCountedThreadSafe<SpellChecker> { // // The request context is used to download dictionaries if they do not exist. // This can be NULL if you don't want this (like in tests). + // The |custom_dictionary_file_name| should be left blank so that Spellchecker + // can figure out the custom dictionary file. It is non empty only for unit + // testing. SpellChecker(const std::wstring& dict_dir, const std::wstring& language, - URLRequestContext* request_context); + URLRequestContext* request_context, + const std::wstring& custom_dictionary_file_name); static void RegisterUserPrefs(PrefService* prefs); @@ -58,6 +62,11 @@ class SpellChecker : public base::RefCountedThreadSafe<SpellChecker> { int* misspelling_len, std::vector<std::wstring>* optional_suggestions); + // Add custom word to the dictionary, which means: + // a) Add it to the current hunspell object for immediate use, + // b) Add the word to a file in disk for custom dictionary. + void AddWord(const std::wstring& word); + private: // Download dictionary files when required. class DictionaryDownloadController; @@ -67,6 +76,10 @@ class SpellChecker : public base::RefCountedThreadSafe<SpellChecker> { // Initializes the Hunspell Dictionary. bool Initialize(); + // After |hunspell_| is initialized, this function is called to add custom + // words from the custom dictionary to the |hunspell_| + void AddCustomWordsToHunspell(); + void set_file_is_downloading(bool value); // Memory maps the given .bdic file. On success, it will return true and will @@ -80,6 +93,9 @@ class SpellChecker : public base::RefCountedThreadSafe<SpellChecker> { // Path to the spellchecker file. std::wstring bdict_file_name_; + // Path to the custom dictionary file. + std::wstring custom_dictionary_file_name_; + // We memory-map the BDict file for spellchecking. These are the handles // necessary for that. HANDLE bdict_file_; diff --git a/chrome/browser/web_contents.cc b/chrome/browser/web_contents.cc index 3a9fd3a..a796dc6 100644 --- a/chrome/browser/web_contents.cc +++ b/chrome/browser/web_contents.cc @@ -954,6 +954,10 @@ void WebContents::Replace(const std::wstring& text) { render_view_host()->Replace(text); } +void WebContents::AddToDictionary(const std::wstring& word) { + render_view_host()->AddToDictionary(word); +} + void WebContents::Delete() { render_view_host()->Delete(); } @@ -1698,8 +1702,12 @@ void WebContents::DidDownloadImage( void WebContents::ShowContextMenu( const ViewHostMsg_ContextMenu_Params& params) { RenderViewContextMenuController menu_controller(this, params); - RenderViewContextMenu menu(&menu_controller, GetHWND(), params.type, - params.dictionary_suggestions, profile()); + RenderViewContextMenu menu(&menu_controller, + GetHWND(), + params.type, + params.misspelled_word, + params.dictionary_suggestions, + profile()); POINT screen_pt = { params.x, params.y }; MapWindowPoints(GetHWND(), HWND_DESKTOP, &screen_pt, 1); diff --git a/chrome/browser/web_contents.h b/chrome/browser/web_contents.h index 30b4c2f..e337068 100644 --- a/chrome/browser/web_contents.h +++ b/chrome/browser/web_contents.h @@ -169,6 +169,7 @@ class WebContents : public TabContents, void Undo(); void Redo(); void Replace(const std::wstring& text); + void AddToDictionary(const std::wstring& word); void Delete(); void SelectAll(); |