| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "components/bookmarks/browser/bookmark_model.h" | 5 #include "components/bookmarks/browser/bookmark_model.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <functional> | 8 #include <functional> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
| 12 #include "base/i18n/string_compare.h" | 12 #include "base/i18n/string_compare.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/macros.h" | 14 #include "base/macros.h" |
| 15 #include "base/metrics/histogram_macros.h" | 15 #include "base/metrics/histogram_macros.h" |
| 16 #include "base/profiler/scoped_tracker.h" | 16 #include "base/profiler/scoped_tracker.h" |
| 17 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
| 18 #include "components/bookmarks/browser/bookmark_expanded_state_tracker.h" | 18 #include "components/bookmarks/browser/bookmark_expanded_state_tracker.h" |
| 19 #include "components/bookmarks/browser/bookmark_index.h" | 19 #include "components/bookmarks/browser/bookmark_index.h" |
| 20 #include "components/bookmarks/browser/bookmark_match.h" | 20 #include "components/bookmarks/browser/bookmark_match.h" |
| 21 #include "components/bookmarks/browser/bookmark_model_observer.h" | 21 #include "components/bookmarks/browser/bookmark_model_observer.h" |
| 22 #include "components/bookmarks/browser/bookmark_node_data.h" | 22 #include "components/bookmarks/browser/bookmark_node_data.h" |
| 23 #include "components/bookmarks/browser/bookmark_storage.h" | 23 #include "components/bookmarks/browser/bookmark_storage.h" |
| 24 #include "components/bookmarks/browser/bookmark_undo_delegate.h" |
| 24 #include "components/bookmarks/browser/bookmark_utils.h" | 25 #include "components/bookmarks/browser/bookmark_utils.h" |
| 25 #include "components/favicon_base/favicon_types.h" | 26 #include "components/favicon_base/favicon_types.h" |
| 26 #include "grit/components_strings.h" | 27 #include "grit/components_strings.h" |
| 27 #include "ui/base/l10n/l10n_util.h" | 28 #include "ui/base/l10n/l10n_util.h" |
| 28 #include "ui/gfx/favicon_size.h" | 29 #include "ui/gfx/favicon_size.h" |
| 29 | 30 |
| 30 using base::Time; | 31 using base::Time; |
| 31 | 32 |
| 32 namespace bookmarks { | 33 namespace bookmarks { |
| 33 | 34 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 *collator_, n1->GetTitle(), n2->GetTitle()) == UCOL_LESS; | 83 *collator_, n1->GetTitle(), n2->GetTitle()) == UCOL_LESS; |
| 83 } | 84 } |
| 84 // Types differ, sort such that folders come first. | 85 // Types differ, sort such that folders come first. |
| 85 return n1->is_folder(); | 86 return n1->is_folder(); |
| 86 } | 87 } |
| 87 | 88 |
| 88 private: | 89 private: |
| 89 icu::Collator* collator_; | 90 icu::Collator* collator_; |
| 90 }; | 91 }; |
| 91 | 92 |
| 93 // Delegate that does nothing. |
| 94 class EmptyUndoDelegate : public BookmarkUndoDelegate { |
| 95 public: |
| 96 EmptyUndoDelegate() {} |
| 97 ~EmptyUndoDelegate() override {} |
| 98 |
| 99 private: |
| 100 // BookmarkUndoDelegate: |
| 101 void SetUndoProvider(BookmarkUndoProvider* provider) override {} |
| 102 void OnBookmarkNodeRemoved(BookmarkModel* model, |
| 103 const BookmarkNode* parent, |
| 104 int index, |
| 105 scoped_ptr<BookmarkNode> node) override {} |
| 106 |
| 107 DISALLOW_COPY_AND_ASSIGN(EmptyUndoDelegate); |
| 108 }; |
| 109 |
| 92 } // namespace | 110 } // namespace |
| 93 | 111 |
| 94 // BookmarkModel -------------------------------------------------------------- | 112 // BookmarkModel -------------------------------------------------------------- |
| 95 | 113 |
| 96 BookmarkModel::BookmarkModel(BookmarkClient* client) | 114 BookmarkModel::BookmarkModel(BookmarkClient* client) |
| 97 : client_(client), | 115 : client_(client), |
| 98 loaded_(false), | 116 loaded_(false), |
| 99 root_(GURL()), | 117 root_(GURL()), |
| 100 bookmark_bar_node_(NULL), | 118 bookmark_bar_node_(NULL), |
| 101 other_node_(NULL), | 119 other_node_(NULL), |
| 102 mobile_node_(NULL), | 120 mobile_node_(NULL), |
| 103 next_node_id_(1), | 121 next_node_id_(1), |
| 104 observers_( | 122 observers_( |
| 105 base::ObserverList<BookmarkModelObserver>::NOTIFY_EXISTING_ONLY), | 123 base::ObserverList<BookmarkModelObserver>::NOTIFY_EXISTING_ONLY), |
| 106 loaded_signal_(true, false), | 124 loaded_signal_(true, false), |
| 107 extensive_changes_(0) { | 125 extensive_changes_(0), |
| 126 undo_delegate_(nullptr), |
| 127 empty_undo_delegate_(new EmptyUndoDelegate) { |
| 108 DCHECK(client_); | 128 DCHECK(client_); |
| 109 } | 129 } |
| 110 | 130 |
| 111 BookmarkModel::~BookmarkModel() { | 131 BookmarkModel::~BookmarkModel() { |
| 112 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, | 132 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, |
| 113 BookmarkModelBeingDeleted(this)); | 133 BookmarkModelBeingDeleted(this)); |
| 114 | 134 |
| 115 if (store_.get()) { | 135 if (store_.get()) { |
| 116 // The store maintains a reference back to us. We need to tell it we're gone | 136 // The store maintains a reference back to us. We need to tell it we're gone |
| 117 // so that it doesn't try and invoke a method back on us again. | 137 // so that it doesn't try and invoke a method back on us again. |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 | 212 |
| 193 void BookmarkModel::Remove(const BookmarkNode* node) { | 213 void BookmarkModel::Remove(const BookmarkNode* node) { |
| 194 DCHECK(loaded_); | 214 DCHECK(loaded_); |
| 195 DCHECK(node); | 215 DCHECK(node); |
| 196 DCHECK(!is_root_node(node)); | 216 DCHECK(!is_root_node(node)); |
| 197 RemoveAndDeleteNode(AsMutable(node)); | 217 RemoveAndDeleteNode(AsMutable(node)); |
| 198 } | 218 } |
| 199 | 219 |
| 200 void BookmarkModel::RemoveAllUserBookmarks() { | 220 void BookmarkModel::RemoveAllUserBookmarks() { |
| 201 std::set<GURL> removed_urls; | 221 std::set<GURL> removed_urls; |
| 202 ScopedVector<BookmarkNode> removed_nodes; | 222 struct RemoveNodeData { |
| 223 RemoveNodeData(const BookmarkNode* parent, int index, BookmarkNode* node) |
| 224 : parent(parent), index(index), node(node) {} |
| 225 |
| 226 const BookmarkNode* parent; |
| 227 int index; |
| 228 BookmarkNode* node; |
| 229 }; |
| 230 std::vector<RemoveNodeData> removed_node_data_list; |
| 203 | 231 |
| 204 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, | 232 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, |
| 205 OnWillRemoveAllUserBookmarks(this)); | 233 OnWillRemoveAllUserBookmarks(this)); |
| 206 | 234 |
| 207 BeginExtensiveChanges(); | 235 BeginExtensiveChanges(); |
| 208 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and | 236 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and |
| 209 // its immediate children. For removing all non permanent nodes just remove | 237 // its immediate children. For removing all non permanent nodes just remove |
| 210 // all children of non-root permanent nodes. | 238 // all children of non-root permanent nodes. |
| 211 { | 239 { |
| 212 base::AutoLock url_lock(url_lock_); | 240 base::AutoLock url_lock(url_lock_); |
| 213 for (int i = 0; i < root_.child_count(); ++i) { | 241 for (int i = 0; i < root_.child_count(); ++i) { |
| 214 BookmarkNode* permanent_node = root_.GetChild(i); | 242 const BookmarkNode* permanent_node = root_.GetChild(i); |
| 215 | 243 |
| 216 if (!client_->CanBeEditedByUser(permanent_node)) | 244 if (!client_->CanBeEditedByUser(permanent_node)) |
| 217 continue; | 245 continue; |
| 218 | 246 |
| 219 for (int j = permanent_node->child_count() - 1; j >= 0; --j) { | 247 for (int j = permanent_node->child_count() - 1; j >= 0; --j) { |
| 220 BookmarkNode* child_node = permanent_node->GetChild(j); | 248 BookmarkNode* child_node = AsMutable(permanent_node->GetChild(j)); |
| 221 removed_nodes.push_back(child_node); | |
| 222 RemoveNodeAndGetRemovedUrls(child_node, &removed_urls); | 249 RemoveNodeAndGetRemovedUrls(child_node, &removed_urls); |
| 250 removed_node_data_list.push_back( |
| 251 RemoveNodeData(permanent_node, j, child_node)); |
| 223 } | 252 } |
| 224 } | 253 } |
| 225 } | 254 } |
| 226 EndExtensiveChanges(); | 255 EndExtensiveChanges(); |
| 227 if (store_.get()) | 256 if (store_.get()) |
| 228 store_->ScheduleSave(); | 257 store_->ScheduleSave(); |
| 229 | 258 |
| 230 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, | 259 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, |
| 231 BookmarkAllUserNodesRemoved(this, removed_urls)); | 260 BookmarkAllUserNodesRemoved(this, removed_urls)); |
| 261 |
| 262 BeginGroupedChanges(); |
| 263 for (const auto& removed_node_data : removed_node_data_list) { |
| 264 undo_delegate()->OnBookmarkNodeRemoved( |
| 265 this, |
| 266 removed_node_data.parent, |
| 267 removed_node_data.index, |
| 268 scoped_ptr<BookmarkNode>(removed_node_data.node)); |
| 269 } |
| 270 EndGroupedChanges(); |
| 232 } | 271 } |
| 233 | 272 |
| 234 void BookmarkModel::Move(const BookmarkNode* node, | 273 void BookmarkModel::Move(const BookmarkNode* node, |
| 235 const BookmarkNode* new_parent, | 274 const BookmarkNode* new_parent, |
| 236 int index) { | 275 int index) { |
| 237 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) || | 276 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) || |
| 238 is_root_node(new_parent) || is_permanent_node(node)) { | 277 is_root_node(new_parent) || is_permanent_node(node)) { |
| 239 NOTREACHED(); | 278 NOTREACHED(); |
| 240 return; | 279 return; |
| 241 } | 280 } |
| (...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 711 case BookmarkNode::OTHER_NODE: | 750 case BookmarkNode::OTHER_NODE: |
| 712 return other_node_; | 751 return other_node_; |
| 713 case BookmarkNode::MOBILE: | 752 case BookmarkNode::MOBILE: |
| 714 return mobile_node_; | 753 return mobile_node_; |
| 715 default: | 754 default: |
| 716 NOTREACHED(); | 755 NOTREACHED(); |
| 717 return NULL; | 756 return NULL; |
| 718 } | 757 } |
| 719 } | 758 } |
| 720 | 759 |
| 760 void BookmarkModel::RestoreRemovedNode(const BookmarkNode* parent, |
| 761 int index, |
| 762 scoped_ptr<BookmarkNode> scoped_node) { |
| 763 BookmarkNode* node = scoped_node.release(); |
| 764 AddNode(AsMutable(parent), index, node); |
| 765 |
| 766 // We might be restoring a folder node that have already contained a set of |
| 767 // child nodes. We need to notify all of them. |
| 768 NotifyNodeAddedForAllDescendents(node); |
| 769 } |
| 770 |
| 771 void BookmarkModel::NotifyNodeAddedForAllDescendents(const BookmarkNode* node) { |
| 772 for (int i = 0; i < node->child_count(); ++i) { |
| 773 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, |
| 774 BookmarkNodeAdded(this, node, i)); |
| 775 NotifyNodeAddedForAllDescendents(node->GetChild(i)); |
| 776 } |
| 777 } |
| 778 |
| 721 bool BookmarkModel::IsBookmarkedNoLock(const GURL& url) { | 779 bool BookmarkModel::IsBookmarkedNoLock(const GURL& url) { |
| 722 BookmarkNode tmp_node(url); | 780 BookmarkNode tmp_node(url); |
| 723 return (nodes_ordered_by_url_set_.find(&tmp_node) != | 781 return (nodes_ordered_by_url_set_.find(&tmp_node) != |
| 724 nodes_ordered_by_url_set_.end()); | 782 nodes_ordered_by_url_set_.end()); |
| 725 } | 783 } |
| 726 | 784 |
| 727 void BookmarkModel::RemoveNode(BookmarkNode* node, | 785 void BookmarkModel::RemoveNode(BookmarkNode* node, |
| 728 std::set<GURL>* removed_urls) { | 786 std::set<GURL>* removed_urls) { |
| 729 if (!loaded_ || !node || is_permanent_node(node)) { | 787 if (!loaded_ || !node || is_permanent_node(node)) { |
| 730 NOTREACHED(); | 788 NOTREACHED(); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 852 RemoveNodeAndGetRemovedUrls(node.get(), &removed_urls); | 910 RemoveNodeAndGetRemovedUrls(node.get(), &removed_urls); |
| 853 } | 911 } |
| 854 | 912 |
| 855 if (store_.get()) | 913 if (store_.get()) |
| 856 store_->ScheduleSave(); | 914 store_->ScheduleSave(); |
| 857 | 915 |
| 858 FOR_EACH_OBSERVER( | 916 FOR_EACH_OBSERVER( |
| 859 BookmarkModelObserver, | 917 BookmarkModelObserver, |
| 860 observers_, | 918 observers_, |
| 861 BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls)); | 919 BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls)); |
| 920 |
| 921 undo_delegate()->OnBookmarkNodeRemoved(this, parent, index, node.Pass()); |
| 862 } | 922 } |
| 863 | 923 |
| 864 void BookmarkModel::RemoveNodeFromInternalMaps(BookmarkNode* node) { | 924 void BookmarkModel::RemoveNodeFromInternalMaps(BookmarkNode* node) { |
| 865 index_->Remove(node); | 925 index_->Remove(node); |
| 866 // NOTE: this is called in such a way that url_lock_ is already held. As | 926 // NOTE: this is called in such a way that url_lock_ is already held. As |
| 867 // such, this doesn't explicitly grab the lock. | 927 // such, this doesn't explicitly grab the lock. |
| 868 url_lock_.AssertAcquired(); | 928 url_lock_.AssertAcquired(); |
| 869 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node); | 929 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node); |
| 870 DCHECK(i != nodes_ordered_by_url_set_.end()); | 930 DCHECK(i != nodes_ordered_by_url_set_.end()); |
| 871 // i points to the first node with the URL, advance until we find the | 931 // i points to the first node with the URL, advance until we find the |
| (...skipping 30 matching lines...) Expand all Loading... |
| 902 } | 962 } |
| 903 | 963 |
| 904 BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent, | 964 BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent, |
| 905 int index, | 965 int index, |
| 906 BookmarkNode* node) { | 966 BookmarkNode* node) { |
| 907 parent->Add(node, index); | 967 parent->Add(node, index); |
| 908 | 968 |
| 909 if (store_.get()) | 969 if (store_.get()) |
| 910 store_->ScheduleSave(); | 970 store_->ScheduleSave(); |
| 911 | 971 |
| 912 if (node->type() == BookmarkNode::URL) { | 972 { |
| 913 base::AutoLock url_lock(url_lock_); | 973 base::AutoLock url_lock(url_lock_); |
| 914 AddNodeToInternalMaps(node); | 974 AddNodeToInternalMaps(node); |
| 915 } else { | |
| 916 index_->Add(node); | |
| 917 } | 975 } |
| 918 | 976 |
| 919 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, | 977 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, |
| 920 BookmarkNodeAdded(this, parent, index)); | 978 BookmarkNodeAdded(this, parent, index)); |
| 921 | 979 |
| 922 return node; | 980 return node; |
| 923 } | 981 } |
| 924 | 982 |
| 925 void BookmarkModel::AddNodeToInternalMaps(BookmarkNode* node) { | 983 void BookmarkModel::AddNodeToInternalMaps(BookmarkNode* node) { |
| 926 index_->Add(node); | |
| 927 url_lock_.AssertAcquired(); | 984 url_lock_.AssertAcquired(); |
| 928 nodes_ordered_by_url_set_.insert(node); | 985 if (node->is_url()) { |
| 986 index_->Add(node); |
| 987 nodes_ordered_by_url_set_.insert(node); |
| 988 } |
| 989 for (int i = 0; i < node->child_count(); ++i) |
| 990 AddNodeToInternalMaps(node->GetChild(i)); |
| 929 } | 991 } |
| 930 | 992 |
| 931 bool BookmarkModel::IsValidIndex(const BookmarkNode* parent, | 993 bool BookmarkModel::IsValidIndex(const BookmarkNode* parent, |
| 932 int index, | 994 int index, |
| 933 bool allow_end) { | 995 bool allow_end) { |
| 934 return (parent && parent->is_folder() && | 996 return (parent && parent->is_folder() && |
| 935 (index >= 0 && (index < parent->child_count() || | 997 (index >= 0 && (index < parent->child_count() || |
| 936 (allow_end && index == parent->child_count())))); | 998 (allow_end && index == parent->child_count())))); |
| 937 } | 999 } |
| 938 | 1000 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1041 CreatePermanentNode(BookmarkNode::MOBILE); | 1103 CreatePermanentNode(BookmarkNode::MOBILE); |
| 1042 return scoped_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails( | 1104 return scoped_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails( |
| 1043 bb_node, | 1105 bb_node, |
| 1044 other_node, | 1106 other_node, |
| 1045 mobile_node, | 1107 mobile_node, |
| 1046 client_->GetLoadExtraNodesCallback(), | 1108 client_->GetLoadExtraNodesCallback(), |
| 1047 new BookmarkIndex(client_, accept_languages), | 1109 new BookmarkIndex(client_, accept_languages), |
| 1048 next_node_id_)); | 1110 next_node_id_)); |
| 1049 } | 1111 } |
| 1050 | 1112 |
| 1113 void BookmarkModel::SetUndoDelegate(BookmarkUndoDelegate* undo_delegate) { |
| 1114 undo_delegate_ = undo_delegate; |
| 1115 if (undo_delegate_) |
| 1116 undo_delegate_->SetUndoProvider(this); |
| 1117 } |
| 1118 |
| 1119 BookmarkUndoDelegate* BookmarkModel::undo_delegate() const { |
| 1120 return undo_delegate_ ? undo_delegate_ : empty_undo_delegate_.get(); |
| 1121 } |
| 1122 |
| 1051 } // namespace bookmarks | 1123 } // namespace bookmarks |
| OLD | NEW |