| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/spellchecker/spellcheck_custom_dictionary.h" | 5 #include "chrome/browser/spellchecker/spellcheck_custom_dictionary.h" |
| 6 | 6 |
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/lazy_instance.h" | |
| 9 #include "base/string_split.h" | 8 #include "base/string_split.h" |
| 10 #include "base/string_util.h" | |
| 11 #include "chrome/browser/profiles/profile.h" | 9 #include "chrome/browser/profiles/profile.h" |
| 12 #include "chrome/browser/spellchecker/spellcheck_service.h" | |
| 13 #include "chrome/common/chrome_constants.h" | 10 #include "chrome/common/chrome_constants.h" |
| 14 #include "chrome/common/spellcheck_messages.h" | 11 #include "chrome/common/spellcheck_messages.h" |
| 15 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
| 16 #include "content/public/browser/render_process_host.h" | 13 #include "content/public/browser/render_process_host.h" |
| 17 | 14 |
| 18 #include <functional> | |
| 19 | |
| 20 using content::BrowserThread; | 15 using content::BrowserThread; |
| 21 using chrome::spellcheck_common::WordList; | 16 using chrome::spellcheck_common::WordList; |
| 22 | 17 |
| 23 SpellcheckCustomDictionary::SpellcheckCustomDictionary(Profile* profile) | 18 SpellcheckCustomDictionary::SpellcheckCustomDictionary(Profile* profile) |
| 24 : SpellcheckDictionary(profile), | 19 : SpellcheckDictionary(profile), |
| 25 custom_dictionary_path_(), | 20 custom_dictionary_path_(), |
| 26 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | 21 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| 27 DCHECK(profile); | 22 DCHECK(profile); |
| 28 custom_dictionary_path_ = | 23 custom_dictionary_path_ = |
| 29 profile_->GetPath().Append(chrome::kCustomDictionaryFileName); | 24 profile_->GetPath().Append(chrome::kCustomDictionaryFileName); |
| 30 } | 25 } |
| 31 | 26 |
| 32 SpellcheckCustomDictionary::~SpellcheckCustomDictionary() { | 27 SpellcheckCustomDictionary::~SpellcheckCustomDictionary() { |
| 33 } | 28 } |
| 34 | 29 |
| 30 void SpellcheckCustomDictionary::Load() { |
| 31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 32 |
| 33 BrowserThread::PostTaskAndReplyWithResult<WordList*>( |
| 34 BrowserThread::FILE, |
| 35 FROM_HERE, |
| 36 base::Bind(&SpellcheckCustomDictionary::LoadDictionary, |
| 37 base::Unretained(this)), |
| 38 base::Bind(&SpellcheckCustomDictionary::SetCustomWordListAndDelete, |
| 39 weak_ptr_factory_.GetWeakPtr())); |
| 40 } |
| 41 |
| 42 const WordList& SpellcheckCustomDictionary::GetWords() const { |
| 43 return words_; |
| 44 } |
| 45 |
| 35 void SpellcheckCustomDictionary::LoadDictionaryIntoCustomWordList( | 46 void SpellcheckCustomDictionary::LoadDictionaryIntoCustomWordList( |
| 36 WordList* custom_words) { | 47 WordList* custom_words) { |
| 37 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 48 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 38 | 49 |
| 39 std::string contents; | 50 std::string contents; |
| 40 file_util::ReadFileToString(custom_dictionary_path_, &contents); | 51 file_util::ReadFileToString(custom_dictionary_path_, &contents); |
| 41 if (contents.empty()) | 52 if (contents.empty()) |
| 42 return; | 53 return; |
| 43 | 54 |
| 44 base::SplitString(contents, '\n', custom_words); | 55 base::SplitString(contents, '\n', custom_words); |
| 45 // Clear out empty words. | 56 // Clear out empty words. |
| 46 custom_words->erase(remove_if(custom_words->begin(), custom_words->end(), | 57 custom_words->erase(remove_if(custom_words->begin(), custom_words->end(), |
| 47 mem_fun_ref(&std::string::empty)), custom_words->end()); | 58 mem_fun_ref(&std::string::empty)), custom_words->end()); |
| 48 } | 59 } |
| 49 | 60 |
| 50 void SpellcheckCustomDictionary::Load() { | 61 void SpellcheckCustomDictionary::SetCustomWordList(WordList* custom_words) { |
| 51 custom_words_.clear(); | 62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 52 // We are not guaranteed to be on the FILE thread so post the task. | 63 |
| 53 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( | 64 words_.clear(); |
| 54 &SpellcheckCustomDictionary::LoadDictionaryIntoCustomWordList, | 65 if (custom_words) |
| 55 base::Unretained(this), &custom_words_)); | 66 std::swap(words_, *custom_words); |
| 67 |
| 68 std::vector<Observer*>::iterator it; |
| 69 for (it = observers_.begin(); it != observers_.end(); ++it) |
| 70 (*it)->OnCustomDictionaryLoaded(); |
| 71 } |
| 72 |
| 73 bool SpellcheckCustomDictionary::AddWord(const std::string& word) { |
| 74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 75 |
| 76 if (!CustomWordAddedLocally(word)) |
| 77 return false; |
| 78 |
| 79 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| 80 base::Bind(&SpellcheckCustomDictionary::WriteWordToCustomDictionary, |
| 81 base::Unretained(this), word)); |
| 82 |
| 83 for (content::RenderProcessHost::iterator i( |
| 84 content::RenderProcessHost::AllHostsIterator()); |
| 85 !i.IsAtEnd(); i.Advance()) { |
| 86 i.GetCurrentValue()->Send(new SpellCheckMsg_WordAdded(word)); |
| 87 } |
| 88 |
| 89 std::vector<Observer*>::iterator it; |
| 90 for (it = observers_.begin(); it != observers_.end(); ++it) |
| 91 (*it)->OnCustomDictionaryWordAdded(word); |
| 92 |
| 93 return true; |
| 94 } |
| 95 |
| 96 bool SpellcheckCustomDictionary::CustomWordAddedLocally( |
| 97 const std::string& word) { |
| 98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 99 |
| 100 WordList::iterator it = std::find(words_.begin(), words_.end(), word); |
| 101 if (it == words_.end()) { |
| 102 words_.push_back(word); |
| 103 return true; |
| 104 } |
| 105 return false; |
| 106 // TODO(rlp): record metrics on custom word size |
| 56 } | 107 } |
| 57 | 108 |
| 58 void SpellcheckCustomDictionary::WriteWordToCustomDictionary( | 109 void SpellcheckCustomDictionary::WriteWordToCustomDictionary( |
| 59 const std::string& word) { | 110 const std::string& word) { |
| 60 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 61 | 112 |
| 62 // Stored in UTF-8. | 113 // Stored in UTF-8. |
| 63 DCHECK(IsStringUTF8(word)); | 114 DCHECK(IsStringUTF8(word)); |
| 64 | 115 |
| 65 std::string word_to_add(word + "\n"); | 116 std::string word_to_add(word + "\n"); |
| 66 if (!file_util::PathExists(custom_dictionary_path_)) { | 117 if (!file_util::PathExists(custom_dictionary_path_)) { |
| 67 file_util::WriteFile(custom_dictionary_path_, word_to_add.c_str(), | 118 file_util::WriteFile(custom_dictionary_path_, word_to_add.c_str(), |
| 68 word_to_add.length()); | 119 word_to_add.length()); |
| 69 } else { | 120 } else { |
| 70 file_util::AppendToFile(custom_dictionary_path_, word_to_add.c_str(), | 121 file_util::AppendToFile(custom_dictionary_path_, word_to_add.c_str(), |
| 71 word_to_add.length()); | 122 word_to_add.length()); |
| 72 } | 123 } |
| 73 } | 124 } |
| 74 | 125 |
| 75 void SpellcheckCustomDictionary::CustomWordAddedLocally( | 126 bool SpellcheckCustomDictionary::RemoveWord(const std::string& word) { |
| 76 const std::string& word) { | |
| 77 custom_words_.push_back(word); | |
| 78 // TODO(rlp): record metrics on custom word size | |
| 79 } | |
| 80 | |
| 81 bool SpellcheckCustomDictionary::SetCustomWordList(WordList* custom_words) { | |
| 82 if (!custom_words) | |
| 83 return false; | |
| 84 custom_words_.clear(); | |
| 85 std::swap(custom_words_, *custom_words); | |
| 86 return true; | |
| 87 } | |
| 88 | |
| 89 const WordList& SpellcheckCustomDictionary::GetCustomWords() const { | |
| 90 return custom_words_; | |
| 91 } | |
| 92 | |
| 93 void SpellcheckCustomDictionary::AddWord(const std::string& word) { | |
| 94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 95 | 128 |
| 96 CustomWordAddedLocally(word); | 129 if (!CustomWordRemovedLocally(word)) |
| 130 return false; |
| 97 | 131 |
| 98 BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE, | 132 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| 99 base::Bind(&SpellcheckCustomDictionary::WriteWordToCustomDictionary, | 133 base::Bind(&SpellcheckCustomDictionary::EraseWordFromCustomDictionary, |
| 100 base::Unretained(this), word), | 134 base::Unretained(this), word)); |
| 101 base::Bind(&SpellcheckCustomDictionary::AddWordComplete, | |
| 102 weak_ptr_factory_.GetWeakPtr(), word)); | |
| 103 } | |
| 104 | |
| 105 void SpellcheckCustomDictionary::AddWordComplete(const std::string& word) { | |
| 106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 107 | 135 |
| 108 for (content::RenderProcessHost::iterator i( | 136 for (content::RenderProcessHost::iterator i( |
| 109 content::RenderProcessHost::AllHostsIterator()); | 137 content::RenderProcessHost::AllHostsIterator()); |
| 110 !i.IsAtEnd(); i.Advance()) { | 138 !i.IsAtEnd(); i.Advance()) { |
| 111 i.GetCurrentValue()->Send(new SpellCheckMsg_WordAdded(word)); | 139 i.GetCurrentValue()->Send(new SpellCheckMsg_WordRemoved(word)); |
| 140 } |
| 141 |
| 142 std::vector<Observer*>::iterator it; |
| 143 for (it = observers_.begin(); it != observers_.end(); ++it) |
| 144 (*it)->OnCustomDictionaryWordRemoved(word); |
| 145 |
| 146 return true; |
| 147 } |
| 148 |
| 149 bool SpellcheckCustomDictionary::CustomWordRemovedLocally( |
| 150 const std::string& word) { |
| 151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 152 |
| 153 WordList::iterator it = std::find(words_.begin(), words_.end(), word); |
| 154 if (it != words_.end()) { |
| 155 words_.erase(it); |
| 156 return true; |
| 157 } |
| 158 return false; |
| 159 } |
| 160 |
| 161 void SpellcheckCustomDictionary::EraseWordFromCustomDictionary( |
| 162 const std::string& word) { |
| 163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 164 DCHECK(IsStringUTF8(word)); |
| 165 |
| 166 WordList custom_words; |
| 167 LoadDictionaryIntoCustomWordList(&custom_words); |
| 168 |
| 169 char empty[] = {'\0'}; |
| 170 char separator[] = {'\n', '\0'}; |
| 171 file_util::WriteFile(custom_dictionary_path_, empty, 0); |
| 172 for (WordList::iterator it = custom_words.begin(); |
| 173 it != custom_words.end(); |
| 174 ++it) { |
| 175 std::string word_to_add = *it; |
| 176 if (word.compare(word_to_add) != 0) { |
| 177 file_util::AppendToFile(custom_dictionary_path_, word_to_add.c_str(), |
| 178 word_to_add.length()); |
| 179 file_util::AppendToFile(custom_dictionary_path_, separator, 1); |
| 180 } |
| 112 } | 181 } |
| 113 } | 182 } |
| 114 | 183 |
| 184 void SpellcheckCustomDictionary::AddObserver(Observer* observer) { |
| 185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 115 | 186 |
| 187 observers_.push_back(observer); |
| 188 } |
| 189 |
| 190 void SpellcheckCustomDictionary::RemoveObserver(Observer* observer) { |
| 191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 192 |
| 193 std::vector<Observer*>::iterator it = std::find(observers_.begin(), |
| 194 observers_.end(), |
| 195 observer); |
| 196 if (it != observers_.end()) |
| 197 observers_.erase(it); |
| 198 } |
| 199 |
| 200 WordList* SpellcheckCustomDictionary::LoadDictionary() { |
| 201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 202 |
| 203 WordList* custom_words = new WordList; |
| 204 LoadDictionaryIntoCustomWordList(custom_words); |
| 205 return custom_words; |
| 206 } |
| 207 |
| 208 void SpellcheckCustomDictionary::SetCustomWordListAndDelete( |
| 209 WordList* custom_words) { |
| 210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 211 |
| 212 SetCustomWordList(custom_words); |
| 213 delete custom_words; |
| 214 } |
| OLD | NEW |