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

Side by Side Diff: components/bookmarks/browser/bookmark_model.cc

Issue 1379983002: Supporting undoing bookmark deletion without creating new ID. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address feedback Created 5 years, 2 months 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 unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698