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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 : client_(client), | 98 : client_(client), |
98 loaded_(false), | 99 loaded_(false), |
99 root_(GURL()), | 100 root_(GURL()), |
100 bookmark_bar_node_(NULL), | 101 bookmark_bar_node_(NULL), |
101 other_node_(NULL), | 102 other_node_(NULL), |
102 mobile_node_(NULL), | 103 mobile_node_(NULL), |
103 next_node_id_(1), | 104 next_node_id_(1), |
104 observers_( | 105 observers_( |
105 base::ObserverList<BookmarkModelObserver>::NOTIFY_EXISTING_ONLY), | 106 base::ObserverList<BookmarkModelObserver>::NOTIFY_EXISTING_ONLY), |
106 loaded_signal_(true, false), | 107 loaded_signal_(true, false), |
107 extensive_changes_(0) { | 108 extensive_changes_(0), |
109 undo_delegate_(nullptr) { | |
108 DCHECK(client_); | 110 DCHECK(client_); |
109 } | 111 } |
110 | 112 |
111 BookmarkModel::~BookmarkModel() { | 113 BookmarkModel::~BookmarkModel() { |
112 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, | 114 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, |
113 BookmarkModelBeingDeleted(this)); | 115 BookmarkModelBeingDeleted(this)); |
114 | 116 |
115 if (store_.get()) { | 117 if (store_.get()) { |
116 // The store maintains a reference back to us. We need to tell it we're gone | 118 // 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. | 119 // so that it doesn't try and invoke a method back on us again. |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
193 void BookmarkModel::Remove(const BookmarkNode* node) { | 195 void BookmarkModel::Remove(const BookmarkNode* node) { |
194 DCHECK(loaded_); | 196 DCHECK(loaded_); |
195 DCHECK(node); | 197 DCHECK(node); |
196 DCHECK(!is_root_node(node)); | 198 DCHECK(!is_root_node(node)); |
197 RemoveAndDeleteNode(AsMutable(node)); | 199 RemoveAndDeleteNode(AsMutable(node)); |
198 } | 200 } |
199 | 201 |
200 void BookmarkModel::RemoveAllUserBookmarks() { | 202 void BookmarkModel::RemoveAllUserBookmarks() { |
201 std::set<GURL> removed_urls; | 203 std::set<GURL> removed_urls; |
202 ScopedVector<BookmarkNode> removed_nodes; | 204 ScopedVector<BookmarkNode> removed_nodes; |
205 std::vector<std::pair<const BookmarkNode*, int>> removed_node_data; | |
203 | 206 |
204 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, | 207 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, |
205 OnWillRemoveAllUserBookmarks(this)); | 208 OnWillRemoveAllUserBookmarks(this)); |
206 | 209 |
207 BeginExtensiveChanges(); | 210 BeginExtensiveChanges(); |
208 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and | 211 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and |
209 // its immediate children. For removing all non permanent nodes just remove | 212 // its immediate children. For removing all non permanent nodes just remove |
210 // all children of non-root permanent nodes. | 213 // all children of non-root permanent nodes. |
211 { | 214 { |
212 base::AutoLock url_lock(url_lock_); | 215 base::AutoLock url_lock(url_lock_); |
213 for (int i = 0; i < root_.child_count(); ++i) { | 216 for (int i = 0; i < root_.child_count(); ++i) { |
214 BookmarkNode* permanent_node = root_.GetChild(i); | 217 BookmarkNode* permanent_node = root_.GetChild(i); |
215 | 218 |
216 if (!client_->CanBeEditedByUser(permanent_node)) | 219 if (!client_->CanBeEditedByUser(permanent_node)) |
217 continue; | 220 continue; |
218 | 221 |
219 for (int j = permanent_node->child_count() - 1; j >= 0; --j) { | 222 for (int j = permanent_node->child_count() - 1; j >= 0; --j) { |
220 BookmarkNode* child_node = permanent_node->GetChild(j); | 223 BookmarkNode* child_node = permanent_node->GetChild(j); |
224 RemoveNodeAndGetRemovedUrls(child_node, &removed_urls); | |
221 removed_nodes.push_back(child_node); | 225 removed_nodes.push_back(child_node); |
sky
2015/10/08 15:20:00
You shouldn't need both removed_nodes and removed_
jianli
2015/10/08 23:37:40
Done.
| |
222 RemoveNodeAndGetRemovedUrls(child_node, &removed_urls); | 226 removed_node_data.push_back(std::make_pair(permanent_node, j)); |
sky
2015/10/08 15:20:00
Please add test coverage here as permanent_node is
jianli
2015/10/08 23:37:40
I've updated BookmarkModelTest.RemoveAllUserBookma
sky
2015/10/09 16:01:19
Also add coverage that the undodelegate is in fact
jianli
2015/10/09 21:51:16
Done.
| |
223 } | 227 } |
224 } | 228 } |
225 } | 229 } |
226 EndExtensiveChanges(); | 230 EndExtensiveChanges(); |
227 if (store_.get()) | 231 if (store_.get()) |
228 store_->ScheduleSave(); | 232 store_->ScheduleSave(); |
229 | 233 |
230 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, | 234 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, |
231 BookmarkAllUserNodesRemoved(this, removed_urls)); | 235 BookmarkAllUserNodesRemoved(this, removed_urls)); |
236 | |
237 if (undo_delegate_) { | |
sky
2015/10/08 15:20:00
Again, always have an undo_delegate_ so that it al
jianli
2015/10/08 23:37:40
Done.
| |
238 BeginGroupedChanges(); | |
239 for (size_t i = 0; i < removed_nodes.size(); ++i) { | |
240 undo_delegate_->OnBookmarkNodeDeleted( | |
241 this, this, removed_node_data[i].first, removed_node_data[i].second, | |
242 scoped_ptr<BookmarkNode>(removed_nodes[i])); | |
243 } | |
244 EndGroupedChanges(); | |
245 removed_nodes.weak_clear(); | |
246 } | |
232 } | 247 } |
233 | 248 |
234 void BookmarkModel::Move(const BookmarkNode* node, | 249 void BookmarkModel::Move(const BookmarkNode* node, |
235 const BookmarkNode* new_parent, | 250 const BookmarkNode* new_parent, |
236 int index) { | 251 int index) { |
237 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) || | 252 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) || |
238 is_root_node(new_parent) || is_permanent_node(node)) { | 253 is_root_node(new_parent) || is_permanent_node(node)) { |
239 NOTREACHED(); | 254 NOTREACHED(); |
240 return; | 255 return; |
241 } | 256 } |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
711 case BookmarkNode::OTHER_NODE: | 726 case BookmarkNode::OTHER_NODE: |
712 return other_node_; | 727 return other_node_; |
713 case BookmarkNode::MOBILE: | 728 case BookmarkNode::MOBILE: |
714 return mobile_node_; | 729 return mobile_node_; |
715 default: | 730 default: |
716 NOTREACHED(); | 731 NOTREACHED(); |
717 return NULL; | 732 return NULL; |
718 } | 733 } |
719 } | 734 } |
720 | 735 |
736 void BookmarkModel::RestoreRemovedNode(const BookmarkNode* parent, | |
737 int index, | |
738 scoped_ptr<BookmarkNode> scoped_node) { | |
739 BookmarkNode* node = scoped_node.release(); | |
740 AsMutable(parent)->Add(node, index); | |
sky
2015/10/08 15:20:00
Use AddNode for the common parts.
jianli
2015/10/08 23:37:40
Done.
| |
741 | |
742 if (store_.get()) | |
743 store_->ScheduleSave(); | |
744 | |
745 { | |
746 base::AutoLock url_lock(url_lock_); | |
747 AddNodeToInternalMaps(node); | |
748 } | |
749 | |
750 // We might be restoring a folder node that have already contained a set of | |
751 // child nodes. We need to notify all of them. | |
752 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, | |
753 BookmarkNodeAdded(this, parent, index)); | |
754 NotifyNodeAddedForAllDescendents(node); | |
755 } | |
756 | |
757 void BookmarkModel::NotifyNodeAddedForAllDescendents(const BookmarkNode* node) { | |
758 for (int i = 0; i < node->child_count(); ++i) { | |
759 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, | |
760 BookmarkNodeAdded(this, node, i)); | |
761 NotifyNodeAddedForAllDescendents(node->GetChild(i)); | |
762 } | |
763 } | |
764 | |
721 bool BookmarkModel::IsBookmarkedNoLock(const GURL& url) { | 765 bool BookmarkModel::IsBookmarkedNoLock(const GURL& url) { |
722 BookmarkNode tmp_node(url); | 766 BookmarkNode tmp_node(url); |
723 return (nodes_ordered_by_url_set_.find(&tmp_node) != | 767 return (nodes_ordered_by_url_set_.find(&tmp_node) != |
724 nodes_ordered_by_url_set_.end()); | 768 nodes_ordered_by_url_set_.end()); |
725 } | 769 } |
726 | 770 |
727 void BookmarkModel::RemoveNode(BookmarkNode* node, | 771 void BookmarkModel::RemoveNode(BookmarkNode* node, |
728 std::set<GURL>* removed_urls) { | 772 std::set<GURL>* removed_urls) { |
729 if (!loaded_ || !node || is_permanent_node(node)) { | 773 if (!loaded_ || !node || is_permanent_node(node)) { |
730 NOTREACHED(); | 774 NOTREACHED(); |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
852 RemoveNodeAndGetRemovedUrls(node.get(), &removed_urls); | 896 RemoveNodeAndGetRemovedUrls(node.get(), &removed_urls); |
853 } | 897 } |
854 | 898 |
855 if (store_.get()) | 899 if (store_.get()) |
856 store_->ScheduleSave(); | 900 store_->ScheduleSave(); |
857 | 901 |
858 FOR_EACH_OBSERVER( | 902 FOR_EACH_OBSERVER( |
859 BookmarkModelObserver, | 903 BookmarkModelObserver, |
860 observers_, | 904 observers_, |
861 BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls)); | 905 BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls)); |
906 | |
907 if (undo_delegate_) { | |
908 undo_delegate_->OnBookmarkNodeDeleted( | |
909 this, this, parent, index, node.Pass()); | |
910 } | |
862 } | 911 } |
863 | 912 |
864 void BookmarkModel::RemoveNodeFromInternalMaps(BookmarkNode* node) { | 913 void BookmarkModel::RemoveNodeFromInternalMaps(BookmarkNode* node) { |
865 index_->Remove(node); | 914 index_->Remove(node); |
866 // NOTE: this is called in such a way that url_lock_ is already held. As | 915 // NOTE: this is called in such a way that url_lock_ is already held. As |
867 // such, this doesn't explicitly grab the lock. | 916 // such, this doesn't explicitly grab the lock. |
868 url_lock_.AssertAcquired(); | 917 url_lock_.AssertAcquired(); |
869 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node); | 918 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node); |
870 DCHECK(i != nodes_ordered_by_url_set_.end()); | 919 DCHECK(i != nodes_ordered_by_url_set_.end()); |
871 // i points to the first node with the URL, advance until we find the | 920 // i points to the first node with the URL, advance until we find the |
(...skipping 30 matching lines...) Expand all Loading... | |
902 } | 951 } |
903 | 952 |
904 BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent, | 953 BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent, |
905 int index, | 954 int index, |
906 BookmarkNode* node) { | 955 BookmarkNode* node) { |
907 parent->Add(node, index); | 956 parent->Add(node, index); |
908 | 957 |
909 if (store_.get()) | 958 if (store_.get()) |
910 store_->ScheduleSave(); | 959 store_->ScheduleSave(); |
911 | 960 |
912 if (node->type() == BookmarkNode::URL) { | 961 { |
913 base::AutoLock url_lock(url_lock_); | 962 base::AutoLock url_lock(url_lock_); |
914 AddNodeToInternalMaps(node); | 963 AddNodeToInternalMaps(node); |
915 } else { | |
916 index_->Add(node); | |
917 } | 964 } |
918 | 965 |
919 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, | 966 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, |
920 BookmarkNodeAdded(this, parent, index)); | 967 BookmarkNodeAdded(this, parent, index)); |
921 | 968 |
922 return node; | 969 return node; |
923 } | 970 } |
924 | 971 |
925 void BookmarkModel::AddNodeToInternalMaps(BookmarkNode* node) { | 972 void BookmarkModel::AddNodeToInternalMaps(BookmarkNode* node) { |
926 index_->Add(node); | |
927 url_lock_.AssertAcquired(); | 973 url_lock_.AssertAcquired(); |
928 nodes_ordered_by_url_set_.insert(node); | 974 if (node->is_url()) { |
975 index_->Add(node); | |
976 nodes_ordered_by_url_set_.insert(node); | |
977 } | |
978 for (int i = 0; i < node->child_count(); ++i) | |
979 AddNodeToInternalMaps(node->GetChild(i)); | |
929 } | 980 } |
930 | 981 |
931 bool BookmarkModel::IsValidIndex(const BookmarkNode* parent, | 982 bool BookmarkModel::IsValidIndex(const BookmarkNode* parent, |
932 int index, | 983 int index, |
933 bool allow_end) { | 984 bool allow_end) { |
934 return (parent && parent->is_folder() && | 985 return (parent && parent->is_folder() && |
935 (index >= 0 && (index < parent->child_count() || | 986 (index >= 0 && (index < parent->child_count() || |
936 (allow_end && index == parent->child_count())))); | 987 (allow_end && index == parent->child_count())))); |
937 } | 988 } |
938 | 989 |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1042 return scoped_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails( | 1093 return scoped_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails( |
1043 bb_node, | 1094 bb_node, |
1044 other_node, | 1095 other_node, |
1045 mobile_node, | 1096 mobile_node, |
1046 client_->GetLoadExtraNodesCallback(), | 1097 client_->GetLoadExtraNodesCallback(), |
1047 new BookmarkIndex(client_, accept_languages), | 1098 new BookmarkIndex(client_, accept_languages), |
1048 next_node_id_)); | 1099 next_node_id_)); |
1049 } | 1100 } |
1050 | 1101 |
1051 } // namespace bookmarks | 1102 } // namespace bookmarks |
OLD | NEW |