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

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 some more 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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « components/bookmarks/browser/bookmark_model.h ('k') | components/bookmarks/browser/bookmark_model_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698