Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6252)

Unified Diff: chrome/browser/spellchecker/spellcheck_custom_dictionary.cc

Issue 11445002: Sync user's custom spellcheck dictionary (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
index 588e3675c2fa3d8e22620f578cd497abef322e16..7b8390be32e5edb5e1c66930d8afc2e89555b969 100644
--- a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
+++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
@@ -9,21 +9,32 @@
#include "base/file_util.h"
#include "base/files/important_file_writer.h"
#include "base/md5.h"
+#include "base/string_number_conversions.h"
#include "base/string_split.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/spellcheck_messages.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_process_host.h"
+#include "sync/api/sync_change.h"
+#include "sync/api/sync_data.h"
+#include "sync/api/sync_error_factory.h"
+#include "sync/protocol/sync.pb.h"
using content::BrowserThread;
using chrome::spellcheck_common::WordList;
namespace {
+const size_t MAX_SYNC_SIZE = 1300;
groby-ooo-7-16 2012/12/19 22:16:00 Please document vars. (Specifically, what does "13
please use gerrit instead 2012/12/22 03:20:19 Done. I renamed the variable, commented it, and mo
const FilePath::CharType BACKUP_EXTENSION[] = FILE_PATH_LITERAL("backup");
const char CHECKSUM_PREFIX[] = "checksum_v1 = ";
+const std::string DictionaryTooBigToSyncErrorMessage(size_t dictionary_size) {
groby-ooo-7-16 2012/12/19 22:16:00 Shouldn't we i18n error messages?
please use gerrit instead 2012/12/22 03:20:19 This message is for server-side logging. It will b
+ return "Turning off sync for custom spelling dictionary with " +
+ base::Uint64ToString(dictionary_size) + " words. Sync limit is " +
+ base::Uint64ToString(MAX_SYNC_SIZE) + " words.";
+}
+
// Loads the lines from the file at |file_path| into the |lines| container. If
// the file has a valid checksum, then returns |true|. If the file has an
// invalid checksum, then returns |false| and clears |lines|.
@@ -43,13 +54,9 @@ bool LoadFile(FilePath file_path, std::vector<std::string>* lines) {
return true;
}
-bool IsValidWord(const std::string& word) {
- return IsStringUTF8(word) && word.length() <= 128 && word.length() > 0 &&
- std::string::npos == word.find_first_of(kWhitespaceASCII);
-}
-
bool IsInvalidWord(const std::string& word) {
- return !IsValidWord(word);
+ return !IsStringUTF8(word) || word.length() > 128 || word.empty() ||
groby-ooo-7-16 2012/12/19 22:16:00 128 is a magic number. Is there a constant for thi
please use gerrit instead 2012/12/22 03:20:19 Great catch! The length check needs to match Hunsp
+ word.find_first_of(kWhitespaceASCII) != std::string::npos;
}
} // namespace
@@ -57,7 +64,8 @@ bool IsInvalidWord(const std::string& word) {
SpellcheckCustomDictionary::SpellcheckCustomDictionary(Profile* profile)
: SpellcheckDictionary(profile),
custom_dictionary_path_(),
- weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+ weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ is_loaded_(false) {
DCHECK(profile);
custom_dictionary_path_ =
profile_->GetPath().Append(chrome::kCustomDictionaryFileName);
@@ -73,7 +81,7 @@ void SpellcheckCustomDictionary::Load() {
BrowserThread::FILE,
FROM_HERE,
base::Bind(&SpellcheckCustomDictionary::LoadDictionary,
- base::Unretained(this)),
+ custom_dictionary_path_),
base::Bind(&SpellcheckCustomDictionary::SetCustomWordListAndDelete,
weak_ptr_factory_.GetWeakPtr()));
}
@@ -82,11 +90,13 @@ const WordList& SpellcheckCustomDictionary::GetWords() const {
return words_;
}
+// static
void SpellcheckCustomDictionary::LoadDictionaryIntoCustomWordList(
- WordList* custom_words) {
+ WordList* custom_words,
+ const FilePath& path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- LoadDictionaryFileReliably(custom_words);
+ LoadDictionaryFileReliably(custom_words, path);
if (custom_words->empty())
return;
@@ -100,7 +110,7 @@ void SpellcheckCustomDictionary::LoadDictionaryIntoCustomWordList(
IsInvalidWord),
custom_words->end());
- SaveDictionaryFileReliably(*custom_words);
+ SaveDictionaryFileReliably(*custom_words, path);
}
void SpellcheckCustomDictionary::SetCustomWordList(WordList* custom_words) {
@@ -109,130 +119,212 @@ void SpellcheckCustomDictionary::SetCustomWordList(WordList* custom_words) {
words_.clear();
if (custom_words)
std::swap(words_, *custom_words);
-
- FOR_EACH_OBSERVER(Observer, observers_, OnCustomDictionaryLoaded());
}
bool SpellcheckCustomDictionary::AddWord(const std::string& word) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!IsValidWord(word))
- return false;
-
- if (!CustomWordAddedLocally(word))
- return false;
-
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&SpellcheckCustomDictionary::WriteWordToCustomDictionary,
- base::Unretained(this), word));
+ WordList to_add;
+ to_add.push_back(word);
+ WordList to_remove;
+ return UpdateWords(&to_add, &to_remove);
+}
- for (content::RenderProcessHost::iterator i(
- content::RenderProcessHost::AllHostsIterator());
- !i.IsAtEnd(); i.Advance()) {
- i.GetCurrentValue()->Send(new SpellCheckMsg_WordAdded(word));
- }
+bool SpellcheckCustomDictionary::CustomWordAddedLocally(
+ const std::string& word) {
+ WordList to_add;
+ to_add.push_back(word);
+ WordList to_remove;
+ return CustomWordsUpdatedLocally(&to_add, &to_remove);
+}
- FOR_EACH_OBSERVER(Observer, observers_, OnCustomDictionaryWordAdded(word));
+// static
+void SpellcheckCustomDictionary::WriteWordToCustomDictionary(
+ const std::string& word,
+ const FilePath& path) {
+ WordList to_write;
+ to_write.push_back(word);
+ WordList to_erase;
+ WriteAndEraseWordsInCustomDictionary(&to_write, &to_erase, path);
+}
- return true;
+bool SpellcheckCustomDictionary::RemoveWord(const std::string& word) {
+ WordList to_add;
+ WordList to_remove;
+ to_remove.push_back(word);
+ return UpdateWords(&to_add, &to_remove);
}
-bool SpellcheckCustomDictionary::CustomWordAddedLocally(
+bool SpellcheckCustomDictionary::CustomWordRemovedLocally(
const std::string& word) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(IsValidWord(word));
+ WordList to_add;
groby-ooo-7-16 2012/12/19 22:16:00 There's a potential refactor here, since we have s
please use gerrit instead 2012/12/22 03:20:19 Done.
+ WordList to_remove;
+ to_remove.push_back(word);
+ return CustomWordsUpdatedLocally(&to_add, &to_remove);
+}
- WordList::iterator it = std::find(words_.begin(), words_.end(), word);
- if (it == words_.end()) {
- words_.push_back(word);
- return true;
- }
- return false;
- // TODO(rlp): record metrics on custom word size
+// static
+void SpellcheckCustomDictionary::EraseWordFromCustomDictionary(
+ const std::string& word,
+ const FilePath& path) {
+ WordList to_write;
+ WordList to_erase;
+ to_erase.push_back(word);
+ WriteAndEraseWordsInCustomDictionary(&to_write, &to_erase, path);
}
-void SpellcheckCustomDictionary::WriteWordToCustomDictionary(
- const std::string& word) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- DCHECK(IsValidWord(word));
+void SpellcheckCustomDictionary::AddObserver(Observer* observer) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- WordList custom_words;
- LoadDictionaryFileReliably(&custom_words);
- custom_words.push_back(word);
- SaveDictionaryFileReliably(custom_words);
+ observers_.AddObserver(observer);
}
-bool SpellcheckCustomDictionary::RemoveWord(const std::string& word) {
+void SpellcheckCustomDictionary::RemoveObserver(Observer* observer) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!IsValidWord(word))
- return false;
- if (!CustomWordRemovedLocally(word))
- return false;
+ observers_.RemoveObserver(observer);
+}
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&SpellcheckCustomDictionary::EraseWordFromCustomDictionary,
- base::Unretained(this), word));
+syncer::SyncMergeResult SpellcheckCustomDictionary::MergeDataAndStartSyncing(
+ syncer::ModelType type,
+ const syncer::SyncDataList& initial_sync_data,
+ scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
+ scoped_ptr<syncer::SyncErrorFactory> sync_error_handler) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(!sync_processor_.get());
+ DCHECK(!sync_error_handler_.get());
+ DCHECK(sync_processor.get());
+ DCHECK(sync_error_handler.get());
+ DCHECK_EQ(syncer::DICTIONARY, type);
+
+ sync_processor_ = sync_processor.Pass();
+ sync_error_handler_ = sync_error_handler.Pass();
+
+ WordList to_add_locally;
groby-ooo-7-16 2012/12/19 22:16:00 Please comment what you're actually doing here. (G
please use gerrit instead 2012/12/22 03:20:19 Done.
+ WordList to_add_remotely(words_);
+ std::string word;
+ for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin();
+ it != initial_sync_data.end();
+ ++it) {
+ DCHECK_EQ(syncer::DICTIONARY, it->GetDataType());
+ word = it->GetSpecifics().dictionary().word();
+ WordList::iterator found = std::find(
groby-ooo-7-16 2012/12/19 22:16:00 I might be wrong, but I think most of this can be
please use gerrit instead 2012/12/22 03:20:19 Done. Used std::set_difference and std::set_inters
+ to_add_remotely.begin(), to_add_remotely.end(), word);
+ if (found == to_add_remotely.end())
+ to_add_locally.push_back(word);
+ else
+ to_add_remotely.erase(found);
+ }
- for (content::RenderProcessHost::iterator i(
- content::RenderProcessHost::AllHostsIterator());
- !i.IsAtEnd(); i.Advance()) {
- i.GetCurrentValue()->Send(new SpellCheckMsg_WordRemoved(word));
+ WordList to_remove;
+ UpdateWords(&to_add_locally, &to_remove, true);
+
+ syncer::SyncChangeList local_changes;
+ size_t i = initial_sync_data.size();
+ for (WordList::iterator it = to_add_remotely.begin();
+ it != to_add_remotely.end() && i < MAX_SYNC_SIZE;
+ ++it, ++i) {
+ word = *it;
+ sync_pb::EntitySpecifics specifics;
+ specifics.mutable_dictionary()->set_word(word);
+ local_changes.push_back(syncer::SyncChange(
+ FROM_HERE,
+ syncer::SyncChange::ACTION_ADD,
+ syncer::SyncData::CreateLocalData(word, word, specifics)));
}
- FOR_EACH_OBSERVER(Observer, observers_, OnCustomDictionaryWordRemoved(word));
+ syncer::SyncMergeResult result(type);
+ result.set_error(sync_processor_->ProcessSyncChanges(FROM_HERE,
+ local_changes));
+ if (result.error().IsSet())
+ return result;
+
+ if (words_.size() > MAX_SYNC_SIZE) {
+ result.set_error(sync_error_handler_->CreateAndUploadError(
+ FROM_HERE,
+ DictionaryTooBigToSyncErrorMessage(words_.size())));
+ StopSyncing(syncer::DICTIONARY);
+ }
- return true;
+ return result;
}
-bool SpellcheckCustomDictionary::CustomWordRemovedLocally(
- const std::string& word) {
+void SpellcheckCustomDictionary::StopSyncing(syncer::ModelType type) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(IsValidWord(word));
+ DCHECK_EQ(syncer::DICTIONARY, type);
- WordList::iterator it = std::find(words_.begin(), words_.end(), word);
- if (it != words_.end()) {
- words_.erase(it);
- return true;
- }
- return false;
+ sync_processor_.reset();
+ sync_error_handler_.reset();
}
-void SpellcheckCustomDictionary::EraseWordFromCustomDictionary(
- const std::string& word) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- DCHECK(IsValidWord(word));
-
- WordList custom_words;
- LoadDictionaryFileReliably(&custom_words);
- if (custom_words.empty())
- return;
-
- WordList::iterator it = std::find(custom_words.begin(),
- custom_words.end(),
- word);
- if (it != custom_words.end())
- custom_words.erase(it);
+void SpellcheckCustomDictionary::StopSyncingForTesting() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- SaveDictionaryFileReliably(custom_words);
+ base::IgnoreResult(sync_processor_.release());
groby-ooo-7-16 2012/12/19 22:16:00 Why not sync_processor.reset()?
please use gerrit instead 2012/12/22 03:20:19 Removed StopSyncingForTesting(). Done.
+ sync_error_handler_.reset();
}
-void SpellcheckCustomDictionary::AddObserver(Observer* observer) {
+bool SpellcheckCustomDictionary::IsLoaded() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return is_loaded_;
+}
- observers_.AddObserver(observer);
+syncer::SyncDataList SpellcheckCustomDictionary::GetAllSyncData(
+ syncer::ModelType type) const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(syncer::DICTIONARY, type);
+
+ syncer::SyncDataList data;
+ std::string word;
+ size_t i = 0;
+ for (WordList::const_iterator it = words_.begin();
+ it != words_.end() && i < MAX_SYNC_SIZE;
+ ++it, ++i) {
+ word = *it;
+ sync_pb::EntitySpecifics specifics;
+ specifics.mutable_dictionary()->set_word(word);
+ data.push_back(syncer::SyncData::CreateLocalData(word, word, specifics));
+ }
+ return data;
}
-void SpellcheckCustomDictionary::RemoveObserver(Observer* observer) {
+syncer::SyncError SpellcheckCustomDictionary::ProcessSyncChanges(
+ const tracked_objects::Location& from_here,
+ const syncer::SyncChangeList& change_list) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- observers_.RemoveObserver(observer);
+ WordList to_add;
+ WordList to_remove;
+ for (syncer::SyncChangeList::const_iterator it = change_list.begin();
+ it != change_list.end();
+ ++it) {
+ DCHECK(it->IsValid());
+ std::string word = it->sync_data().GetSpecifics().dictionary().word();
+ switch (it->change_type()) {
+ case syncer::SyncChange::ACTION_ADD:
+ to_add.push_back(word);
+ break;
+ case syncer::SyncChange::ACTION_DELETE:
+ to_remove.push_back(word);
+ break;
+ default:
+ NOTREACHED() << "Unexpected sync change state.";
groby-ooo-7-16 2012/12/19 22:16:00 I think we should either do a NOTREACHED _or_ the
please use gerrit instead 2012/12/22 03:20:19 Done. Handling error condition normally.
+ return sync_error_handler_->CreateAndUploadError(
+ FROM_HERE,
+ "Processing sync changes failed on change type " +
+ syncer::SyncChange::ChangeTypeToString(it->change_type()));
+ }
+ }
+
+ UpdateWords(&to_add, &to_remove, true);
+
+ return syncer::SyncError();
}
-WordList* SpellcheckCustomDictionary::LoadDictionary() {
+// static
+WordList* SpellcheckCustomDictionary::LoadDictionary(const FilePath& path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
WordList* custom_words = new WordList;
- LoadDictionaryIntoCustomWordList(custom_words);
+ LoadDictionaryIntoCustomWordList(custom_words, path);
groby-ooo-7-16 2012/12/19 22:16:00 Can we get rid of LoadDictionary and have API cons
please use gerrit instead 2012/12/22 03:20:19 Got rid of LoadDictionaryIntoCustomWordList in fav
return custom_words;
}
@@ -240,20 +332,31 @@ void SpellcheckCustomDictionary::SetCustomWordListAndDelete(
WordList* custom_words) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- SetCustomWordList(custom_words);
+ if (sync_processor_.get()) {
+ WordList to_remove;
+ CustomWordsUpdatedLocally(custom_words, &to_remove);
+ } else {
+ SetCustomWordList(custom_words);
+ }
+
delete custom_words;
+
+ is_loaded_ = true;
+ FOR_EACH_OBSERVER(Observer, observers_, OnCustomDictionaryLoaded());
}
+// static
void SpellcheckCustomDictionary::LoadDictionaryFileReliably(
- WordList* custom_words) {
+ WordList* custom_words,
+ const FilePath& path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
// Load the contents and verify the checksum.
- if (LoadFile(custom_dictionary_path_, custom_words))
+ if (LoadFile(path, custom_words))
return;
// Checksum is not valid. See if there's a backup.
- FilePath backup = custom_dictionary_path_.AddExtension(BACKUP_EXTENSION);
+ FilePath backup = path.AddExtension(BACKUP_EXTENSION);
if (!file_util::PathExists(backup))
return;
@@ -262,11 +365,13 @@ void SpellcheckCustomDictionary::LoadDictionaryFileReliably(
return;
// Backup checksum is valid. Restore the backup.
- file_util::CopyFile(backup, custom_dictionary_path_);
+ file_util::CopyFile(backup, path);
}
+// static
void SpellcheckCustomDictionary::SaveDictionaryFileReliably(
- const WordList& custom_words) {
+ const WordList& custom_words,
+ const FilePath& path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
std::stringstream content;
@@ -278,8 +383,167 @@ void SpellcheckCustomDictionary::SaveDictionaryFileReliably(
std::string checksum = base::MD5String(content.str());
content << CHECKSUM_PREFIX << checksum;
- file_util::CopyFile(custom_dictionary_path_,
- custom_dictionary_path_.AddExtension(BACKUP_EXTENSION));
- base::ImportantFileWriter::WriteFileAtomically(custom_dictionary_path_,
- content.str());
+ file_util::CopyFile(path,path.AddExtension(BACKUP_EXTENSION));
+ base::ImportantFileWriter::WriteFileAtomically(path, content.str());
+}
+
+bool SpellcheckCustomDictionary::UpdateWords(
+ WordList* to_add,
+ WordList* to_remove) {
+ return UpdateWords(to_add, to_remove, false);
+}
+
+bool SpellcheckCustomDictionary::UpdateWords(
+ WordList* to_add,
+ WordList* to_remove,
+ bool is_sync_update) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(to_add);
+ DCHECK(to_remove);
+
+ bool success = CustomWordsUpdatedLocally(to_add, to_remove, is_sync_update);
+
+ WordList* to_write = new WordList(*to_add);
+ WordList* to_erase = new WordList(*to_remove);
+ BrowserThread::PostTaskAndReply(
groby-ooo-7-16 2012/12/19 22:16:00 Since the reply task does nothing but delete to_wr
please use gerrit instead 2012/12/22 03:20:19 Posting a task with base::Passed(scoped_ptr).
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(
+ &SpellcheckCustomDictionary::WriteAndEraseWordsInCustomDictionary,
+ to_write,
+ to_erase,
+ custom_dictionary_path_),
+ base::Bind(
+ &SpellcheckCustomDictionary::OnWriteAndEraseFinished,
+ base::Unretained(this),
+ to_write,
+ to_erase));
+
+ return success;
+}
+
+bool SpellcheckCustomDictionary::CustomWordsUpdatedLocally(
+ WordList* to_add,
+ WordList* to_remove) {
+ return CustomWordsUpdatedLocally(to_add, to_remove, false);
+}
+
+// TODO(rlp): record metrics on custom word size
+bool SpellcheckCustomDictionary::CustomWordsUpdatedLocally(
+ WordList* to_add,
+ WordList* to_remove,
+ bool is_sync_update) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(to_add);
+ DCHECK(to_remove);
+
+ std::string word;
+ WordList cannot_add;
groby-ooo-7-16 2012/12/19 22:16:00 Why not use std::remove_if?
please use gerrit instead 2012/12/22 03:20:19 Done.
+ for (WordList::iterator it = to_add->begin(); it != to_add->end(); ++it) {
+ word = *it;
+ if (IsInvalidWord(word) ||
+ std::find(words_.begin(), words_.end(), word) != words_.end()) {
+ cannot_add.push_back(word);
+ }
+ }
+
+ for (WordList::iterator it = cannot_add.begin(); it != cannot_add.end(); ++it)
+ to_add->erase(std::find(to_add->begin(), to_add->end(), *it));
+
+ syncer::SyncChangeList local_changes;
+ for (WordList::iterator it = to_add->begin(); it != to_add->end(); ++it) {
+ word = *it;
+ words_.push_back(word);
+ sync_pb::EntitySpecifics specifics;
+ specifics.mutable_dictionary()->set_word(word);
+ local_changes.push_back(syncer::SyncChange(
+ FROM_HERE,
+ syncer::SyncChange::ACTION_ADD,
+ syncer::SyncData::CreateLocalData(word, word, specifics)));
+ }
+
+ WordList cannot_remove;
groby-ooo-7-16 2012/12/19 22:16:00 remove_if
please use gerrit instead 2012/12/22 03:20:19 Done.
+ for (WordList::iterator it = to_remove->begin();
+ it != to_remove->end();
+ ++it) {
+ word = *it;
+ if (std::find(words_.begin(), words_.end(), word) == words_.end())
+ cannot_remove.push_back(word);
+ }
+
+ for (WordList::iterator it = cannot_remove.begin();
+ it != cannot_remove.end();
+ ++it) {
+ to_remove->erase(std::find(to_remove->begin(), to_remove->end(), *it));
+ }
+
+ for (WordList::iterator it = to_remove->begin();
+ it != to_remove->end();
+ ++it) {
+ word = *it;
+ words_.erase(std::find(words_.begin(), words_.end(), word));
+ sync_pb::EntitySpecifics specifics;
+ specifics.mutable_dictionary()->set_word(word);
+ local_changes.push_back(syncer::SyncChange(
+ FROM_HERE,
+ syncer::SyncChange::ACTION_DELETE,
+ syncer::SyncData::CreateLocalData(word, word, specifics)));
+ }
+
+ FOR_EACH_OBSERVER(Observer,
groby-ooo-7-16 2012/12/19 22:16:00 If you go with the DictionaryChange object, just o
please use gerrit instead 2012/12/22 03:20:19 Done.
+ observers_,
+ OnCustomDictionaryWordsAdded(*to_add));
+ FOR_EACH_OBSERVER(Observer,
+ observers_,
+ OnCustomDictionaryWordsRemoved(*to_remove));
+
+ bool success = cannot_add.empty() && cannot_remove.empty();
+ if (is_sync_update || !sync_processor_.get())
+ return success;
+
+ if (words_.size() <= MAX_SYNC_SIZE) {
+ sync_processor_->ProcessSyncChanges(FROM_HERE, local_changes);
+ } else {
+ sync_error_handler_->CreateAndUploadError(
+ FROM_HERE,
+ DictionaryTooBigToSyncErrorMessage(words_.size()));
+ StopSyncing(syncer::DICTIONARY);
+ }
+
+ return success;
+}
+
+// static
+void SpellcheckCustomDictionary::WriteAndEraseWordsInCustomDictionary(
+ const WordList* to_write,
+ const WordList* to_erase,
+ const FilePath& path) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ WordList custom_words;
+ LoadDictionaryFileReliably(&custom_words, path);
+
+ for (WordList::const_iterator it = to_write->begin();
groby-ooo-7-16 2012/12/19 22:16:00 custom_words.insert(custom_words.end(), to_write.b
please use gerrit instead 2012/12/22 03:20:19 Done.
+ it != to_write->end();
+ ++it) {
+ custom_words.push_back(*it);
+ }
+
+ for (WordList::const_iterator it = to_erase->begin();
groby-ooo-7-16 2012/12/19 22:16:00 If custom_words is sorted, set_difference does the
please use gerrit instead 2012/12/22 03:20:19 Done.
+ it != to_erase->end();
+ ++it) {
+ custom_words.erase(std::find(custom_words.begin(),
+ custom_words.end(),
+ *it));
+ }
+
+ SaveDictionaryFileReliably(custom_words, path);
+}
+
+void SpellcheckCustomDictionary::OnWriteAndEraseFinished(
groby-ooo-7-16 2012/12/19 22:16:00 Can be killed - see above.
please use gerrit instead 2012/12/22 03:20:19 Done.
+ const WordList* written,
+ const WordList* erased) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ delete written;
+ delete erased;
}

Powered by Google App Engine
This is Rietveld 408576698