blob: 179083b8076bd91c0d5c03c26198fc8d813ca193 [file] [log] [blame]
[email protected]c47f86fa2014-04-30 02:20:181// Copyright 2014 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]a90c8ca2014-05-20 17:16:045#include "components/bookmarks/browser/bookmark_model.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]4e425be42011-01-15 06:56:097#include <algorithm>
8#include <functional>
dcheng51606352015-12-26 21:16:239#include <utility>
[email protected]4e425be42011-01-15 06:56:0910
[email protected]bbdd2982011-10-08 18:14:2411#include "base/bind.h"
12#include "base/bind_helpers.h"
[email protected]9a08fe82013-04-23 05:06:0513#include "base/i18n/string_compare.h"
[email protected]6a848b52014-04-26 22:06:5414#include "base/logging.h"
[email protected]996dbe82014-05-12 12:32:1815#include "base/macros.h"
avicee78e4e2016-09-30 17:08:1416#include "base/memory/ptr_util.h"
pkotwiczca240dd2015-07-09 16:15:3217#include "base/metrics/histogram_macros.h"
robliaoad0efe962015-03-14 00:13:0218#include "base/profiler/scoped_tracker.h"
[email protected]6a848b52014-04-26 22:06:5419#include "base/strings/string_util.h"
[email protected]a90c8ca2014-05-20 17:16:0420#include "components/bookmarks/browser/bookmark_expanded_state_tracker.h"
[email protected]a90c8ca2014-05-20 17:16:0421#include "components/bookmarks/browser/bookmark_model_observer.h"
22#include "components/bookmarks/browser/bookmark_node_data.h"
23#include "components/bookmarks/browser/bookmark_storage.h"
jianli14436d52015-10-09 22:47:3524#include "components/bookmarks/browser/bookmark_undo_delegate.h"
[email protected]a90c8ca2014-05-20 17:16:0425#include "components/bookmarks/browser/bookmark_utils.h"
mattreynolds25e9a312016-12-14 21:52:1326#include "components/bookmarks/browser/titled_url_index.h"
27#include "components/bookmarks/browser/titled_url_match.h"
mattreynolds191b88722016-12-13 19:25:3228#include "components/bookmarks/browser/typed_count_sorter.h"
[email protected]7627e0b42014-04-17 17:20:5329#include "components/favicon_base/favicon_types.h"
thakisfe8fa0a2017-02-23 19:46:3630#include "components/strings/grit/components_strings.h"
[email protected]c051a1b2011-01-21 23:30:1731#include "ui/base/l10n/l10n_util.h"
[email protected]65baa222012-08-30 15:43:5132#include "ui/gfx/favicon_size.h"
initial.commit09911bf2008-07-26 23:55:2933
[email protected]e1acf6f2008-10-27 20:43:3334using base::Time;
tfarinaa0ec34e2015-01-12 18:46:4835
36namespace bookmarks {
[email protected]e1acf6f2008-10-27 20:43:3337
[email protected]b3c33d462009-06-26 22:29:2038namespace {
39
40// Helper to get a mutable bookmark node.
[email protected]7b084b02011-07-08 16:06:4841BookmarkNode* AsMutable(const BookmarkNode* node) {
[email protected]b3c33d462009-06-26 22:29:2042 return const_cast<BookmarkNode*>(node);
43}
44
[email protected]996dbe82014-05-12 12:32:1845// Helper to get a mutable permanent bookmark node.
46BookmarkPermanentNode* AsMutable(const BookmarkPermanentNode* node) {
47 return const_cast<BookmarkPermanentNode*>(node);
48}
49
50// Comparator used when sorting permanent nodes. Nodes that are initially
51// visible are sorted before nodes that are initially hidden.
vmpstr3abe3302016-03-09 19:38:1952class VisibilityComparator {
[email protected]996dbe82014-05-12 12:32:1853 public:
54 explicit VisibilityComparator(BookmarkClient* client) : client_(client) {}
55
avicee78e4e2016-09-30 17:08:1456 // Returns true if |n1| precedes |n2|.
57 bool operator()(const std::unique_ptr<BookmarkPermanentNode>& n1,
58 const std::unique_ptr<BookmarkPermanentNode>& n2) {
59 bool n1_visible = client_->IsPermanentNodeVisible(n1.get());
60 bool n2_visible = client_->IsPermanentNodeVisible(n2.get());
[email protected]996dbe82014-05-12 12:32:1861 return n1_visible != n2_visible && n1_visible;
62 }
63
64 private:
65 BookmarkClient* client_;
66};
67
[email protected]ef762642009-03-05 16:30:2568// Comparator used when sorting bookmarks. Folders are sorted first, then
[email protected]2c685cc22009-08-28 00:17:4469// bookmarks.
vmpstr3abe3302016-03-09 19:38:1970class SortComparator {
[email protected]ef762642009-03-05 16:30:2571 public:
[email protected]a48f87d2012-10-09 18:06:3372 explicit SortComparator(icu::Collator* collator) : collator_(collator) {}
[email protected]ef762642009-03-05 16:30:2573
avicee78e4e2016-09-30 17:08:1474 // Returns true if |n1| precedes |n2|.
75 bool operator()(const std::unique_ptr<BookmarkNode>& n1,
76 const std::unique_ptr<BookmarkNode>& n2) {
[email protected]037db002009-10-19 20:06:0877 if (n1->type() == n2->type()) {
[email protected]ef762642009-03-05 16:30:2578 // Types are the same, compare the names.
79 if (!collator_)
[email protected]440b37b22010-08-30 05:31:4080 return n1->GetTitle() < n2->GetTitle();
[email protected]9a08fe82013-04-23 05:06:0581 return base::i18n::CompareString16WithCollator(
estade1274f882015-04-11 05:13:3582 *collator_, n1->GetTitle(), n2->GetTitle()) == UCOL_LESS;
[email protected]ef762642009-03-05 16:30:2583 }
84 // Types differ, sort such that folders come first.
85 return n1->is_folder();
86 }
87
88 private:
[email protected]b5b2385a2009-08-18 05:12:2989 icu::Collator* collator_;
[email protected]ef762642009-03-05 16:30:2590};
91
jianli14436d52015-10-09 22:47:3592// Delegate that does nothing.
93class EmptyUndoDelegate : public BookmarkUndoDelegate {
94 public:
95 EmptyUndoDelegate() {}
96 ~EmptyUndoDelegate() override {}
97
98 private:
99 // BookmarkUndoDelegate:
100 void SetUndoProvider(BookmarkUndoProvider* provider) override {}
101 void OnBookmarkNodeRemoved(BookmarkModel* model,
102 const BookmarkNode* parent,
103 int index,
dchengacd3f522016-04-21 22:30:41104 std::unique_ptr<BookmarkNode> node) override {}
jianli14436d52015-10-09 22:47:35105
106 DISALLOW_COPY_AND_ASSIGN(EmptyUndoDelegate);
107};
108
[email protected]bc770a032011-12-12 17:35:30109} // namespace
[email protected]97fdd162011-12-03 20:50:12110
[email protected]97fdd162011-12-03 20:50:12111// BookmarkModel --------------------------------------------------------------
112
dchengacd3f522016-04-21 22:30:41113BookmarkModel::BookmarkModel(std::unique_ptr<BookmarkClient> client)
sdefresne070a5102016-02-01 13:42:14114 : client_(std::move(client)),
initial.commit09911bf2008-07-26 23:55:29115 loaded_(false),
[email protected]ea2e5aa52009-05-20 18:01:28116 root_(GURL()),
initial.commit09911bf2008-07-26 23:55:29117 bookmark_bar_node_(NULL),
[email protected]90ef13132008-08-27 03:27:46118 other_node_(NULL),
[email protected]37bc9132011-12-01 22:29:29119 mobile_node_(NULL),
[email protected]4d89f382009-05-12 06:56:49120 next_node_id_(1),
brettw236d3172015-06-03 16:31:43121 observers_(
122 base::ObserverList<BookmarkModelObserver>::NOTIFY_EXISTING_ONLY),
gab77f88322016-06-02 13:47:03123 loaded_signal_(base::WaitableEvent::ResetPolicy::MANUAL,
124 base::WaitableEvent::InitialState::NOT_SIGNALED),
jianli14436d52015-10-09 22:47:35125 extensive_changes_(0),
126 undo_delegate_(nullptr),
127 empty_undo_delegate_(new EmptyUndoDelegate) {
[email protected]6a848b52014-04-26 22:06:54128 DCHECK(client_);
sdefresne070a5102016-02-01 13:42:14129 client_->Init(this);
initial.commit09911bf2008-07-26 23:55:29130}
131
[email protected]d8e41ed2008-09-11 15:22:32132BookmarkModel::~BookmarkModel() {
tfarina2fa1d2fb2016-10-19 01:44:31133 for (BookmarkModelObserver& observer : observers_)
134 observer.BookmarkModelBeingDeleted(this);
[email protected]3de6fd342008-09-05 02:44:51135
[email protected]dc24976f2013-06-02 21:15:09136 if (store_.get()) {
[email protected]f25387b2008-08-21 15:20:33137 // The store maintains a reference back to us. We need to tell it we're gone
138 // so that it doesn't try and invoke a method back on us again.
139 store_->BookmarkModelDeleted();
initial.commit09911bf2008-07-26 23:55:29140 }
141}
142
[email protected]f61f4782012-06-08 21:54:21143void BookmarkModel::Shutdown() {
[email protected]88e6a232011-09-14 14:53:20144 if (loaded_)
145 return;
146
[email protected]f61f4782012-06-08 21:54:21147 // See comment in HistoryService::ShutdownOnUIThread where this is invoked for
148 // details. It is also called when the BookmarkModel is deleted.
[email protected]88e6a232011-09-14 14:53:20149 loaded_signal_.Signal();
150}
151
[email protected]afecfb72013-04-18 17:17:33152void BookmarkModel::Load(
[email protected]6a848b52014-04-26 22:06:54153 PrefService* pref_service,
[email protected]6a848b52014-04-26 22:06:54154 const base::FilePath& profile_path,
155 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
156 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) {
[email protected]90ef13132008-08-27 03:27:46157 if (store_.get()) {
158 // If the store is non-null, it means Load was already invoked. Load should
159 // only be invoked once.
160 NOTREACHED();
161 return;
162 }
163
[email protected]6df6ec022013-07-16 03:05:22164 expanded_state_tracker_.reset(
[email protected]6a848b52014-04-26 22:06:54165 new BookmarkExpandedStateTracker(this, pref_service));
[email protected]90ef13132008-08-27 03:27:46166
167 // Load the bookmarks. BookmarkStorage notifies us when done.
skyad686a32015-06-25 17:42:28168 store_.reset(new BookmarkStorage(this, profile_path, io_task_runner.get()));
jshin1fb76462016-04-05 22:13:03169 store_->LoadBookmarks(CreateLoadDetails(), ui_task_runner);
[email protected]90ef13132008-08-27 03:27:46170}
171
[email protected]125b234182011-07-08 19:54:41172void BookmarkModel::AddObserver(BookmarkModelObserver* observer) {
173 observers_.AddObserver(observer);
174}
175
176void BookmarkModel::RemoveObserver(BookmarkModelObserver* observer) {
177 observers_.RemoveObserver(observer);
178}
179
[email protected]b68a8172012-02-17 00:25:18180void BookmarkModel::BeginExtensiveChanges() {
181 if (++extensive_changes_ == 1) {
tfarina2fa1d2fb2016-10-19 01:44:31182 for (BookmarkModelObserver& observer : observers_)
183 observer.ExtensiveBookmarkChangesBeginning(this);
[email protected]b68a8172012-02-17 00:25:18184 }
[email protected]125b234182011-07-08 19:54:41185}
186
[email protected]b68a8172012-02-17 00:25:18187void BookmarkModel::EndExtensiveChanges() {
188 --extensive_changes_;
189 DCHECK_GE(extensive_changes_, 0);
190 if (extensive_changes_ == 0) {
tfarina2fa1d2fb2016-10-19 01:44:31191 for (BookmarkModelObserver& observer : observers_)
192 observer.ExtensiveBookmarkChangesEnded(this);
[email protected]b68a8172012-02-17 00:25:18193 }
[email protected]125b234182011-07-08 19:54:41194}
195
[email protected]346453a2014-03-12 10:14:37196void BookmarkModel::BeginGroupedChanges() {
tfarina2fa1d2fb2016-10-19 01:44:31197 for (BookmarkModelObserver& observer : observers_)
198 observer.GroupedBookmarkChangesBeginning(this);
[email protected]346453a2014-03-12 10:14:37199}
200
201void BookmarkModel::EndGroupedChanges() {
tfarina2fa1d2fb2016-10-19 01:44:31202 for (BookmarkModelObserver& observer : observers_)
203 observer.GroupedBookmarkChangesEnded(this);
[email protected]346453a2014-03-12 10:14:37204}
205
deepak.m139312672015-05-04 16:29:43206void BookmarkModel::Remove(const BookmarkNode* node) {
tfarina16f92ed42015-06-12 13:54:36207 DCHECK(loaded_);
deepak.m139312672015-05-04 16:29:43208 DCHECK(node);
tfarina16f92ed42015-06-12 13:54:36209 DCHECK(!is_root_node(node));
deepak.m139312672015-05-04 16:29:43210 RemoveAndDeleteNode(AsMutable(node));
[email protected]f25387b2008-08-21 15:20:33211}
212
[email protected]5cd942208a2014-06-11 06:16:46213void BookmarkModel::RemoveAllUserBookmarks() {
[email protected]9109f8a12013-06-12 18:07:48214 std::set<GURL> removed_urls;
jianli14436d52015-10-09 22:47:35215 struct RemoveNodeData {
jianli14436d52015-10-09 22:47:35216 const BookmarkNode* parent;
217 int index;
avicee78e4e2016-09-30 17:08:14218 std::unique_ptr<BookmarkNode> node;
jianli14436d52015-10-09 22:47:35219 };
220 std::vector<RemoveNodeData> removed_node_data_list;
[email protected]472f95e2013-06-10 16:49:18221
tfarina2fa1d2fb2016-10-19 01:44:31222 for (BookmarkModelObserver& observer : observers_)
223 observer.OnWillRemoveAllUserBookmarks(this);
[email protected]472f95e2013-06-10 16:49:18224
[email protected]323dbf72013-03-30 17:08:33225 BeginExtensiveChanges();
226 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and
227 // its immediate children. For removing all non permanent nodes just remove
228 // all children of non-root permanent nodes.
229 {
230 base::AutoLock url_lock(url_lock_);
231 for (int i = 0; i < root_.child_count(); ++i) {
jianli14436d52015-10-09 22:47:35232 const BookmarkNode* permanent_node = root_.GetChild(i);
[email protected]043a76d2014-06-05 16:36:24233
[email protected]23e39692014-06-06 21:10:13234 if (!client_->CanBeEditedByUser(permanent_node))
[email protected]043a76d2014-06-05 16:36:24235 continue;
236
[email protected]323dbf72013-03-30 17:08:33237 for (int j = permanent_node->child_count() - 1; j >= 0; --j) {
avicee78e4e2016-09-30 17:08:14238 std::unique_ptr<BookmarkNode> node = RemoveNodeAndGetRemovedUrls(
239 AsMutable(permanent_node->GetChild(j)), &removed_urls);
240 removed_node_data_list.push_back({permanent_node, j, std::move(node)});
[email protected]323dbf72013-03-30 17:08:33241 }
242 }
243 }
244 EndExtensiveChanges();
245 if (store_.get())
246 store_->ScheduleSave();
247
tfarina2fa1d2fb2016-10-19 01:44:31248 for (BookmarkModelObserver& observer : observers_)
249 observer.BookmarkAllUserNodesRemoved(this, removed_urls);
jianli14436d52015-10-09 22:47:35250
251 BeginGroupedChanges();
avicee78e4e2016-09-30 17:08:14252 for (auto& removed_node_data : removed_node_data_list) {
253 undo_delegate()->OnBookmarkNodeRemoved(this, removed_node_data.parent,
254 removed_node_data.index,
255 std::move(removed_node_data.node));
jianli14436d52015-10-09 22:47:35256 }
257 EndGroupedChanges();
[email protected]5cd942208a2014-06-11 06:16:46258}
259
[email protected]b3c33d462009-06-26 22:29:20260void BookmarkModel::Move(const BookmarkNode* node,
261 const BookmarkNode* new_parent,
[email protected]d8e41ed2008-09-11 15:22:32262 int index) {
[email protected]f25387b2008-08-21 15:20:33263 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
[email protected]6b4d64c2011-07-29 21:33:24264 is_root_node(new_parent) || is_permanent_node(node)) {
initial.commit09911bf2008-07-26 23:55:29265 NOTREACHED();
266 return;
267 }
268
269 if (new_parent->HasAncestor(node)) {
270 // Can't make an ancestor of the node be a child of the node.
271 NOTREACHED();
272 return;
273 }
274
[email protected]2d48ee842011-03-08 23:27:29275 const BookmarkNode* old_parent = node->parent();
[email protected]368f3a72011-03-08 17:17:48276 int old_index = old_parent->GetIndexOf(node);
initial.commit09911bf2008-07-26 23:55:29277
278 if (old_parent == new_parent &&
279 (index == old_index || index == old_index + 1)) {
280 // Node is already in this position, nothing to do.
281 return;
282 }
283
[email protected]9e583642012-12-05 02:48:32284 SetDateFolderModified(new_parent, Time::Now());
285
initial.commit09911bf2008-07-26 23:55:29286 if (old_parent == new_parent && index > old_index)
287 index--;
avicee78e4e2016-09-30 17:08:14288
289 BookmarkNode* mutable_old_parent = AsMutable(old_parent);
290 std::unique_ptr<BookmarkNode> owned_node =
291 mutable_old_parent->Remove(AsMutable(node));
[email protected]b3c33d462009-06-26 22:29:20292 BookmarkNode* mutable_new_parent = AsMutable(new_parent);
avicee78e4e2016-09-30 17:08:14293 mutable_new_parent->Add(std::move(owned_node), index);
initial.commit09911bf2008-07-26 23:55:29294
[email protected]f25387b2008-08-21 15:20:33295 if (store_.get())
296 store_->ScheduleSave();
297
tfarina2fa1d2fb2016-10-19 01:44:31298 for (BookmarkModelObserver& observer : observers_)
299 observer.BookmarkNodeMoved(this, old_parent, old_index, new_parent, index);
initial.commit09911bf2008-07-26 23:55:29300}
301
[email protected]4e187ef652010-03-11 05:21:35302void BookmarkModel::Copy(const BookmarkNode* node,
303 const BookmarkNode* new_parent,
304 int index) {
305 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
[email protected]6b4d64c2011-07-29 21:33:24306 is_root_node(new_parent) || is_permanent_node(node)) {
[email protected]4e187ef652010-03-11 05:21:35307 NOTREACHED();
308 return;
309 }
310
311 if (new_parent->HasAncestor(node)) {
312 // Can't make an ancestor of the node be a child of the node.
313 NOTREACHED();
314 return;
315 }
316
[email protected]c6a7a3d2011-03-12 01:04:30317 SetDateFolderModified(new_parent, Time::Now());
[email protected]67a8ae42013-05-20 09:42:39318 BookmarkNodeData drag_data(node);
[email protected]b1864502010-11-13 00:55:51319 // CloneBookmarkNode will use BookmarkModel methods to do the job, so we
[email protected]1a566fae2010-04-16 01:05:06320 // don't need to send notifications here.
tfarina8f3c40cc2015-01-20 21:22:50321 CloneBookmarkNode(this, drag_data.elements, new_parent, index, true);
[email protected]4e187ef652010-03-11 05:21:35322
323 if (store_.get())
324 store_->ScheduleSave();
[email protected]4e187ef652010-03-11 05:21:35325}
326
[email protected]6a4e5a02012-06-26 19:47:48327const gfx::Image& BookmarkModel::GetFavicon(const BookmarkNode* node) {
[email protected]ea2e5aa52009-05-20 18:01:28328 DCHECK(node);
[email protected]bcc38612012-10-23 01:10:27329 if (node->favicon_state() == BookmarkNode::INVALID_FAVICON) {
[email protected]b3c33d462009-06-26 22:29:20330 BookmarkNode* mutable_node = AsMutable(node);
tfarinac0baf0b2014-12-08 18:01:21331 LoadFavicon(mutable_node,
332 client_->PreferTouchIcon() ? favicon_base::TOUCH_ICON
333 : favicon_base::FAVICON);
[email protected]ea2e5aa52009-05-20 18:01:28334 }
335 return node->favicon();
336}
337
[email protected]504fca82014-05-07 22:48:08338favicon_base::IconType BookmarkModel::GetFaviconType(const BookmarkNode* node) {
339 DCHECK(node);
340 return node->favicon_type();
341}
342
[email protected]6a848b52014-04-26 22:06:54343void BookmarkModel::SetTitle(const BookmarkNode* node,
344 const base::string16& title) {
tfarina5ebd5362015-05-12 21:50:10345 DCHECK(node);
346
[email protected]0491ff72011-12-30 00:45:59347 if (node->GetTitle() == title)
initial.commit09911bf2008-07-26 23:55:29348 return;
[email protected]f25387b2008-08-21 15:20:33349
[email protected]043a76d2014-06-05 16:36:24350 if (is_permanent_node(node) && !client_->CanSetPermanentNodeTitle(node)) {
[email protected]baf4f922009-10-19 16:44:07351 NOTREACHED();
352 return;
353 }
354
tfarina2fa1d2fb2016-10-19 01:44:31355 for (BookmarkModelObserver& observer : observers_)
356 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18357
[email protected]85d911c2009-05-19 03:59:42358 // The title index doesn't support changing the title, instead we remove then
359 // add it back.
[email protected]01eec882009-05-22 18:13:28360 index_->Remove(node);
[email protected]0491ff72011-12-30 00:45:59361 AsMutable(node)->SetTitle(title);
[email protected]01eec882009-05-22 18:13:28362 index_->Add(node);
[email protected]85d911c2009-05-19 03:59:42363
[email protected]f25387b2008-08-21 15:20:33364 if (store_.get())
365 store_->ScheduleSave();
366
tfarina2fa1d2fb2016-10-19 01:44:31367 for (BookmarkModelObserver& observer : observers_)
368 observer.BookmarkNodeChanged(this, node);
initial.commit09911bf2008-07-26 23:55:29369}
370
[email protected]e5486602010-02-09 21:27:55371void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) {
tfarina5ebd5362015-05-12 21:50:10372 DCHECK(node && !node->is_folder());
[email protected]e5486602010-02-09 21:27:55373
[email protected]5d4077542011-07-21 20:24:07374 if (node->url() == url)
[email protected]e5486602010-02-09 21:27:55375 return;
376
[email protected]5b5c9b7f32011-07-21 01:07:18377 BookmarkNode* mutable_node = AsMutable(node);
378 mutable_node->InvalidateFavicon();
379 CancelPendingFaviconLoadRequests(mutable_node);
[email protected]e5486602010-02-09 21:27:55380
tfarina2fa1d2fb2016-10-19 01:44:31381 for (BookmarkModelObserver& observer : observers_)
382 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18383
[email protected]e5486602010-02-09 21:27:55384 {
[email protected]20305ec2011-01-21 04:55:52385 base::AutoLock url_lock(url_lock_);
danduongf4fde322014-11-04 18:56:56386 RemoveNodeFromInternalMaps(mutable_node);
[email protected]5d4077542011-07-21 20:24:07387 mutable_node->set_url(url);
danduongf4fde322014-11-04 18:56:56388 AddNodeToInternalMaps(mutable_node);
[email protected]e5486602010-02-09 21:27:55389 }
390
391 if (store_.get())
392 store_->ScheduleSave();
393
tfarina2fa1d2fb2016-10-19 01:44:31394 for (BookmarkModelObserver& observer : observers_)
395 observer.BookmarkNodeChanged(this, node);
[email protected]e5486602010-02-09 21:27:55396}
397
[email protected]1858410f2012-10-26 05:06:45398void BookmarkModel::SetNodeMetaInfo(const BookmarkNode* node,
399 const std::string& key,
400 const std::string& value) {
[email protected]39e113452013-11-26 00:43:06401 std::string old_value;
402 if (node->GetMetaInfo(key, &old_value) && old_value == value)
403 return;
404
tfarina2fa1d2fb2016-10-19 01:44:31405 for (BookmarkModelObserver& observer : observers_)
406 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40407
[email protected]1858410f2012-10-26 05:06:45408 if (AsMutable(node)->SetMetaInfo(key, value) && store_.get())
409 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40410
tfarina2fa1d2fb2016-10-19 01:44:31411 for (BookmarkModelObserver& observer : observers_)
412 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45413}
414
[email protected]e38a87d2013-12-05 01:35:18415void BookmarkModel::SetNodeMetaInfoMap(
416 const BookmarkNode* node,
417 const BookmarkNode::MetaInfoMap& meta_info_map) {
418 const BookmarkNode::MetaInfoMap* old_meta_info_map = node->GetMetaInfoMap();
419 if ((!old_meta_info_map && meta_info_map.empty()) ||
420 (old_meta_info_map && meta_info_map == *old_meta_info_map))
421 return;
422
tfarina2fa1d2fb2016-10-19 01:44:31423 for (BookmarkModelObserver& observer : observers_)
424 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]e38a87d2013-12-05 01:35:18425
426 AsMutable(node)->SetMetaInfoMap(meta_info_map);
427 if (store_.get())
428 store_->ScheduleSave();
429
tfarina2fa1d2fb2016-10-19 01:44:31430 for (BookmarkModelObserver& observer : observers_)
431 observer.BookmarkMetaInfoChanged(this, node);
[email protected]e38a87d2013-12-05 01:35:18432}
433
[email protected]1858410f2012-10-26 05:06:45434void BookmarkModel::DeleteNodeMetaInfo(const BookmarkNode* node,
435 const std::string& key) {
[email protected]39e113452013-11-26 00:43:06436 const BookmarkNode::MetaInfoMap* meta_info_map = node->GetMetaInfoMap();
437 if (!meta_info_map || meta_info_map->find(key) == meta_info_map->end())
438 return;
439
tfarina2fa1d2fb2016-10-19 01:44:31440 for (BookmarkModelObserver& observer : observers_)
441 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40442
[email protected]1858410f2012-10-26 05:06:45443 if (AsMutable(node)->DeleteMetaInfo(key) && store_.get())
444 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40445
tfarina2fa1d2fb2016-10-19 01:44:31446 for (BookmarkModelObserver& observer : observers_)
447 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45448}
449
rfevangd75d32212014-12-06 01:27:22450void BookmarkModel::AddNonClonedKey(const std::string& key) {
451 non_cloned_keys_.insert(key);
452}
453
[email protected]39e113452013-11-26 00:43:06454void BookmarkModel::SetNodeSyncTransactionVersion(
455 const BookmarkNode* node,
avibc5337b2015-12-25 23:16:33456 int64_t sync_transaction_version) {
[email protected]043a76d2014-06-05 16:36:24457 DCHECK(client_->CanSyncNode(node));
458
[email protected]39e113452013-11-26 00:43:06459 if (sync_transaction_version == node->sync_transaction_version())
460 return;
461
462 AsMutable(node)->set_sync_transaction_version(sync_transaction_version);
463 if (store_.get())
464 store_->ScheduleSave();
465}
466
pkotwiczca240dd2015-07-09 16:15:32467void BookmarkModel::OnFaviconsChanged(const std::set<GURL>& page_urls,
468 const GURL& icon_url) {
469 std::set<const BookmarkNode*> to_update;
470 for (const GURL& page_url : page_urls) {
[email protected]6a848b52014-04-26 22:06:54471 std::vector<const BookmarkNode*> nodes;
pkotwiczca240dd2015-07-09 16:15:32472 GetNodesByURL(page_url, &nodes);
473 to_update.insert(nodes.begin(), nodes.end());
474 }
475
476 if (!icon_url.is_empty()) {
477 // Log Histogram to determine how often |icon_url| is non empty in
478 // practice.
479 // TODO(pkotwicz): Do something more efficient if |icon_url| is non-empty
480 // many times a day for each user.
481 UMA_HISTOGRAM_BOOLEAN("Bookmarks.OnFaviconsChangedIconURL", true);
482
483 base::AutoLock url_lock(url_lock_);
484 for (const BookmarkNode* node : nodes_ordered_by_url_set_) {
ssid144fb7b82017-06-01 02:32:26485 if (node->icon_url() && icon_url == *node->icon_url())
pkotwiczca240dd2015-07-09 16:15:32486 to_update.insert(node);
[email protected]6a848b52014-04-26 22:06:54487 }
488 }
pkotwiczca240dd2015-07-09 16:15:32489
490 for (const BookmarkNode* node : to_update) {
491 // Rerequest the favicon.
492 BookmarkNode* mutable_node = AsMutable(node);
493 mutable_node->InvalidateFavicon();
494 CancelPendingFaviconLoadRequests(mutable_node);
tfarina2fa1d2fb2016-10-19 01:44:31495 for (BookmarkModelObserver& observer : observers_)
496 observer.BookmarkNodeFaviconChanged(this, node);
pkotwiczca240dd2015-07-09 16:15:32497 }
[email protected]6a848b52014-04-26 22:06:54498}
499
tfarina5ebd5362015-05-12 21:50:10500void BookmarkModel::SetDateAdded(const BookmarkNode* node, Time date_added) {
501 DCHECK(node && !is_permanent_node(node));
[email protected]b61445c2012-10-27 00:11:42502
503 if (node->date_added() == date_added)
504 return;
505
[email protected]b61445c2012-10-27 00:11:42506 AsMutable(node)->set_date_added(date_added);
507
508 // Syncing might result in dates newer than the folder's last modified date.
509 if (date_added > node->parent()->date_folder_modified()) {
510 // Will trigger store_->ScheduleSave().
511 SetDateFolderModified(node->parent(), date_added);
512 } else if (store_.get()) {
513 store_->ScheduleSave();
514 }
515}
516
[email protected]848cd05e2008-09-19 18:33:48517void BookmarkModel::GetNodesByURL(const GURL& url,
[email protected]b3c33d462009-06-26 22:29:20518 std::vector<const BookmarkNode*>* nodes) {
[email protected]20305ec2011-01-21 04:55:52519 base::AutoLock url_lock(url_lock_);
[email protected]ea2e5aa52009-05-20 18:01:28520 BookmarkNode tmp_node(url);
initial.commit09911bf2008-07-26 23:55:29521 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node);
[email protected]5d4077542011-07-21 20:24:07522 while (i != nodes_ordered_by_url_set_.end() && (*i)->url() == url) {
[email protected]848cd05e2008-09-19 18:33:48523 nodes->push_back(*i);
524 ++i;
525 }
526}
527
[email protected]23e39692014-06-06 21:10:13528const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL(
[email protected]b3c33d462009-06-26 22:29:20529 const GURL& url) {
530 std::vector<const BookmarkNode*> nodes;
[email protected]848cd05e2008-09-19 18:33:48531 GetNodesByURL(url, &nodes);
tfarinaa0ec34e2015-01-12 18:46:48532 std::sort(nodes.begin(), nodes.end(), &MoreRecentlyAdded);
[email protected]23e39692014-06-06 21:10:13533
534 // Look for the first node that the user can edit.
535 for (size_t i = 0; i < nodes.size(); ++i) {
536 if (client_->CanBeEditedByUser(nodes[i]))
537 return nodes[i];
538 }
539
540 return NULL;
initial.commit09911bf2008-07-26 23:55:29541}
542
[email protected]cf8e8172011-07-23 00:46:24543bool BookmarkModel::HasBookmarks() {
544 base::AutoLock url_lock(url_lock_);
545 return !nodes_ordered_by_url_set_.empty();
546}
547
Marti Wongc67da222017-09-01 02:30:01548bool BookmarkModel::HasNoUserCreatedBookmarksOrFolders() {
549 return bookmark_bar_node_->empty() && other_node_->empty() &&
550 mobile_node_->empty();
551}
552
[email protected]cf8e8172011-07-23 00:46:24553bool BookmarkModel::IsBookmarked(const GURL& url) {
554 base::AutoLock url_lock(url_lock_);
555 return IsBookmarkedNoLock(url);
556}
557
[email protected]0f7bee52012-08-06 20:04:17558void BookmarkModel::GetBookmarks(
[email protected]cef7931c2014-06-06 09:56:09559 std::vector<BookmarkModel::URLAndTitle>* bookmarks) {
[email protected]20305ec2011-01-21 04:55:52560 base::AutoLock url_lock(url_lock_);
[email protected]848cd05e2008-09-19 18:33:48561 const GURL* last_url = NULL;
[email protected]90ef13132008-08-27 03:27:46562 for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin();
563 i != nodes_ordered_by_url_set_.end(); ++i) {
[email protected]5d4077542011-07-21 20:24:07564 const GURL* url = &((*i)->url());
[email protected]848cd05e2008-09-19 18:33:48565 // Only add unique URLs.
[email protected]0f7bee52012-08-06 20:04:17566 if (!last_url || *url != *last_url) {
[email protected]cef7931c2014-06-06 09:56:09567 BookmarkModel::URLAndTitle bookmark;
[email protected]0f7bee52012-08-06 20:04:17568 bookmark.url = *url;
569 bookmark.title = (*i)->GetTitle();
570 bookmarks->push_back(bookmark);
571 }
[email protected]848cd05e2008-09-19 18:33:48572 last_url = url;
[email protected]90ef13132008-08-27 03:27:46573 }
574}
575
[email protected]cf8e8172011-07-23 00:46:24576void BookmarkModel::BlockTillLoaded() {
577 loaded_signal_.Wait();
[email protected]848cd05e2008-09-19 18:33:48578}
579
[email protected]39703292011-03-18 17:03:40580const BookmarkNode* BookmarkModel::AddFolder(const BookmarkNode* parent,
581 int index,
[email protected]96920152013-12-04 21:00:16582 const base::string16& title) {
[email protected]eb59ad12014-04-24 00:05:08583 return AddFolderWithMetaInfo(parent, index, title, NULL);
584}
585const BookmarkNode* BookmarkModel::AddFolderWithMetaInfo(
586 const BookmarkNode* parent,
587 int index,
588 const base::string16& title,
589 const BookmarkNode::MetaInfoMap* meta_info) {
[email protected]6b4d64c2011-07-29 21:33:24590 if (!loaded_ || is_root_node(parent) || !IsValidIndex(parent, index, true)) {
initial.commit09911bf2008-07-26 23:55:29591 // Can't add to the root.
592 NOTREACHED();
593 return NULL;
594 }
595
avicee78e4e2016-09-30 17:08:14596 std::unique_ptr<BookmarkNode> new_node =
597 base::MakeUnique<BookmarkNode>(generate_next_node_id(), GURL());
[email protected]edb63cc2011-03-11 02:00:41598 new_node->set_date_folder_modified(Time::Now());
[email protected]aee236542011-12-01 04:34:03599 // Folders shouldn't have line breaks in their titles.
[email protected]0491ff72011-12-30 00:45:59600 new_node->SetTitle(title);
[email protected]037db002009-10-19 20:06:08601 new_node->set_type(BookmarkNode::FOLDER);
[email protected]eb59ad12014-04-24 00:05:08602 if (meta_info)
603 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29604
avicee78e4e2016-09-30 17:08:14605 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29606}
607
[email protected]e64e9012010-01-11 23:10:55608const BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent,
609 int index,
[email protected]96920152013-12-04 21:00:16610 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55611 const GURL& url) {
[email protected]eb59ad12014-04-24 00:05:08612 return AddURLWithCreationTimeAndMetaInfo(
613 parent,
614 index,
ellyjones132ad412015-11-16 14:48:34615 title,
[email protected]eb59ad12014-04-24 00:05:08616 url,
617 Time::Now(),
618 NULL);
initial.commit09911bf2008-07-26 23:55:29619}
620
[email protected]eb59ad12014-04-24 00:05:08621const BookmarkNode* BookmarkModel::AddURLWithCreationTimeAndMetaInfo(
[email protected]e64e9012010-01-11 23:10:55622 const BookmarkNode* parent,
623 int index,
[email protected]96920152013-12-04 21:00:16624 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55625 const GURL& url,
[email protected]eb59ad12014-04-24 00:05:08626 const Time& creation_time,
627 const BookmarkNode::MetaInfoMap* meta_info) {
[email protected]6b4d64c2011-07-29 21:33:24628 if (!loaded_ || !url.is_valid() || is_root_node(parent) ||
[email protected]f25387b2008-08-21 15:20:33629 !IsValidIndex(parent, index, true)) {
initial.commit09911bf2008-07-26 23:55:29630 NOTREACHED();
631 return NULL;
632 }
initial.commit09911bf2008-07-26 23:55:29633
[email protected]b61445c2012-10-27 00:11:42634 // Syncing may result in dates newer than the last modified date.
[email protected]8ad613b2012-10-12 21:28:45635 if (creation_time > parent->date_folder_modified())
636 SetDateFolderModified(parent, creation_time);
initial.commit09911bf2008-07-26 23:55:29637
avicee78e4e2016-09-30 17:08:14638 std::unique_ptr<BookmarkNode> new_node =
639 base::MakeUnique<BookmarkNode>(generate_next_node_id(), url);
[email protected]0491ff72011-12-30 00:45:59640 new_node->SetTitle(title);
[email protected]b3c33d462009-06-26 22:29:20641 new_node->set_date_added(creation_time);
[email protected]037db002009-10-19 20:06:08642 new_node->set_type(BookmarkNode::URL);
[email protected]eb59ad12014-04-24 00:05:08643 if (meta_info)
644 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29645
avicee78e4e2016-09-30 17:08:14646 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29647}
648
[email protected]b3c33d462009-06-26 22:29:20649void BookmarkModel::SortChildren(const BookmarkNode* parent) {
[email protected]23e39692014-06-06 21:10:13650 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24651
[email protected]6b4d64c2011-07-29 21:33:24652 if (!parent || !parent->is_folder() || is_root_node(parent) ||
[email protected]9c1a75a2011-03-10 02:38:12653 parent->child_count() <= 1) {
[email protected]e2f86d92009-02-25 00:22:01654 return;
655 }
656
tfarina2fa1d2fb2016-10-19 01:44:31657 for (BookmarkModelObserver& observer : observers_)
658 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18659
[email protected]ef762642009-03-05 16:30:25660 UErrorCode error = U_ZERO_ERROR;
dchengacd3f522016-04-21 22:30:41661 std::unique_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
[email protected]ef762642009-03-05 16:30:25662 if (U_FAILURE(error))
663 collator.reset(NULL);
[email protected]b3c33d462009-06-26 22:29:20664 BookmarkNode* mutable_parent = AsMutable(parent);
665 std::sort(mutable_parent->children().begin(),
666 mutable_parent->children().end(),
[email protected]ef762642009-03-05 16:30:25667 SortComparator(collator.get()));
[email protected]e2f86d92009-02-25 00:22:01668
[email protected]997a0362009-03-12 03:10:51669 if (store_.get())
670 store_->ScheduleSave();
671
tfarina2fa1d2fb2016-10-19 01:44:31672 for (BookmarkModelObserver& observer : observers_)
673 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]e2f86d92009-02-25 00:22:01674}
675
[email protected]472f95e2013-06-10 16:49:18676void BookmarkModel::ReorderChildren(
677 const BookmarkNode* parent,
[email protected]257d5082013-08-06 07:46:43678 const std::vector<const BookmarkNode*>& ordered_nodes) {
[email protected]23e39692014-06-06 21:10:13679 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24680
[email protected]472f95e2013-06-10 16:49:18681 // Ensure that all children in |parent| are in |ordered_nodes|.
682 DCHECK_EQ(static_cast<size_t>(parent->child_count()), ordered_nodes.size());
avicee78e4e2016-09-30 17:08:14683 for (const BookmarkNode* node : ordered_nodes)
684 DCHECK_EQ(parent, node->parent());
[email protected]472f95e2013-06-10 16:49:18685
tfarina2fa1d2fb2016-10-19 01:44:31686 for (BookmarkModelObserver& observer : observers_)
687 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18688
avicee78e4e2016-09-30 17:08:14689 if (ordered_nodes.size() > 1) {
690 std::map<const BookmarkNode*, int> order;
691 for (size_t i = 0; i < ordered_nodes.size(); ++i)
692 order[ordered_nodes[i]] = i;
[email protected]472f95e2013-06-10 16:49:18693
avicee78e4e2016-09-30 17:08:14694 std::vector<std::unique_ptr<BookmarkNode>> new_children(
695 ordered_nodes.size());
696 BookmarkNode* mutable_parent = AsMutable(parent);
697 for (auto& child : mutable_parent->children()) {
698 size_t new_location = order[child.get()];
699 new_children[new_location] = std::move(child);
700 }
701 mutable_parent->children().swap(new_children);
702
703 if (store_.get())
704 store_->ScheduleSave();
705 }
[email protected]472f95e2013-06-10 16:49:18706
tfarina2fa1d2fb2016-10-19 01:44:31707 for (BookmarkModelObserver& observer : observers_)
708 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]472f95e2013-06-10 16:49:18709}
710
[email protected]c6a7a3d2011-03-12 01:04:30711void BookmarkModel::SetDateFolderModified(const BookmarkNode* parent,
712 const Time time) {
[email protected]eea8fd5532009-12-16 00:08:10713 DCHECK(parent);
[email protected]edb63cc2011-03-11 02:00:41714 AsMutable(parent)->set_date_folder_modified(time);
[email protected]eea8fd5532009-12-16 00:08:10715
716 if (store_.get())
717 store_->ScheduleSave();
718}
719
[email protected]c6a7a3d2011-03-12 01:04:30720void BookmarkModel::ResetDateFolderModified(const BookmarkNode* node) {
721 SetDateFolderModified(node, Time());
initial.commit09911bf2008-07-26 23:55:29722}
723
kkimlabsf1a7a3732014-11-04 10:30:46724void BookmarkModel::GetBookmarksMatching(const base::string16& text,
725 size_t max_count,
mattreynolds25e9a312016-12-14 21:52:13726 std::vector<TitledUrlMatch>* matches) {
kkimlabsf1a7a3732014-11-04 10:30:46727 GetBookmarksMatching(text, max_count,
728 query_parser::MatchingAlgorithm::DEFAULT, matches);
729}
730
[email protected]b3a84892014-04-23 04:28:07731void BookmarkModel::GetBookmarksMatching(
[email protected]96920152013-12-04 21:00:16732 const base::string16& text,
[email protected]e64e9012010-01-11 23:10:55733 size_t max_count,
kkimlabsf1a7a3732014-11-04 10:30:46734 query_parser::MatchingAlgorithm matching_algorithm,
mattreynolds25e9a312016-12-14 21:52:13735 std::vector<TitledUrlMatch>* matches) {
[email protected]01eec882009-05-22 18:13:28736 if (!loaded_)
737 return;
738
mattreynolds55324d62016-12-09 23:07:29739 index_->GetResultsMatching(text, max_count, matching_algorithm, matches);
[email protected]85d911c2009-05-19 03:59:42740}
741
[email protected]9876bb1c2008-12-16 20:42:25742void BookmarkModel::ClearStore() {
[email protected]265e88e2014-07-07 20:45:19743 store_.reset();
[email protected]9876bb1c2008-12-16 20:42:25744}
745
[email protected]bc770a032011-12-12 17:35:30746void BookmarkModel::SetPermanentNodeVisible(BookmarkNode::Type type,
747 bool value) {
[email protected]043a76d2014-06-05 16:36:24748 BookmarkPermanentNode* node = AsMutable(PermanentNode(type));
749 node->set_visible(value || client_->IsPermanentNodeVisible(node));
[email protected]996dbe82014-05-12 12:32:18750}
751
752const BookmarkPermanentNode* BookmarkModel::PermanentNode(
753 BookmarkNode::Type type) {
[email protected]1da5f712011-12-06 05:52:26754 DCHECK(loaded_);
[email protected]bc770a032011-12-12 17:35:30755 switch (type) {
756 case BookmarkNode::BOOKMARK_BAR:
[email protected]996dbe82014-05-12 12:32:18757 return bookmark_bar_node_;
[email protected]bc770a032011-12-12 17:35:30758 case BookmarkNode::OTHER_NODE:
[email protected]996dbe82014-05-12 12:32:18759 return other_node_;
[email protected]bc770a032011-12-12 17:35:30760 case BookmarkNode::MOBILE:
[email protected]996dbe82014-05-12 12:32:18761 return mobile_node_;
[email protected]bc770a032011-12-12 17:35:30762 default:
763 NOTREACHED();
[email protected]996dbe82014-05-12 12:32:18764 return NULL;
[email protected]bc770a032011-12-12 17:35:30765 }
[email protected]1da5f712011-12-06 05:52:26766}
767
avicee78e4e2016-09-30 17:08:14768void BookmarkModel::RestoreRemovedNode(const BookmarkNode* parent,
769 int index,
770 std::unique_ptr<BookmarkNode> node) {
771 BookmarkNode* node_ptr = node.get();
772 AddNode(AsMutable(parent), index, std::move(node));
jianli14436d52015-10-09 22:47:35773
774 // We might be restoring a folder node that have already contained a set of
775 // child nodes. We need to notify all of them.
avicee78e4e2016-09-30 17:08:14776 NotifyNodeAddedForAllDescendents(node_ptr);
jianli14436d52015-10-09 22:47:35777}
778
779void BookmarkModel::NotifyNodeAddedForAllDescendents(const BookmarkNode* node) {
780 for (int i = 0; i < node->child_count(); ++i) {
tfarina2fa1d2fb2016-10-19 01:44:31781 for (BookmarkModelObserver& observer : observers_)
782 observer.BookmarkNodeAdded(this, node, i);
jianli14436d52015-10-09 22:47:35783 NotifyNodeAddedForAllDescendents(node->GetChild(i));
784 }
785}
786
[email protected]dddc1b42008-10-09 20:56:59787bool BookmarkModel::IsBookmarkedNoLock(const GURL& url) {
[email protected]ea2e5aa52009-05-20 18:01:28788 BookmarkNode tmp_node(url);
[email protected]dddc1b42008-10-09 20:56:59789 return (nodes_ordered_by_url_set_.find(&tmp_node) !=
790 nodes_ordered_by_url_set_.end());
791}
792
[email protected]d8e41ed2008-09-11 15:22:32793void BookmarkModel::RemoveNode(BookmarkNode* node,
794 std::set<GURL>* removed_urls) {
[email protected]b3c33d462009-06-26 22:29:20795 if (!loaded_ || !node || is_permanent_node(node)) {
[email protected]f25387b2008-08-21 15:20:33796 NOTREACHED();
797 return;
798 }
799
[email protected]323dbf72013-03-30 17:08:33800 url_lock_.AssertAcquired();
[email protected]0890e60e2011-06-27 14:55:21801 if (node->is_url()) {
danduongf4fde322014-11-04 18:56:56802 RemoveNodeFromInternalMaps(node);
[email protected]5d4077542011-07-21 20:24:07803 removed_urls->insert(node->url());
initial.commit09911bf2008-07-26 23:55:29804 }
805
[email protected]abc2f262011-03-15 21:15:44806 CancelPendingFaviconLoadRequests(node);
initial.commit09911bf2008-07-26 23:55:29807
808 // Recurse through children.
[email protected]9c1a75a2011-03-10 02:38:12809 for (int i = node->child_count() - 1; i >= 0; --i)
[email protected]f25387b2008-08-21 15:20:33810 RemoveNode(node->GetChild(i), removed_urls);
initial.commit09911bf2008-07-26 23:55:29811}
812
dchengacd3f522016-04-21 22:30:41813void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
[email protected]6a848b52014-04-26 22:06:54814 DCHECK(details);
[email protected]01eec882009-05-22 18:13:28815 if (loaded_) {
816 // We should only ever be loaded once.
817 NOTREACHED();
818 return;
819 }
820
robliaoad0efe962015-03-14 00:13:02821 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/467179
822 // is fixed.
823 tracked_objects::ScopedTracker tracking_profile1(
824 FROM_HERE_WITH_EXPLICIT_FUNCTION("467179 BookmarkModel::DoneLoading1"));
825
[email protected]01eec882009-05-22 18:13:28826 next_node_id_ = details->max_id();
[email protected]367d7072009-07-13 23:27:13827 if (details->computed_checksum() != details->stored_checksum() ||
828 details->ids_reassigned()) {
robliaoad0efe962015-03-14 00:13:02829 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/467179
830 // is fixed.
831 tracked_objects::ScopedTracker tracking_profile2(
832 FROM_HERE_WITH_EXPLICIT_FUNCTION("467179 BookmarkModel::DoneLoading2"));
833
[email protected]367d7072009-07-13 23:27:13834 // If bookmarks file changed externally, the IDs may have changed
835 // externally. In that case, the decoder may have reassigned IDs to make
836 // them unique. So when the file has changed externally, we should save the
837 // bookmarks file to persist new IDs.
838 if (store_.get())
839 store_->ScheduleSave();
840 }
avicee78e4e2016-09-30 17:08:14841 std::unique_ptr<BookmarkPermanentNode> owned_bb_node =
842 details->owned_bb_node();
843 std::unique_ptr<BookmarkPermanentNode> owned_other_folder_node =
844 details->owned_other_folder_node();
845 std::unique_ptr<BookmarkPermanentNode> owned_mobile_folder_node =
846 details->owned_mobile_folder_node();
847 index_ = details->owned_index();
848
849 bookmark_bar_node_ = owned_bb_node.get();
850 other_node_ = owned_other_folder_node.get();
851 mobile_node_ = owned_mobile_folder_node.get();
[email protected]01eec882009-05-22 18:13:28852
[email protected]043a76d2014-06-05 16:36:24853 // Get any extra nodes and take ownership of them at the |root_|.
avicee78e4e2016-09-30 17:08:14854 std::vector<std::unique_ptr<BookmarkPermanentNode>> extra_nodes =
855 details->owned_extra_nodes();
[email protected]043a76d2014-06-05 16:36:24856
robliaoad0efe962015-03-14 00:13:02857 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/467179
858 // is fixed.
859 tracked_objects::ScopedTracker tracking_profile3(
860 FROM_HERE_WITH_EXPLICIT_FUNCTION("467179 BookmarkModel::DoneLoading3"));
861
[email protected]82f4655a2011-10-18 13:05:43862 // WARNING: order is important here, various places assume the order is
[email protected]996dbe82014-05-12 12:32:18863 // constant (but can vary between embedders with the initial visibility
864 // of permanent nodes).
avicee78e4e2016-09-30 17:08:14865 std::vector<std::unique_ptr<BookmarkPermanentNode>> root_children;
866 root_children.push_back(std::move(owned_bb_node));
867 root_children.push_back(std::move(owned_other_folder_node));
868 root_children.push_back(std::move(owned_mobile_folder_node));
869 std::move(extra_nodes.begin(), extra_nodes.end(),
870 std::back_inserter(root_children));
robliaoad0efe962015-03-14 00:13:02871
872 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/467179
873 // is fixed.
874 tracked_objects::ScopedTracker tracking_profile4(
875 FROM_HERE_WITH_EXPLICIT_FUNCTION("467179 BookmarkModel::DoneLoading4"));
876
[email protected]043a76d2014-06-05 16:36:24877 std::stable_sort(root_children.begin(),
878 root_children.end(),
sdefresne070a5102016-02-01 13:42:14879 VisibilityComparator(client_.get()));
[email protected]043a76d2014-06-05 16:36:24880 for (size_t i = 0; i < root_children.size(); ++i)
avicee78e4e2016-09-30 17:08:14881 root_.Add(std::move(root_children[i]), static_cast<int>(i));
[email protected]6c1164042009-05-08 14:41:08882
[email protected]39e113452013-11-26 00:43:06883 root_.SetMetaInfoMap(details->model_meta_info_map());
884 root_.set_sync_transaction_version(details->model_sync_transaction_version());
[email protected]1858410f2012-10-26 05:06:45885
robliaoad0efe962015-03-14 00:13:02886 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/467179
887 // is fixed.
888 tracked_objects::ScopedTracker tracking_profile5(
889 FROM_HERE_WITH_EXPLICIT_FUNCTION("467179 BookmarkModel::DoneLoading5"));
890
[email protected]90ef13132008-08-27 03:27:46891 {
[email protected]20305ec2011-01-21 04:55:52892 base::AutoLock url_lock(url_lock_);
[email protected]90ef13132008-08-27 03:27:46893 // Update nodes_ordered_by_url_set_ from the nodes.
894 PopulateNodesByURL(&root_);
895 }
[email protected]f25387b2008-08-21 15:20:33896
initial.commit09911bf2008-07-26 23:55:29897 loaded_ = true;
898
[email protected]cbcd6412009-03-09 22:31:39899 loaded_signal_.Signal();
[email protected]90ef13132008-08-27 03:27:46900
robliaoad0efe962015-03-14 00:13:02901 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/467179
902 // is fixed.
903 tracked_objects::ScopedTracker tracking_profile6(
904 FROM_HERE_WITH_EXPLICIT_FUNCTION("467179 BookmarkModel::DoneLoading6"));
905
[email protected]f25387b2008-08-21 15:20:33906 // Notify our direct observers.
tfarina2fa1d2fb2016-10-19 01:44:31907 for (BookmarkModelObserver& observer : observers_)
908 observer.BookmarkModelLoaded(this, details->ids_reassigned());
initial.commit09911bf2008-07-26 23:55:29909}
910
avicee78e4e2016-09-30 17:08:14911void BookmarkModel::RemoveAndDeleteNode(BookmarkNode* node_ptr) {
912 std::unique_ptr<BookmarkNode> node;
initial.commit09911bf2008-07-26 23:55:29913
avicee78e4e2016-09-30 17:08:14914 const BookmarkNode* parent = node_ptr->parent();
initial.commit09911bf2008-07-26 23:55:29915 DCHECK(parent);
avicee78e4e2016-09-30 17:08:14916 int index = parent->GetIndexOf(node_ptr);
deepak.m139312672015-05-04 16:29:43917 DCHECK_NE(-1, index);
[email protected]323dbf72013-03-30 17:08:33918
tfarina2fa1d2fb2016-10-19 01:44:31919 for (BookmarkModelObserver& observer : observers_)
920 observer.OnWillRemoveBookmarks(this, parent, index, node_ptr);
[email protected]472f95e2013-06-10 16:49:18921
[email protected]9109f8a12013-06-12 18:07:48922 std::set<GURL> removed_urls;
[email protected]90ef13132008-08-27 03:27:46923 {
[email protected]20305ec2011-01-21 04:55:52924 base::AutoLock url_lock(url_lock_);
avicee78e4e2016-09-30 17:08:14925 node = RemoveNodeAndGetRemovedUrls(node_ptr, &removed_urls);
[email protected]90ef13132008-08-27 03:27:46926 }
initial.commit09911bf2008-07-26 23:55:29927
[email protected]f25387b2008-08-21 15:20:33928 if (store_.get())
929 store_->ScheduleSave();
930
tfarina2fa1d2fb2016-10-19 01:44:31931 for (BookmarkModelObserver& observer : observers_)
932 observer.BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls);
jianli14436d52015-10-09 22:47:35933
dcheng51606352015-12-26 21:16:23934 undo_delegate()->OnBookmarkNodeRemoved(this, parent, index, std::move(node));
[email protected]323dbf72013-03-30 17:08:33935}
[email protected]f25387b2008-08-21 15:20:33936
danduongf4fde322014-11-04 18:56:56937void BookmarkModel::RemoveNodeFromInternalMaps(BookmarkNode* node) {
938 index_->Remove(node);
[email protected]5db00bca2013-12-23 00:43:09939 // NOTE: this is called in such a way that url_lock_ is already held. As
940 // such, this doesn't explicitly grab the lock.
danduongf4fde322014-11-04 18:56:56941 url_lock_.AssertAcquired();
[email protected]5db00bca2013-12-23 00:43:09942 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node);
943 DCHECK(i != nodes_ordered_by_url_set_.end());
944 // i points to the first node with the URL, advance until we find the
945 // node we're removing.
946 while (*i != node)
947 ++i;
948 nodes_ordered_by_url_set_.erase(i);
949}
950
avicee78e4e2016-09-30 17:08:14951std::unique_ptr<BookmarkNode> BookmarkModel::RemoveNodeAndGetRemovedUrls(
952 BookmarkNode* node_ptr,
953 std::set<GURL>* removed_urls) {
[email protected]323dbf72013-03-30 17:08:33954 // NOTE: this method should be always called with |url_lock_| held.
955 // This method does not explicitly acquires a lock.
956 url_lock_.AssertAcquired();
957 DCHECK(removed_urls);
avicee78e4e2016-09-30 17:08:14958 BookmarkNode* parent = node_ptr->parent();
[email protected]323dbf72013-03-30 17:08:33959 DCHECK(parent);
avicee78e4e2016-09-30 17:08:14960 std::unique_ptr<BookmarkNode> node = parent->Remove(node_ptr);
961 RemoveNode(node_ptr, removed_urls);
[email protected]323dbf72013-03-30 17:08:33962 // RemoveNode adds an entry to removed_urls for each node of type URL. As we
963 // allow duplicates we need to remove any entries that are still bookmarked.
964 for (std::set<GURL>::iterator i = removed_urls->begin();
965 i != removed_urls->end();) {
966 if (IsBookmarkedNoLock(*i)) {
967 // When we erase the iterator pointing at the erasee is
968 // invalidated, so using i++ here within the "erase" call is
969 // important as it advances the iterator before passing the
970 // old value through to erase.
971 removed_urls->erase(i++);
972 } else {
973 ++i;
974 }
975 }
avicee78e4e2016-09-30 17:08:14976
977 return node;
[email protected]323dbf72013-03-30 17:08:33978}
979
[email protected]d8e41ed2008-09-11 15:22:32980BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
981 int index,
avicee78e4e2016-09-30 17:08:14982 std::unique_ptr<BookmarkNode> node) {
983 BookmarkNode* node_ptr = node.get();
984 parent->Add(std::move(node), index);
initial.commit09911bf2008-07-26 23:55:29985
[email protected]f25387b2008-08-21 15:20:33986 if (store_.get())
987 store_->ScheduleSave();
988
jianli14436d52015-10-09 22:47:35989 {
danduongf4fde322014-11-04 18:56:56990 base::AutoLock url_lock(url_lock_);
avicee78e4e2016-09-30 17:08:14991 AddNodeToInternalMaps(node_ptr);
danduongf4fde322014-11-04 18:56:56992 }
993
tfarina2fa1d2fb2016-10-19 01:44:31994 for (BookmarkModelObserver& observer : observers_)
995 observer.BookmarkNodeAdded(this, parent, index);
[email protected]f25387b2008-08-21 15:20:33996
avicee78e4e2016-09-30 17:08:14997 return node_ptr;
initial.commit09911bf2008-07-26 23:55:29998}
999
danduongf4fde322014-11-04 18:56:561000void BookmarkModel::AddNodeToInternalMaps(BookmarkNode* node) {
danduongf4fde322014-11-04 18:56:561001 url_lock_.AssertAcquired();
jianli14436d52015-10-09 22:47:351002 if (node->is_url()) {
1003 index_->Add(node);
1004 nodes_ordered_by_url_set_.insert(node);
1005 }
1006 for (int i = 0; i < node->child_count(); ++i)
1007 AddNodeToInternalMaps(node->GetChild(i));
danduongf4fde322014-11-04 18:56:561008}
1009
[email protected]b3c33d462009-06-26 22:29:201010bool BookmarkModel::IsValidIndex(const BookmarkNode* parent,
[email protected]d8e41ed2008-09-11 15:22:321011 int index,
1012 bool allow_end) {
[email protected]776e7492008-10-23 16:47:411013 return (parent && parent->is_folder() &&
[email protected]9c1a75a2011-03-10 02:38:121014 (index >= 0 && (index < parent->child_count() ||
1015 (allow_end && index == parent->child_count()))));
[email protected]bd1b96702009-07-08 21:54:141016}
[email protected]f25387b2008-08-21 15:20:331017
[email protected]bc770a032011-12-12 17:35:301018BookmarkPermanentNode* BookmarkModel::CreatePermanentNode(
1019 BookmarkNode::Type type) {
[email protected]e1f76c62011-06-30 20:15:391020 DCHECK(type == BookmarkNode::BOOKMARK_BAR ||
1021 type == BookmarkNode::OTHER_NODE ||
[email protected]37bc9132011-12-01 22:29:291022 type == BookmarkNode::MOBILE);
[email protected]bc770a032011-12-12 17:35:301023 BookmarkPermanentNode* node =
1024 new BookmarkPermanentNode(generate_next_node_id());
[email protected]043a76d2014-06-05 16:36:241025 node->set_type(type);
1026 node->set_visible(client_->IsPermanentNodeVisible(node));
[email protected]bc770a032011-12-12 17:35:301027
1028 int title_id;
1029 switch (type) {
1030 case BookmarkNode::BOOKMARK_BAR:
1031 title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
1032 break;
1033 case BookmarkNode::OTHER_NODE:
1034 title_id = IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME;
1035 break;
1036 case BookmarkNode::MOBILE:
1037 title_id = IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME;
1038 break;
1039 default:
[email protected]97fdd162011-12-03 20:50:121040 NOTREACHED();
[email protected]bc770a032011-12-12 17:35:301041 title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
1042 break;
[email protected]7caca8a22010-08-21 18:25:311043 }
[email protected]0491ff72011-12-30 00:45:591044 node->SetTitle(l10n_util::GetStringUTF16(title_id));
initial.commit09911bf2008-07-26 23:55:291045 return node;
1046}
1047
[email protected]abc2f262011-03-15 21:15:441048void BookmarkModel::OnFaviconDataAvailable(
[email protected]0ea3db52012-12-07 01:32:011049 BookmarkNode* node,
[email protected]504fca82014-05-07 22:48:081050 favicon_base::IconType icon_type,
[email protected]7627e0b42014-04-17 17:20:531051 const favicon_base::FaviconImageResult& image_result) {
[email protected]4167c3a2008-08-21 18:12:201052 DCHECK(node);
[email protected]e95b717f2014-02-06 13:47:131053 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
[email protected]bcc38612012-10-23 01:10:271054 node->set_favicon_state(BookmarkNode::LOADED_FAVICON);
[email protected]65baa222012-08-30 15:43:511055 if (!image_result.image.IsEmpty()) {
[email protected]504fca82014-05-07 22:48:081056 node->set_favicon_type(icon_type);
[email protected]65baa222012-08-30 15:43:511057 node->set_favicon(image_result.image);
[email protected]2ad0e872012-11-30 01:24:461058 node->set_icon_url(image_result.icon_url);
[email protected]65baa222012-08-30 15:43:511059 FaviconLoaded(node);
[email protected]504fca82014-05-07 22:48:081060 } else if (icon_type == favicon_base::TOUCH_ICON) {
1061 // Couldn't load the touch icon, fallback to the regular favicon.
1062 DCHECK(client_->PreferTouchIcon());
1063 LoadFavicon(node, favicon_base::FAVICON);
initial.commit09911bf2008-07-26 23:55:291064 }
1065}
1066
tfarinac0baf0b2014-12-08 18:01:211067void BookmarkModel::LoadFavicon(BookmarkNode* node,
1068 favicon_base::IconType icon_type) {
[email protected]0890e60e2011-06-27 14:55:211069 if (node->is_folder())
initial.commit09911bf2008-07-26 23:55:291070 return;
1071
[email protected]5d4077542011-07-21 20:24:071072 DCHECK(node->url().is_valid());
[email protected]504fca82014-05-07 22:48:081073 node->set_favicon_state(BookmarkNode::LOADING_FAVICON);
[email protected]25244a932014-07-12 23:00:241074 base::CancelableTaskTracker::TaskId taskId =
1075 client_->GetFaviconImageForPageURL(
1076 node->url(),
1077 icon_type,
1078 base::Bind(
1079 &BookmarkModel::OnFaviconDataAvailable,
1080 base::Unretained(this),
1081 node,
1082 icon_type),
1083 &cancelable_task_tracker_);
[email protected]6a848b52014-04-26 22:06:541084 if (taskId != base::CancelableTaskTracker::kBadTaskId)
1085 node->set_favicon_load_task_id(taskId);
initial.commit09911bf2008-07-26 23:55:291086}
1087
[email protected]5b5c9b7f32011-07-21 01:07:181088void BookmarkModel::FaviconLoaded(const BookmarkNode* node) {
tfarina2fa1d2fb2016-10-19 01:44:311089 for (BookmarkModelObserver& observer : observers_)
1090 observer.BookmarkNodeFaviconChanged(this, node);
[email protected]5b5c9b7f32011-07-21 01:07:181091}
1092
[email protected]abc2f262011-03-15 21:15:441093void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) {
[email protected]e95b717f2014-02-06 13:47:131094 if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) {
[email protected]0ea3db52012-12-07 01:32:011095 cancelable_task_tracker_.TryCancel(node->favicon_load_task_id());
[email protected]e95b717f2014-02-06 13:47:131096 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
initial.commit09911bf2008-07-26 23:55:291097 }
1098}
1099
[email protected]d8e41ed2008-09-11 15:22:321100void BookmarkModel::PopulateNodesByURL(BookmarkNode* node) {
[email protected]90ef13132008-08-27 03:27:461101 // NOTE: this is called with url_lock_ already held. As such, this doesn't
1102 // explicitly grab the lock.
[email protected]f25387b2008-08-21 15:20:331103 if (node->is_url())
1104 nodes_ordered_by_url_set_.insert(node);
[email protected]9c1a75a2011-03-10 02:38:121105 for (int i = 0; i < node->child_count(); ++i)
[email protected]f25387b2008-08-21 15:20:331106 PopulateNodesByURL(node->GetChild(i));
1107}
[email protected]4d89f382009-05-12 06:56:491108
avibc5337b2015-12-25 23:16:331109int64_t BookmarkModel::generate_next_node_id() {
[email protected]4d89f382009-05-12 06:56:491110 return next_node_id_++;
1111}
[email protected]01eec882009-05-22 18:13:281112
dchengacd3f522016-04-21 22:30:411113std::unique_ptr<BookmarkLoadDetails> BookmarkModel::CreateLoadDetails() {
[email protected]bc770a032011-12-12 17:35:301114 BookmarkPermanentNode* bb_node =
1115 CreatePermanentNode(BookmarkNode::BOOKMARK_BAR);
1116 BookmarkPermanentNode* other_node =
1117 CreatePermanentNode(BookmarkNode::OTHER_NODE);
1118 BookmarkPermanentNode* mobile_node =
1119 CreatePermanentNode(BookmarkNode::MOBILE);
mattreynolds191b88722016-12-13 19:25:321120 std::unique_ptr<TitledUrlNodeSorter> node_sorter =
1121 base::MakeUnique<TypedCountSorter>(client_.get());
dchengacd3f522016-04-21 22:30:411122 return std::unique_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails(
1123 bb_node, other_node, mobile_node, client_->GetLoadExtraNodesCallback(),
mattreynolds25e9a312016-12-14 21:52:131124 new TitledUrlIndex(std::move(node_sorter)), next_node_id_));
[email protected]01eec882009-05-22 18:13:281125}
tfarinaa0ec34e2015-01-12 18:46:481126
jianli14436d52015-10-09 22:47:351127void BookmarkModel::SetUndoDelegate(BookmarkUndoDelegate* undo_delegate) {
1128 undo_delegate_ = undo_delegate;
1129 if (undo_delegate_)
1130 undo_delegate_->SetUndoProvider(this);
1131}
1132
1133BookmarkUndoDelegate* BookmarkModel::undo_delegate() const {
1134 return undo_delegate_ ? undo_delegate_ : empty_undo_delegate_.get();
1135}
1136
tfarinaa0ec34e2015-01-12 18:46:481137} // namespace bookmarks