Chromium Code Reviews| Index: chrome/browser/bookmarks/bookmark_tag_model.cc |
| diff --git a/chrome/browser/bookmarks/bookmark_tag_model.cc b/chrome/browser/bookmarks/bookmark_tag_model.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..94f1384204ea91952735ae5c12c5a85291fb8be3 |
| --- /dev/null |
| +++ b/chrome/browser/bookmarks/bookmark_tag_model.cc |
| @@ -0,0 +1,574 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/bookmarks/bookmark_tag_model.h" |
| + |
| +#include "base/json/json_string_value_serializer.h" |
| +#include "base/observer_list.h" |
| +#include "base/strings/string_util.h" |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "chrome/browser/bookmarks/bookmark_model_factory.h" |
| +#include "chrome/browser/bookmarks/bookmark_tag_model_observer.h" |
| +#include "ui/base/models/tree_node_iterator.h" |
| + |
| +namespace { |
| +// The key used to store the tag list in the metainfo of a bookmark. |
| +const char* TAG_KEY = "TAG_KEY"; |
| + |
| +// Predicates to sort bookmarks. |
| +bool CompareBookmarkTitles(const BookmarkNode* a, const BookmarkNode* b) { |
| + return a->GetTitle() < b->GetTitle(); |
| +} |
| +bool CompareBookmarkUrl(const BookmarkNode* a, const BookmarkNode* b) { |
| + return a->url() < b->url(); |
| +} |
| +bool CompareBookmarkCreation(const BookmarkNode* a, const BookmarkNode* b) { |
| + return a->date_added() < b->date_added(); |
| +} |
| + |
| +// Comparator to sort tags by usage. |
| +struct TagComparator { |
| + TagComparator(std::map<BookmarkTag, unsigned int>& tags) : tags_(tags) { |
| + } |
| + ~TagComparator() {} |
| + |
| + bool operator()(BookmarkTag a, BookmarkTag b) { |
| + return (tags_[a] < tags_[b]); |
| + } |
| + |
| + std::map<BookmarkTag, unsigned int>& tags_; |
| +}; |
| +} // namespace |
| + |
| +BookmarkTagModel::BookmarkTagModel(BookmarkModel* bookmark_model) |
| + : bookmark_model_(bookmark_model), |
| + loaded_(false), |
| + observers_(ObserverList<BookmarkTagModelObserver>::NOTIFY_EXISTING_ONLY), |
| + inhibit_change_notifications_(false) { |
| + bookmark_model_->AddObserver(this); |
| + if (bookmark_model_->loaded()) |
| + Load(); |
| +} |
| + |
| +BookmarkTagModel::~BookmarkTagModel() { |
| + if (bookmark_model_) |
|
Yaron
2013/10/11 10:50:41
Can this ever fail? Seems like the c-tor guarantee
noyau (Ping after 24h)
2013/10/11 12:09:21
The bookmark model notifies its observer when it i
|
| + bookmark_model_->RemoveObserver(this); |
| +} |
| + |
| +#pragma mark BookmarkModel forwarding. |
| + |
| +void BookmarkTagModel::AddObserver(BookmarkTagModelObserver* observer) { |
| + observers_.AddObserver(observer); |
| +} |
| + |
| +void BookmarkTagModel::RemoveObserver(BookmarkTagModelObserver* observer) { |
| + observers_.RemoveObserver(observer); |
| +} |
| + |
| +void BookmarkTagModel::BeginExtensiveChanges() { |
| + DCHECK(bookmark_model_); |
|
Yaron
2013/10/11 10:50:41
These DCHECKS all seem unnecessary for reasons abo
noyau (Ping after 24h)
2013/10/11 12:09:21
These DCHECK are necessary for reasons above :)
|
| + bookmark_model_->BeginExtensiveChanges(); |
| +} |
| + |
| +void BookmarkTagModel::EndExtensiveChanges() { |
| + DCHECK(bookmark_model_); |
| + bookmark_model_->EndExtensiveChanges(); |
| +} |
| + |
| +bool BookmarkTagModel::IsDoingExtensiveChanges() const { |
| + DCHECK(bookmark_model_); |
| + return bookmark_model_->IsDoingExtensiveChanges(); |
| +} |
| + |
| +void BookmarkTagModel::Remove(const BookmarkNode* bookmark) { |
| + DCHECK(bookmark_model_); |
| + DCHECK(loaded_); |
| + const BookmarkNode *parent = bookmark->parent(); |
| + bookmark_model_->Remove(parent, parent->GetIndexOf(bookmark)); |
| +} |
| + |
| +void BookmarkTagModel::RemoveAll() { |
| + DCHECK(bookmark_model_); |
| + DCHECK(loaded_); |
| + bookmark_model_->RemoveAll(); |
| +} |
| + |
| +const gfx::Image& BookmarkTagModel::GetFavicon(const BookmarkNode* bookmark) { |
| + DCHECK(bookmark_model_); |
| + DCHECK(loaded_); |
| + return bookmark_model_->GetFavicon(bookmark); |
| +} |
| + |
| +void BookmarkTagModel::SetTitle(const BookmarkNode* bookmark, |
| + const string16& title) { |
| + DCHECK(bookmark_model_); |
| + DCHECK(loaded_); |
| + bookmark_model_->SetTitle(bookmark, title); |
| +} |
| + |
| +void BookmarkTagModel::SetURL(const BookmarkNode* bookmark, const GURL& url) { |
| + DCHECK(bookmark_model_); |
| + DCHECK(loaded_); |
| + bookmark_model_->SetURL(bookmark, url); |
| +} |
| + |
| +void BookmarkTagModel::SetDateAdded(const BookmarkNode* bookmark, |
| + base::Time date_added) { |
| + DCHECK(bookmark_model_); |
| + DCHECK(loaded_); |
| + bookmark_model_->SetDateAdded(bookmark, date_added); |
| +} |
| + |
| +const BookmarkNode* |
| + BookmarkTagModel::GetMostRecentlyAddedBookmarkForURL(const GURL& url) { |
| + DCHECK(bookmark_model_); |
| + DCHECK(loaded_); |
| + return bookmark_model_->GetMostRecentlyAddedNodeForURL(url); |
| +} |
| + |
| +#pragma mark Tags. |
| + |
| +const BookmarkNode* BookmarkTagModel::AddURL( |
| + const string16& title, |
| + const GURL& url, |
| + const std::set<BookmarkTag>& tags) { |
| + DCHECK(bookmark_model_); |
| + DCHECK(loaded_); |
| + |
| + inhibit_change_notifications_ = true; |
| + const BookmarkNode* parent = bookmark_model_->GetParentForNewNodes(); |
| + const BookmarkNode* bookmark = bookmark_model_->AddURL( |
|
Yaron
2013/10/11 10:50:41
I'm pretty sure the underlying BookmarkModel will
noyau (Ping after 24h)
2013/10/11 12:09:21
Yes, it will, and should. This class relies on the
|
| + parent, 0, title, url); |
| + AddTagsToBookmark(tags, bookmark); |
| + inhibit_change_notifications_ = false; |
| + |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + BookmarkNodeAdded(this, bookmark)); |
| + |
| + return bookmark; |
| +} |
| + |
| +std::set<BookmarkTag> |
| + BookmarkTagModel::AllTagsForBookmark(const BookmarkNode* bookmark) { |
| + DCHECK(loaded_); |
| + return bookmark_to_tags_[bookmark]; |
| +} |
| + |
| +void BookmarkTagModel::AddTagsToBookmark( |
| + const std::set<BookmarkTag>& tags, const BookmarkNode* bookmark) { |
| + std::set<BookmarkTag> all_tags(AllTagsForBookmark(bookmark)); |
| + for (std::set<BookmarkTag>::iterator it = tags.begin(); |
| + it != tags.end(); ++it) { |
| + BookmarkTag trimmed_tag = CollapseWhitespace(*it, true); |
| + if (trimmed_tag.empty()) |
| + continue; |
| + all_tags.insert(trimmed_tag); |
| + } |
| + ReplaceTagsOnBookmark(all_tags, bookmark); |
| +} |
| + |
| +void BookmarkTagModel::AddTagsToBookmarks( |
| + const std::set<BookmarkTag>& tags, |
| + const std::set<const BookmarkNode*>& bookmarks) { |
| + for (std::set<const BookmarkNode*>::iterator it = bookmarks.begin(); |
| + it != bookmarks.end(); ++it) { |
| + AddTagsToBookmark(tags, *it); |
| + } |
| +} |
| + |
| +void BookmarkTagModel::RemoveTagsFromBookmark( |
| + const std::set<BookmarkTag>& tags, |
| + const BookmarkNode* bookmark) { |
| + std::set<BookmarkTag> all_tags(AllTagsForBookmark(bookmark)); |
| + for (std::set<BookmarkTag>::iterator it = tags.begin(); |
| + it != tags.end(); ++it) { |
| + all_tags.erase(*it); |
| + } |
| + ReplaceTagsOnBookmark(all_tags, bookmark); |
| +} |
| + |
| +void BookmarkTagModel::RemoveTagsFromBookmarks( |
| + const std::set<BookmarkTag>& tags, |
| + const std::set<const BookmarkNode*>& bookmarks){ |
| + for (std::set<const BookmarkNode*>::iterator it = bookmarks.begin(); |
| + it != bookmarks.end(); ++it) { |
| + RemoveTagsFromBookmark(tags, *it); |
| + } |
| +} |
| + |
| +std::vector<const BookmarkNode*> BookmarkTagModel::BookmarksForTags( |
| + const std::set<BookmarkTag>& tags, |
| + BookmarkTagModel::BookmarkOrdering ordering) { |
| + DCHECK(loaded_); |
| + std::set<const BookmarkNode*> bookmarks; |
| + for (std::set<BookmarkTag>::iterator it = tags.begin(); |
| + it != tags.end(); ++it) { |
| + const std::set<const BookmarkNode*> subset(tag_to_bookmarks_[*it]); |
| + bookmarks.insert(subset.begin(), subset.end()); |
|
noyau (Ping after 24h)
2013/10/11 12:09:21
GCC on Android fail to compile this insert() with
|
| + } |
| + |
| + std::vector<const BookmarkNode*> sorted_bookmarks(bookmarks.begin(), |
| + bookmarks.end()); |
| + switch (ordering) { |
| + case UNSORTED_BOOKMARK_ORDERING: |
| + break; |
| + case TITLE_BOOKMARK_ORDERING: |
| + std::sort(sorted_bookmarks.begin(), sorted_bookmarks.end(), |
| + CompareBookmarkTitles); |
| + break; |
| + case URL_BOOKMARK_ORDERING: |
| + std::sort(sorted_bookmarks.begin(), sorted_bookmarks.end(), |
| + CompareBookmarkUrl); |
| + break; |
| + case CREATION_TIME_BOOKMARK_ORDERING: |
| + std::sort(sorted_bookmarks.begin(), sorted_bookmarks.end(), |
| + CompareBookmarkCreation); |
| + break; |
| + default: |
| + NOTREACHED(); |
| + } |
| + return sorted_bookmarks; |
| +} |
| + |
| +std::vector<const BookmarkNode*> BookmarkTagModel::BookmarksForTag( |
| + const BookmarkTag& tag, BookmarkOrdering ordering) { |
| + DCHECK(!tag.empty()); |
| + std::set<BookmarkTag> tagset; |
| + tagset.insert(tag); |
| + return BookmarksForTags(tagset, ordering); |
| +} |
| + |
| +std::vector<BookmarkTag> BookmarkTagModel::TagsRelatedToTag( |
| + const BookmarkTag& tag, BookmarkTagModel::TagOrdering ordering) { |
| + DCHECK(loaded_); |
| + std::map<BookmarkTag, unsigned int> tags; |
| + |
| + if (tag.empty()) { |
| + // Returns all the tags. |
| + for (std::map<const BookmarkTag, std::set<const BookmarkNode*> >::iterator |
| + it = tag_to_bookmarks_.begin(); it != tag_to_bookmarks_.end(); ++it) { |
| + tags[it->first] = it->second.size(); |
| + } |
| + } else { |
| + std::vector<const BookmarkNode*> bookmarks( |
| + BookmarksForTag(tag, UNSORTED_BOOKMARK_ORDERING)); |
| + |
| + for (std::vector<const BookmarkNode*>::iterator it = bookmarks.begin(); |
| + it != bookmarks.end(); ++it) { |
| + std::set<BookmarkTag> subset(bookmark_to_tags_[*it]); |
| + for (std::set<BookmarkTag>::iterator tag_it = subset.begin(); |
| + tag_it != subset.end(); ++tag_it) { |
| + tags[*tag_it] += 1; |
| + } |
| + } |
| + tags.erase(tag); // A tag is not related to itself. |
| + } |
| + |
| + // There is no keys() method on std::map. Nobody thought it might be useful? |
| + std::vector<BookmarkTag> sorted_tags; |
| + for (std::map<BookmarkTag, unsigned int>::iterator it = tags.begin(); |
| + it != tags.end(); ++it) { |
| + sorted_tags.push_back(it->first); |
| + } |
| + |
| + switch (ordering) { |
| + case UNSORTED_TAG_ORDERING: |
| + case ALPHABETICAL_TAG_ORDERING: |
| + break; // std::map is already sorting its keys. |
| + case MOST_USED_TAG_ORDERING: |
| + std::sort(sorted_tags.begin(), sorted_tags.end(), TagComparator(tags)); |
| + break; |
| + default: |
| + NOTREACHED(); |
| + } |
| + return sorted_tags; |
| +} |
| + |
| +#pragma mark Private methods. |
|
rlarocque
2013/10/11 18:06:25
What does this do?
noyau (Ping after 24h)
2013/10/14 23:59:39
Mac tools read those and use the text as a separat
|
| + |
| +std::set<BookmarkTag> BookmarkTagModel::ExtractTagsFromBookmark( |
| + const BookmarkNode *bookmark) { |
| + DCHECK(bookmark_model_); |
| + // This is awful BTW. Metainfo is itself an encoded JSON, and here we decode |
| + // another layer. |
| + |
| + // Retrieve the encodedData from the bookmark. If there is no encoded data |
| + // at all returns the name of all the ancestors as separate tags. |
| + std::string encoded; |
| + if (!bookmark->GetMetaInfo(TAG_KEY, &encoded)) { |
| + std::set<BookmarkTag> tags; |
| + const BookmarkNode* folder = bookmark->parent(); |
| + while (folder && folder->type() == BookmarkNode::FOLDER) { |
| + BookmarkTag trimmed_tag = CollapseWhitespace(folder->GetTitle(), true); |
| + if (!trimmed_tag.empty()) |
| + tags.insert(trimmed_tag); |
| + folder = folder->parent(); |
| + } |
| + return tags; |
| + } |
| + |
| + // Decode into a base::Value. If the data is not encoded properly as a list |
| + // return an empty result. |
| + JSONStringValueSerializer serializer(&encoded); |
| + int error_code = 0; |
| + std::string error_message; |
| + base::Value* result = serializer.Deserialize(&error_code, &error_message); |
|
noyau (Ping after 24h)
2013/10/11 12:09:21
Memory leak fixed (Thanks memory bot!)
|
| + |
| + if (error_code || !result->IsType(base::Value::TYPE_LIST)) |
| + return std::set<BookmarkTag>(); |
| + |
| + base::ListValue* list = NULL; |
| + if (!result->GetAsList(&list) || list->empty()) |
| + return std::set<BookmarkTag>(); |
| + |
| + // Build the set. |
| + std::set<BookmarkTag> return_value; |
| + |
| + for (base::ListValue::iterator it = list->begin(); |
| + it != list->end(); ++it) { |
| + base::Value* item = *it; |
| + BookmarkTag tag; |
| + if (!item->GetAsString(&tag)) |
| + continue; |
| + return_value.insert(tag); |
| + } |
| + return return_value; |
| +} |
| + |
| +void BookmarkTagModel::ReplaceTagsOnBookmark( |
| + const std::set<BookmarkTag>& tags, const BookmarkNode *bookmark) { |
| + DCHECK(bookmark_model_); |
| + DCHECK(loaded_); |
| + |
| + // Build a ListValue. |
| + std::vector<BookmarkTag> tag_vector(tags.begin(), tags.end()); |
| + base::ListValue list; |
| + list.AppendStrings(tag_vector); |
| + |
| + // Encodes it. |
| + std::string encoded; |
| + JSONStringValueSerializer serializer(&encoded); |
| + |
| + // Pushes it in the bookmark's metainfo. |
| + serializer.Serialize(list); |
| + bookmark_model_->SetNodeMetaInfo(bookmark, TAG_KEY, encoded); |
| +} |
| + |
| +void BookmarkTagModel::Load() { |
| + DCHECK(bookmark_model_); |
| + DCHECK(!loaded_); |
| + ui::TreeNodeIterator<const BookmarkNode> iterator( |
| + bookmark_model_->root_node()); |
| + while (iterator.has_next()) |
| + LoadBookmark(iterator.Next()); |
| + loaded_ = true; |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + Loaded(this)); |
| +} |
| + |
| +void BookmarkTagModel::LoadBookmark(const BookmarkNode* bookmark) { |
| + DCHECK(bookmark_model_); |
| + if (bookmark->is_url()) { |
| + std::set<BookmarkTag> tags(ExtractTagsFromBookmark(bookmark)); |
| + |
| + bookmark_to_tags_[bookmark] = tags; |
| + for (std::set<BookmarkTag>::iterator it = tags.begin(); |
| + it != tags.end(); ++it) { |
| + tag_to_bookmarks_[*it].insert(bookmark); |
| + } |
| + } |
| +} |
| + |
| +void BookmarkTagModel::RemoveBookmark(const BookmarkNode* bookmark) { |
| + DCHECK(bookmark_model_); |
| + if (bookmark->is_url()) { |
| + std::set<BookmarkTag> tags(bookmark_to_tags_[bookmark]); |
| + bookmark_to_tags_.erase(bookmark); |
| + |
| + for (std::set<BookmarkTag>::iterator it = tags.begin(); |
| + it != tags.end(); ++it) { |
| + tag_to_bookmarks_[*it].erase(bookmark); |
| + // Remove the tags no longer used. |
| + if (!tag_to_bookmarks_[*it].size()) |
| + tag_to_bookmarks_.erase(*it); |
| + } |
| + } |
| +} |
| + |
| +#pragma mark BookmarkModelObserver. |
| + |
| +// Invoked when the model has finished loading. |
| +void BookmarkTagModel::Loaded(BookmarkModel* model, bool ids_reassigned) { |
| + Load(); |
| +}; |
| + |
| +// Invoked from the destructor of the BookmarkModel. |
| +void BookmarkTagModel::BookmarkModelBeingDeleted(BookmarkModel* model) { |
| + DCHECK(bookmark_model_); |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + BookmarkTagModelBeingDeleted(this)); |
| + bookmark_model_ = NULL; |
| + observers_.Clear(); |
| +} |
| + |
| +// Invoked when a node has moved. |
| +void BookmarkTagModel::BookmarkNodeMoved(BookmarkModel* model, |
| + const BookmarkNode* old_parent, |
| + int old_index, |
| + const BookmarkNode* new_parent, |
| + int new_index) { |
| + DCHECK(loaded_); |
| + const BookmarkNode* bookmark = new_parent->GetChild(new_index); |
| + std::string encoded; |
| + if (!bookmark->GetMetaInfo(TAG_KEY, &encoded)) { |
| + // The bookmark moved and the system currently use its ancestors name as a |
| + // poor approximation for tags. |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + OnWillChangeBookmarkTags(this, bookmark)); |
| + RemoveBookmark(bookmark); |
| + LoadBookmark(bookmark); |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + BookmarkTagsChanged(this, bookmark)); |
| + } |
| +}; |
| + |
| +// Invoked when a node has been added. |
| +void BookmarkTagModel::BookmarkNodeAdded(BookmarkModel* model, |
| + const BookmarkNode* parent, |
| + int index) { |
| + DCHECK(loaded_); |
| + const BookmarkNode* bookmark = parent->GetChild(index); |
| + if (!bookmark->is_url()) |
| + return; |
| + LoadBookmark(bookmark); |
| + |
| + if (!inhibit_change_notifications_) |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + BookmarkNodeAdded(this, bookmark)); |
| +} |
| + |
| +// Invoked before a node is removed. |
| +// |parent| the parent of the node that will be removed. |
| +// |old_index| the index of the node about to be removed in |parent|. |
| +// |node| is the node to be removed. |
| +void BookmarkTagModel::OnWillRemoveBookmarks(BookmarkModel* model, |
| + const BookmarkNode* parent, |
| + int old_index, |
| + const BookmarkNode* node) { |
| + DCHECK(loaded_); |
| + RemoveBookmark(node); |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + OnWillRemoveBookmarks(this, node)); |
| +} |
| + |
| +// Invoked when a node has been removed, the item may still be starred though. |
| +// |parent| the parent of the node that was removed. |
| +// |old_index| the index of the removed node in |parent| before it was |
| +// removed. |
| +// |node| is the node that was removed. |
| +void BookmarkTagModel::BookmarkNodeRemoved(BookmarkModel* model, |
| + const BookmarkNode* parent, |
| + int old_index, |
| + const BookmarkNode* node) { |
| + DCHECK(loaded_); |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + BookmarkNodeRemoved(this, node)); |
| +} |
| + |
| +// Invoked before the title or url of a node is changed. |
| +void BookmarkTagModel::OnWillChangeBookmarkNode(BookmarkModel* model, |
| + const BookmarkNode* node) { |
| + DCHECK(loaded_); |
| + if (!inhibit_change_notifications_) |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + OnWillChangeBookmarkNode(this, node)); |
| +} |
| + |
| +// Invoked when the title or url of a node changes. |
| +void BookmarkTagModel::BookmarkNodeChanged(BookmarkModel* model, |
| + const BookmarkNode* node) { |
| + DCHECK(loaded_); |
| + if (!inhibit_change_notifications_) |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + BookmarkNodeChanged(this, node)); |
| +} |
| + |
| +// Invoked before the metainfo of a node is changed. |
| +void BookmarkTagModel::OnWillChangeBookmarkMetaInfo(BookmarkModel* model, |
| + const BookmarkNode* node) { |
| + DCHECK(loaded_); |
| + if (!inhibit_change_notifications_) |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + OnWillChangeBookmarkTags(this, node)); |
| +} |
| + |
| +// Invoked when the metainfo on a node changes. |
| +void BookmarkTagModel::BookmarkMetaInfoChanged(BookmarkModel* model, |
| + const BookmarkNode* node) { |
| + DCHECK(loaded_); |
| + RemoveBookmark(node); |
| + LoadBookmark(node); |
| + if (!inhibit_change_notifications_) |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + BookmarkTagsChanged(this, node)); |
| +} |
| + |
| +// Invoked when a favicon has been loaded or changed. |
| +void BookmarkTagModel::BookmarkNodeFaviconChanged(BookmarkModel* model, |
| + const BookmarkNode* node) { |
| + DCHECK(loaded_); |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + BookmarkNodeFaviconChanged(this, node)); |
| +} |
| + |
| +// Invoked before the direct children of |node| have been reordered in some |
| +// way, such as sorted. |
| +void BookmarkTagModel::OnWillReorderBookmarkNode(BookmarkModel* model, |
| + const BookmarkNode* node) { |
| + // This model doesn't care. |
| +} |
| + |
| +// Invoked when the children (just direct children, not descendants) of |
| +// |node| have been reordered in some way, such as sorted. |
| +void BookmarkTagModel::BookmarkNodeChildrenReordered(BookmarkModel* model, |
| + const BookmarkNode* node) { |
| + // This model doesn't care. |
| +} |
| + |
| +// Invoked before an extensive set of model changes is about to begin. |
| +// This tells UI intensive observers to wait until the updates finish to |
| +// update themselves. |
| +// These methods should only be used for imports and sync. |
| +// Observers should still respond to BookmarkNodeRemoved immediately, |
| +// to avoid holding onto stale node pointers. |
| +void BookmarkTagModel::ExtensiveBookmarkChangesBeginning(BookmarkModel* model) { |
| + DCHECK(loaded_); |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + ExtensiveBookmarkChangesBeginning(this)); |
| +} |
| + |
| +// Invoked after an extensive set of model changes has ended. |
| +// This tells observers to update themselves if they were waiting for the |
| +// update to finish. |
| +void BookmarkTagModel::ExtensiveBookmarkChangesEnded(BookmarkModel* model) { |
| + DCHECK(loaded_); |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + ExtensiveBookmarkChangesEnded(this)); |
| +} |
| + |
| +// Invoked before all non-permanent bookmark nodes are removed. |
| +void BookmarkTagModel::OnWillRemoveAllBookmarks(BookmarkModel* model) { |
| + DCHECK(loaded_); |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + OnWillRemoveAllBookmarks(this)); |
| +} |
| + |
| +// Invoked when all non-permanent bookmark nodes have been removed. |
| +void BookmarkTagModel::BookmarkAllNodesRemoved(BookmarkModel* model){ |
| + DCHECK(loaded_); |
| + tag_to_bookmarks_.clear(); |
| + bookmark_to_tags_.clear(); |
| + FOR_EACH_OBSERVER(BookmarkTagModelObserver, observers_, |
| + BookmarkAllNodesRemoved(this)); |
| +} |