summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorsidchat@google.com <sidchat@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-17 20:02:04 +0000
committersidchat@google.com <sidchat@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-17 20:02:04 +0000
commit63271da3b3740aadd3bd5d186bf7bd2b33ee6347 (patch)
tree43ab35878220b56a78a8dda05b775df87ddacc4e /chrome/browser
parent64b421f984b2dfe04546729f8b35648cac3d0f20 (diff)
downloadchromium_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.cc2
-rw-r--r--chrome/browser/render_process_host.cc7
-rw-r--r--chrome/browser/render_process_host.h3
-rw-r--r--chrome/browser/render_view_context_menu.cc8
-rw-r--r--chrome/browser/render_view_context_menu.h2
-rw-r--r--chrome/browser/render_view_context_menu_controller.cc7
-rw-r--r--chrome/browser/render_view_host.cc4
-rw-r--r--chrome/browser/render_view_host.h1
-rw-r--r--chrome/browser/resource_message_filter.cc13
-rw-r--r--chrome/browser/spellchecker.cc84
-rw-r--r--chrome/browser/spellchecker.h18
-rw-r--r--chrome/browser/web_contents.cc12
-rw-r--r--chrome/browser/web_contents.h1
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,
- &params.dictionary_suggestions);
+ bool is_misspelled = !spellchecker_->SpellCheckWord(
+ params.misspelled_word.c_str(),
+ static_cast<int>(params.misspelled_word.length()),
+ &misspell_location, &misspell_length,
+ &params.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();