blob: d3498d706cd383e27bebab21984e0480a83aa6d4 [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"
[email protected]6a848b52014-04-26 22:06:5418#include "base/strings/string_util.h"
[email protected]a90c8ca2014-05-20 17:16:0419#include "components/bookmarks/browser/bookmark_expanded_state_tracker.h"
[email protected]a90c8ca2014-05-20 17:16:0420#include "components/bookmarks/browser/bookmark_model_observer.h"
21#include "components/bookmarks/browser/bookmark_node_data.h"
22#include "components/bookmarks/browser/bookmark_storage.h"
jianli14436d52015-10-09 22:47:3523#include "components/bookmarks/browser/bookmark_undo_delegate.h"
[email protected]a90c8ca2014-05-20 17:16:0424#include "components/bookmarks/browser/bookmark_utils.h"
mattreynolds25e9a312016-12-14 21:52:1325#include "components/bookmarks/browser/titled_url_index.h"
26#include "components/bookmarks/browser/titled_url_match.h"
mattreynolds191b88722016-12-13 19:25:3227#include "components/bookmarks/browser/typed_count_sorter.h"
[email protected]7627e0b42014-04-17 17:20:5328#include "components/favicon_base/favicon_types.h"
thakisfe8fa0a2017-02-23 19:46:3629#include "components/strings/grit/components_strings.h"
[email protected]c051a1b2011-01-21 23:30:1730#include "ui/base/l10n/l10n_util.h"
[email protected]65baa222012-08-30 15:43:5131#include "ui/gfx/favicon_size.h"
initial.commit09911bf2008-07-26 23:55:2932
[email protected]e1acf6f2008-10-27 20:43:3333using base::Time;
tfarinaa0ec34e2015-01-12 18:46:4834
35namespace bookmarks {
[email protected]e1acf6f2008-10-27 20:43:3336
[email protected]b3c33d462009-06-26 22:29:2037namespace {
38
39// Helper to get a mutable bookmark node.
[email protected]7b084b02011-07-08 16:06:4840BookmarkNode* AsMutable(const BookmarkNode* node) {
[email protected]b3c33d462009-06-26 22:29:2041 return const_cast<BookmarkNode*>(node);
42}
43
[email protected]996dbe82014-05-12 12:32:1844// Helper to get a mutable permanent bookmark node.
45BookmarkPermanentNode* AsMutable(const BookmarkPermanentNode* node) {
46 return const_cast<BookmarkPermanentNode*>(node);
47}
48
49// Comparator used when sorting permanent nodes. Nodes that are initially
50// visible are sorted before nodes that are initially hidden.
vmpstr3abe3302016-03-09 19:38:1951class VisibilityComparator {
[email protected]996dbe82014-05-12 12:32:1852 public:
53 explicit VisibilityComparator(BookmarkClient* client) : client_(client) {}
54
avicee78e4e2016-09-30 17:08:1455 // Returns true if |n1| precedes |n2|.
56 bool operator()(const std::unique_ptr<BookmarkPermanentNode>& n1,
57 const std::unique_ptr<BookmarkPermanentNode>& n2) {
58 bool n1_visible = client_->IsPermanentNodeVisible(n1.get());
59 bool n2_visible = client_->IsPermanentNodeVisible(n2.get());
[email protected]996dbe82014-05-12 12:32:1860 return n1_visible != n2_visible && n1_visible;
61 }
62
63 private:
64 BookmarkClient* client_;
65};
66
[email protected]ef762642009-03-05 16:30:2567// Comparator used when sorting bookmarks. Folders are sorted first, then
[email protected]2c685cc22009-08-28 00:17:4468// bookmarks.
vmpstr3abe3302016-03-09 19:38:1969class SortComparator {
[email protected]ef762642009-03-05 16:30:2570 public:
[email protected]a48f87d2012-10-09 18:06:3371 explicit SortComparator(icu::Collator* collator) : collator_(collator) {}
[email protected]ef762642009-03-05 16:30:2572
avicee78e4e2016-09-30 17:08:1473 // Returns true if |n1| precedes |n2|.
74 bool operator()(const std::unique_ptr<BookmarkNode>& n1,
75 const std::unique_ptr<BookmarkNode>& n2) {
[email protected]037db002009-10-19 20:06:0876 if (n1->type() == n2->type()) {
[email protected]ef762642009-03-05 16:30:2577 // Types are the same, compare the names.
78 if (!collator_)
[email protected]440b37b22010-08-30 05:31:4079 return n1->GetTitle() < n2->GetTitle();
[email protected]9a08fe82013-04-23 05:06:0580 return base::i18n::CompareString16WithCollator(
estade1274f882015-04-11 05:13:3581 *collator_, n1->GetTitle(), n2->GetTitle()) == UCOL_LESS;
[email protected]ef762642009-03-05 16:30:2582 }
83 // Types differ, sort such that folders come first.
84 return n1->is_folder();
85 }
86
87 private:
[email protected]b5b2385a2009-08-18 05:12:2988 icu::Collator* collator_;
[email protected]ef762642009-03-05 16:30:2589};
90
jianli14436d52015-10-09 22:47:3591// Delegate that does nothing.
92class EmptyUndoDelegate : public BookmarkUndoDelegate {
93 public:
94 EmptyUndoDelegate() {}
95 ~EmptyUndoDelegate() override {}
96
97 private:
98 // BookmarkUndoDelegate:
99 void SetUndoProvider(BookmarkUndoProvider* provider) override {}
100 void OnBookmarkNodeRemoved(BookmarkModel* model,
101 const BookmarkNode* parent,
102 int index,
dchengacd3f522016-04-21 22:30:41103 std::unique_ptr<BookmarkNode> node) override {}
jianli14436d52015-10-09 22:47:35104
105 DISALLOW_COPY_AND_ASSIGN(EmptyUndoDelegate);
106};
107
[email protected]bc770a032011-12-12 17:35:30108} // namespace
[email protected]97fdd162011-12-03 20:50:12109
[email protected]97fdd162011-12-03 20:50:12110// BookmarkModel --------------------------------------------------------------
111
dchengacd3f522016-04-21 22:30:41112BookmarkModel::BookmarkModel(std::unique_ptr<BookmarkClient> client)
sdefresne070a5102016-02-01 13:42:14113 : client_(std::move(client)),
initial.commit09911bf2008-07-26 23:55:29114 loaded_(false),
[email protected]ea2e5aa52009-05-20 18:01:28115 root_(GURL()),
Ivan Kotenkov75b1c3a2017-10-24 14:47:24116 bookmark_bar_node_(nullptr),
117 other_node_(nullptr),
118 mobile_node_(nullptr),
[email protected]4d89f382009-05-12 06:56:49119 next_node_id_(1),
brettw236d3172015-06-03 16:31:43120 observers_(
121 base::ObserverList<BookmarkModelObserver>::NOTIFY_EXISTING_ONLY),
gab77f88322016-06-02 13:47:03122 loaded_signal_(base::WaitableEvent::ResetPolicy::MANUAL,
123 base::WaitableEvent::InitialState::NOT_SIGNALED),
jianli14436d52015-10-09 22:47:35124 extensive_changes_(0),
125 undo_delegate_(nullptr),
126 empty_undo_delegate_(new EmptyUndoDelegate) {
[email protected]6a848b52014-04-26 22:06:54127 DCHECK(client_);
sdefresne070a5102016-02-01 13:42:14128 client_->Init(this);
initial.commit09911bf2008-07-26 23:55:29129}
130
[email protected]d8e41ed2008-09-11 15:22:32131BookmarkModel::~BookmarkModel() {
tfarina2fa1d2fb2016-10-19 01:44:31132 for (BookmarkModelObserver& observer : observers_)
133 observer.BookmarkModelBeingDeleted(this);
[email protected]3de6fd342008-09-05 02:44:51134
[email protected]dc24976f2013-06-02 21:15:09135 if (store_.get()) {
[email protected]f25387b2008-08-21 15:20:33136 // The store maintains a reference back to us. We need to tell it we're gone
137 // so that it doesn't try and invoke a method back on us again.
138 store_->BookmarkModelDeleted();
initial.commit09911bf2008-07-26 23:55:29139 }
140}
141
[email protected]f61f4782012-06-08 21:54:21142void BookmarkModel::Shutdown() {
[email protected]88e6a232011-09-14 14:53:20143 if (loaded_)
144 return;
145
[email protected]f61f4782012-06-08 21:54:21146 // See comment in HistoryService::ShutdownOnUIThread where this is invoked for
147 // details. It is also called when the BookmarkModel is deleted.
[email protected]88e6a232011-09-14 14:53:20148 loaded_signal_.Signal();
149}
150
[email protected]afecfb72013-04-18 17:17:33151void BookmarkModel::Load(
[email protected]6a848b52014-04-26 22:06:54152 PrefService* pref_service,
[email protected]6a848b52014-04-26 22:06:54153 const base::FilePath& profile_path,
154 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
155 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) {
[email protected]90ef13132008-08-27 03:27:46156 if (store_.get()) {
157 // If the store is non-null, it means Load was already invoked. Load should
158 // only be invoked once.
159 NOTREACHED();
160 return;
161 }
162
[email protected]6df6ec022013-07-16 03:05:22163 expanded_state_tracker_.reset(
[email protected]6a848b52014-04-26 22:06:54164 new BookmarkExpandedStateTracker(this, pref_service));
[email protected]90ef13132008-08-27 03:27:46165
166 // Load the bookmarks. BookmarkStorage notifies us when done.
skyad686a32015-06-25 17:42:28167 store_.reset(new BookmarkStorage(this, profile_path, io_task_runner.get()));
jshin1fb76462016-04-05 22:13:03168 store_->LoadBookmarks(CreateLoadDetails(), ui_task_runner);
[email protected]90ef13132008-08-27 03:27:46169}
170
[email protected]125b234182011-07-08 19:54:41171void BookmarkModel::AddObserver(BookmarkModelObserver* observer) {
172 observers_.AddObserver(observer);
173}
174
175void BookmarkModel::RemoveObserver(BookmarkModelObserver* observer) {
176 observers_.RemoveObserver(observer);
177}
178
[email protected]b68a8172012-02-17 00:25:18179void BookmarkModel::BeginExtensiveChanges() {
180 if (++extensive_changes_ == 1) {
tfarina2fa1d2fb2016-10-19 01:44:31181 for (BookmarkModelObserver& observer : observers_)
182 observer.ExtensiveBookmarkChangesBeginning(this);
[email protected]b68a8172012-02-17 00:25:18183 }
[email protected]125b234182011-07-08 19:54:41184}
185
[email protected]b68a8172012-02-17 00:25:18186void BookmarkModel::EndExtensiveChanges() {
187 --extensive_changes_;
188 DCHECK_GE(extensive_changes_, 0);
189 if (extensive_changes_ == 0) {
tfarina2fa1d2fb2016-10-19 01:44:31190 for (BookmarkModelObserver& observer : observers_)
191 observer.ExtensiveBookmarkChangesEnded(this);
[email protected]b68a8172012-02-17 00:25:18192 }
[email protected]125b234182011-07-08 19:54:41193}
194
[email protected]346453a2014-03-12 10:14:37195void BookmarkModel::BeginGroupedChanges() {
tfarina2fa1d2fb2016-10-19 01:44:31196 for (BookmarkModelObserver& observer : observers_)
197 observer.GroupedBookmarkChangesBeginning(this);
[email protected]346453a2014-03-12 10:14:37198}
199
200void BookmarkModel::EndGroupedChanges() {
tfarina2fa1d2fb2016-10-19 01:44:31201 for (BookmarkModelObserver& observer : observers_)
202 observer.GroupedBookmarkChangesEnded(this);
[email protected]346453a2014-03-12 10:14:37203}
204
deepak.m139312672015-05-04 16:29:43205void BookmarkModel::Remove(const BookmarkNode* node) {
tfarina16f92ed42015-06-12 13:54:36206 DCHECK(loaded_);
deepak.m139312672015-05-04 16:29:43207 DCHECK(node);
tfarina16f92ed42015-06-12 13:54:36208 DCHECK(!is_root_node(node));
deepak.m139312672015-05-04 16:29:43209 RemoveAndDeleteNode(AsMutable(node));
[email protected]f25387b2008-08-21 15:20:33210}
211
[email protected]5cd942208a2014-06-11 06:16:46212void BookmarkModel::RemoveAllUserBookmarks() {
[email protected]9109f8a12013-06-12 18:07:48213 std::set<GURL> removed_urls;
jianli14436d52015-10-09 22:47:35214 struct RemoveNodeData {
jianli14436d52015-10-09 22:47:35215 const BookmarkNode* parent;
216 int index;
avicee78e4e2016-09-30 17:08:14217 std::unique_ptr<BookmarkNode> node;
jianli14436d52015-10-09 22:47:35218 };
219 std::vector<RemoveNodeData> removed_node_data_list;
[email protected]472f95e2013-06-10 16:49:18220
tfarina2fa1d2fb2016-10-19 01:44:31221 for (BookmarkModelObserver& observer : observers_)
222 observer.OnWillRemoveAllUserBookmarks(this);
[email protected]472f95e2013-06-10 16:49:18223
[email protected]323dbf72013-03-30 17:08:33224 BeginExtensiveChanges();
225 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and
226 // its immediate children. For removing all non permanent nodes just remove
227 // all children of non-root permanent nodes.
228 {
229 base::AutoLock url_lock(url_lock_);
230 for (int i = 0; i < root_.child_count(); ++i) {
jianli14436d52015-10-09 22:47:35231 const BookmarkNode* permanent_node = root_.GetChild(i);
[email protected]043a76d2014-06-05 16:36:24232
[email protected]23e39692014-06-06 21:10:13233 if (!client_->CanBeEditedByUser(permanent_node))
[email protected]043a76d2014-06-05 16:36:24234 continue;
235
[email protected]323dbf72013-03-30 17:08:33236 for (int j = permanent_node->child_count() - 1; j >= 0; --j) {
avicee78e4e2016-09-30 17:08:14237 std::unique_ptr<BookmarkNode> node = RemoveNodeAndGetRemovedUrls(
238 AsMutable(permanent_node->GetChild(j)), &removed_urls);
239 removed_node_data_list.push_back({permanent_node, j, std::move(node)});
[email protected]323dbf72013-03-30 17:08:33240 }
241 }
242 }
243 EndExtensiveChanges();
244 if (store_.get())
245 store_->ScheduleSave();
246
tfarina2fa1d2fb2016-10-19 01:44:31247 for (BookmarkModelObserver& observer : observers_)
248 observer.BookmarkAllUserNodesRemoved(this, removed_urls);
jianli14436d52015-10-09 22:47:35249
250 BeginGroupedChanges();
avicee78e4e2016-09-30 17:08:14251 for (auto& removed_node_data : removed_node_data_list) {
252 undo_delegate()->OnBookmarkNodeRemoved(this, removed_node_data.parent,
253 removed_node_data.index,
254 std::move(removed_node_data.node));
jianli14436d52015-10-09 22:47:35255 }
256 EndGroupedChanges();
[email protected]5cd942208a2014-06-11 06:16:46257}
258
[email protected]b3c33d462009-06-26 22:29:20259void BookmarkModel::Move(const BookmarkNode* node,
260 const BookmarkNode* new_parent,
[email protected]d8e41ed2008-09-11 15:22:32261 int index) {
[email protected]f25387b2008-08-21 15:20:33262 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
[email protected]6b4d64c2011-07-29 21:33:24263 is_root_node(new_parent) || is_permanent_node(node)) {
initial.commit09911bf2008-07-26 23:55:29264 NOTREACHED();
265 return;
266 }
267
268 if (new_parent->HasAncestor(node)) {
269 // Can't make an ancestor of the node be a child of the node.
270 NOTREACHED();
271 return;
272 }
273
[email protected]2d48ee842011-03-08 23:27:29274 const BookmarkNode* old_parent = node->parent();
[email protected]368f3a72011-03-08 17:17:48275 int old_index = old_parent->GetIndexOf(node);
initial.commit09911bf2008-07-26 23:55:29276
277 if (old_parent == new_parent &&
278 (index == old_index || index == old_index + 1)) {
279 // Node is already in this position, nothing to do.
280 return;
281 }
282
[email protected]9e583642012-12-05 02:48:32283 SetDateFolderModified(new_parent, Time::Now());
284
initial.commit09911bf2008-07-26 23:55:29285 if (old_parent == new_parent && index > old_index)
286 index--;
avicee78e4e2016-09-30 17:08:14287
288 BookmarkNode* mutable_old_parent = AsMutable(old_parent);
289 std::unique_ptr<BookmarkNode> owned_node =
290 mutable_old_parent->Remove(AsMutable(node));
[email protected]b3c33d462009-06-26 22:29:20291 BookmarkNode* mutable_new_parent = AsMutable(new_parent);
avicee78e4e2016-09-30 17:08:14292 mutable_new_parent->Add(std::move(owned_node), index);
initial.commit09911bf2008-07-26 23:55:29293
[email protected]f25387b2008-08-21 15:20:33294 if (store_.get())
295 store_->ScheduleSave();
296
tfarina2fa1d2fb2016-10-19 01:44:31297 for (BookmarkModelObserver& observer : observers_)
298 observer.BookmarkNodeMoved(this, old_parent, old_index, new_parent, index);
initial.commit09911bf2008-07-26 23:55:29299}
300
[email protected]4e187ef652010-03-11 05:21:35301void BookmarkModel::Copy(const BookmarkNode* node,
302 const BookmarkNode* new_parent,
303 int index) {
304 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
[email protected]6b4d64c2011-07-29 21:33:24305 is_root_node(new_parent) || is_permanent_node(node)) {
[email protected]4e187ef652010-03-11 05:21:35306 NOTREACHED();
307 return;
308 }
309
310 if (new_parent->HasAncestor(node)) {
311 // Can't make an ancestor of the node be a child of the node.
312 NOTREACHED();
313 return;
314 }
315
[email protected]c6a7a3d2011-03-12 01:04:30316 SetDateFolderModified(new_parent, Time::Now());
[email protected]67a8ae42013-05-20 09:42:39317 BookmarkNodeData drag_data(node);
[email protected]b1864502010-11-13 00:55:51318 // CloneBookmarkNode will use BookmarkModel methods to do the job, so we
[email protected]1a566fae2010-04-16 01:05:06319 // don't need to send notifications here.
tfarina8f3c40cc2015-01-20 21:22:50320 CloneBookmarkNode(this, drag_data.elements, new_parent, index, true);
[email protected]4e187ef652010-03-11 05:21:35321
322 if (store_.get())
323 store_->ScheduleSave();
[email protected]4e187ef652010-03-11 05:21:35324}
325
[email protected]6a4e5a02012-06-26 19:47:48326const gfx::Image& BookmarkModel::GetFavicon(const BookmarkNode* node) {
[email protected]ea2e5aa52009-05-20 18:01:28327 DCHECK(node);
[email protected]bcc38612012-10-23 01:10:27328 if (node->favicon_state() == BookmarkNode::INVALID_FAVICON) {
[email protected]b3c33d462009-06-26 22:29:20329 BookmarkNode* mutable_node = AsMutable(node);
tfarinac0baf0b2014-12-08 18:01:21330 LoadFavicon(mutable_node,
331 client_->PreferTouchIcon() ? favicon_base::TOUCH_ICON
332 : favicon_base::FAVICON);
[email protected]ea2e5aa52009-05-20 18:01:28333 }
334 return node->favicon();
335}
336
[email protected]504fca82014-05-07 22:48:08337favicon_base::IconType BookmarkModel::GetFaviconType(const BookmarkNode* node) {
338 DCHECK(node);
339 return node->favicon_type();
340}
341
[email protected]6a848b52014-04-26 22:06:54342void BookmarkModel::SetTitle(const BookmarkNode* node,
343 const base::string16& title) {
tfarina5ebd5362015-05-12 21:50:10344 DCHECK(node);
345
[email protected]0491ff72011-12-30 00:45:59346 if (node->GetTitle() == title)
initial.commit09911bf2008-07-26 23:55:29347 return;
[email protected]f25387b2008-08-21 15:20:33348
[email protected]043a76d2014-06-05 16:36:24349 if (is_permanent_node(node) && !client_->CanSetPermanentNodeTitle(node)) {
[email protected]baf4f922009-10-19 16:44:07350 NOTREACHED();
351 return;
352 }
353
tfarina2fa1d2fb2016-10-19 01:44:31354 for (BookmarkModelObserver& observer : observers_)
355 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18356
[email protected]85d911c2009-05-19 03:59:42357 // The title index doesn't support changing the title, instead we remove then
358 // add it back.
[email protected]01eec882009-05-22 18:13:28359 index_->Remove(node);
[email protected]0491ff72011-12-30 00:45:59360 AsMutable(node)->SetTitle(title);
[email protected]01eec882009-05-22 18:13:28361 index_->Add(node);
[email protected]85d911c2009-05-19 03:59:42362
[email protected]f25387b2008-08-21 15:20:33363 if (store_.get())
364 store_->ScheduleSave();
365
tfarina2fa1d2fb2016-10-19 01:44:31366 for (BookmarkModelObserver& observer : observers_)
367 observer.BookmarkNodeChanged(this, node);
initial.commit09911bf2008-07-26 23:55:29368}
369
[email protected]e5486602010-02-09 21:27:55370void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) {
tfarina5ebd5362015-05-12 21:50:10371 DCHECK(node && !node->is_folder());
[email protected]e5486602010-02-09 21:27:55372
[email protected]5d4077542011-07-21 20:24:07373 if (node->url() == url)
[email protected]e5486602010-02-09 21:27:55374 return;
375
[email protected]5b5c9b7f32011-07-21 01:07:18376 BookmarkNode* mutable_node = AsMutable(node);
377 mutable_node->InvalidateFavicon();
378 CancelPendingFaviconLoadRequests(mutable_node);
[email protected]e5486602010-02-09 21:27:55379
tfarina2fa1d2fb2016-10-19 01:44:31380 for (BookmarkModelObserver& observer : observers_)
381 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18382
[email protected]e5486602010-02-09 21:27:55383 {
[email protected]20305ec2011-01-21 04:55:52384 base::AutoLock url_lock(url_lock_);
danduongf4fde322014-11-04 18:56:56385 RemoveNodeFromInternalMaps(mutable_node);
[email protected]5d4077542011-07-21 20:24:07386 mutable_node->set_url(url);
danduongf4fde322014-11-04 18:56:56387 AddNodeToInternalMaps(mutable_node);
[email protected]e5486602010-02-09 21:27:55388 }
389
390 if (store_.get())
391 store_->ScheduleSave();
392
tfarina2fa1d2fb2016-10-19 01:44:31393 for (BookmarkModelObserver& observer : observers_)
394 observer.BookmarkNodeChanged(this, node);
[email protected]e5486602010-02-09 21:27:55395}
396
[email protected]1858410f2012-10-26 05:06:45397void BookmarkModel::SetNodeMetaInfo(const BookmarkNode* node,
398 const std::string& key,
399 const std::string& value) {
[email protected]39e113452013-11-26 00:43:06400 std::string old_value;
401 if (node->GetMetaInfo(key, &old_value) && old_value == value)
402 return;
403
tfarina2fa1d2fb2016-10-19 01:44:31404 for (BookmarkModelObserver& observer : observers_)
405 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40406
[email protected]1858410f2012-10-26 05:06:45407 if (AsMutable(node)->SetMetaInfo(key, value) && store_.get())
408 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40409
tfarina2fa1d2fb2016-10-19 01:44:31410 for (BookmarkModelObserver& observer : observers_)
411 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45412}
413
[email protected]e38a87d2013-12-05 01:35:18414void BookmarkModel::SetNodeMetaInfoMap(
415 const BookmarkNode* node,
416 const BookmarkNode::MetaInfoMap& meta_info_map) {
417 const BookmarkNode::MetaInfoMap* old_meta_info_map = node->GetMetaInfoMap();
418 if ((!old_meta_info_map && meta_info_map.empty()) ||
419 (old_meta_info_map && meta_info_map == *old_meta_info_map))
420 return;
421
tfarina2fa1d2fb2016-10-19 01:44:31422 for (BookmarkModelObserver& observer : observers_)
423 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]e38a87d2013-12-05 01:35:18424
425 AsMutable(node)->SetMetaInfoMap(meta_info_map);
426 if (store_.get())
427 store_->ScheduleSave();
428
tfarina2fa1d2fb2016-10-19 01:44:31429 for (BookmarkModelObserver& observer : observers_)
430 observer.BookmarkMetaInfoChanged(this, node);
[email protected]e38a87d2013-12-05 01:35:18431}
432
[email protected]1858410f2012-10-26 05:06:45433void BookmarkModel::DeleteNodeMetaInfo(const BookmarkNode* node,
434 const std::string& key) {
[email protected]39e113452013-11-26 00:43:06435 const BookmarkNode::MetaInfoMap* meta_info_map = node->GetMetaInfoMap();
436 if (!meta_info_map || meta_info_map->find(key) == meta_info_map->end())
437 return;
438
tfarina2fa1d2fb2016-10-19 01:44:31439 for (BookmarkModelObserver& observer : observers_)
440 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40441
[email protected]1858410f2012-10-26 05:06:45442 if (AsMutable(node)->DeleteMetaInfo(key) && store_.get())
443 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40444
tfarina2fa1d2fb2016-10-19 01:44:31445 for (BookmarkModelObserver& observer : observers_)
446 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45447}
448
rfevangd75d32212014-12-06 01:27:22449void BookmarkModel::AddNonClonedKey(const std::string& key) {
450 non_cloned_keys_.insert(key);
451}
452
[email protected]39e113452013-11-26 00:43:06453void BookmarkModel::SetNodeSyncTransactionVersion(
454 const BookmarkNode* node,
avibc5337b2015-12-25 23:16:33455 int64_t sync_transaction_version) {
[email protected]043a76d2014-06-05 16:36:24456 DCHECK(client_->CanSyncNode(node));
457
[email protected]39e113452013-11-26 00:43:06458 if (sync_transaction_version == node->sync_transaction_version())
459 return;
460
461 AsMutable(node)->set_sync_transaction_version(sync_transaction_version);
462 if (store_.get())
463 store_->ScheduleSave();
464}
465
pkotwiczca240dd2015-07-09 16:15:32466void BookmarkModel::OnFaviconsChanged(const std::set<GURL>& page_urls,
467 const GURL& icon_url) {
468 std::set<const BookmarkNode*> to_update;
469 for (const GURL& page_url : page_urls) {
[email protected]6a848b52014-04-26 22:06:54470 std::vector<const BookmarkNode*> nodes;
pkotwiczca240dd2015-07-09 16:15:32471 GetNodesByURL(page_url, &nodes);
472 to_update.insert(nodes.begin(), nodes.end());
473 }
474
475 if (!icon_url.is_empty()) {
476 // Log Histogram to determine how often |icon_url| is non empty in
477 // practice.
478 // TODO(pkotwicz): Do something more efficient if |icon_url| is non-empty
479 // many times a day for each user.
480 UMA_HISTOGRAM_BOOLEAN("Bookmarks.OnFaviconsChangedIconURL", true);
481
482 base::AutoLock url_lock(url_lock_);
483 for (const BookmarkNode* node : nodes_ordered_by_url_set_) {
ssid144fb7b82017-06-01 02:32:26484 if (node->icon_url() && icon_url == *node->icon_url())
pkotwiczca240dd2015-07-09 16:15:32485 to_update.insert(node);
[email protected]6a848b52014-04-26 22:06:54486 }
487 }
pkotwiczca240dd2015-07-09 16:15:32488
489 for (const BookmarkNode* node : to_update) {
490 // Rerequest the favicon.
491 BookmarkNode* mutable_node = AsMutable(node);
492 mutable_node->InvalidateFavicon();
493 CancelPendingFaviconLoadRequests(mutable_node);
tfarina2fa1d2fb2016-10-19 01:44:31494 for (BookmarkModelObserver& observer : observers_)
495 observer.BookmarkNodeFaviconChanged(this, node);
pkotwiczca240dd2015-07-09 16:15:32496 }
[email protected]6a848b52014-04-26 22:06:54497}
498
tfarina5ebd5362015-05-12 21:50:10499void BookmarkModel::SetDateAdded(const BookmarkNode* node, Time date_added) {
500 DCHECK(node && !is_permanent_node(node));
[email protected]b61445c2012-10-27 00:11:42501
502 if (node->date_added() == date_added)
503 return;
504
[email protected]b61445c2012-10-27 00:11:42505 AsMutable(node)->set_date_added(date_added);
506
507 // Syncing might result in dates newer than the folder's last modified date.
508 if (date_added > node->parent()->date_folder_modified()) {
509 // Will trigger store_->ScheduleSave().
510 SetDateFolderModified(node->parent(), date_added);
511 } else if (store_.get()) {
512 store_->ScheduleSave();
513 }
514}
515
[email protected]848cd05e2008-09-19 18:33:48516void BookmarkModel::GetNodesByURL(const GURL& url,
[email protected]b3c33d462009-06-26 22:29:20517 std::vector<const BookmarkNode*>* nodes) {
[email protected]20305ec2011-01-21 04:55:52518 base::AutoLock url_lock(url_lock_);
[email protected]ea2e5aa52009-05-20 18:01:28519 BookmarkNode tmp_node(url);
initial.commit09911bf2008-07-26 23:55:29520 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node);
[email protected]5d4077542011-07-21 20:24:07521 while (i != nodes_ordered_by_url_set_.end() && (*i)->url() == url) {
[email protected]848cd05e2008-09-19 18:33:48522 nodes->push_back(*i);
523 ++i;
524 }
525}
526
[email protected]23e39692014-06-06 21:10:13527const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL(
[email protected]b3c33d462009-06-26 22:29:20528 const GURL& url) {
529 std::vector<const BookmarkNode*> nodes;
[email protected]848cd05e2008-09-19 18:33:48530 GetNodesByURL(url, &nodes);
tfarinaa0ec34e2015-01-12 18:46:48531 std::sort(nodes.begin(), nodes.end(), &MoreRecentlyAdded);
[email protected]23e39692014-06-06 21:10:13532
533 // Look for the first node that the user can edit.
534 for (size_t i = 0; i < nodes.size(); ++i) {
535 if (client_->CanBeEditedByUser(nodes[i]))
536 return nodes[i];
537 }
538
Ivan Kotenkov75b1c3a2017-10-24 14:47:24539 return nullptr;
initial.commit09911bf2008-07-26 23:55:29540}
541
[email protected]cf8e8172011-07-23 00:46:24542bool BookmarkModel::HasBookmarks() {
543 base::AutoLock url_lock(url_lock_);
544 return !nodes_ordered_by_url_set_.empty();
545}
546
Marti Wongc67da222017-09-01 02:30:01547bool BookmarkModel::HasNoUserCreatedBookmarksOrFolders() {
548 return bookmark_bar_node_->empty() && other_node_->empty() &&
549 mobile_node_->empty();
550}
551
[email protected]cf8e8172011-07-23 00:46:24552bool BookmarkModel::IsBookmarked(const GURL& url) {
553 base::AutoLock url_lock(url_lock_);
554 return IsBookmarkedNoLock(url);
555}
556
[email protected]0f7bee52012-08-06 20:04:17557void BookmarkModel::GetBookmarks(
[email protected]cef7931c2014-06-06 09:56:09558 std::vector<BookmarkModel::URLAndTitle>* bookmarks) {
[email protected]20305ec2011-01-21 04:55:52559 base::AutoLock url_lock(url_lock_);
Ivan Kotenkov75b1c3a2017-10-24 14:47:24560 const GURL* last_url = nullptr;
[email protected]90ef13132008-08-27 03:27:46561 for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin();
562 i != nodes_ordered_by_url_set_.end(); ++i) {
[email protected]5d4077542011-07-21 20:24:07563 const GURL* url = &((*i)->url());
[email protected]848cd05e2008-09-19 18:33:48564 // Only add unique URLs.
[email protected]0f7bee52012-08-06 20:04:17565 if (!last_url || *url != *last_url) {
[email protected]cef7931c2014-06-06 09:56:09566 BookmarkModel::URLAndTitle bookmark;
[email protected]0f7bee52012-08-06 20:04:17567 bookmark.url = *url;
568 bookmark.title = (*i)->GetTitle();
569 bookmarks->push_back(bookmark);
570 }
[email protected]848cd05e2008-09-19 18:33:48571 last_url = url;
[email protected]90ef13132008-08-27 03:27:46572 }
573}
574
[email protected]cf8e8172011-07-23 00:46:24575void BookmarkModel::BlockTillLoaded() {
576 loaded_signal_.Wait();
[email protected]848cd05e2008-09-19 18:33:48577}
578
[email protected]39703292011-03-18 17:03:40579const BookmarkNode* BookmarkModel::AddFolder(const BookmarkNode* parent,
580 int index,
[email protected]96920152013-12-04 21:00:16581 const base::string16& title) {
Ivan Kotenkov75b1c3a2017-10-24 14:47:24582 return AddFolderWithMetaInfo(parent, index, title, nullptr);
[email protected]eb59ad12014-04-24 00:05:08583}
584const BookmarkNode* BookmarkModel::AddFolderWithMetaInfo(
585 const BookmarkNode* parent,
586 int index,
587 const base::string16& title,
588 const BookmarkNode::MetaInfoMap* meta_info) {
[email protected]6b4d64c2011-07-29 21:33:24589 if (!loaded_ || is_root_node(parent) || !IsValidIndex(parent, index, true)) {
initial.commit09911bf2008-07-26 23:55:29590 // Can't add to the root.
591 NOTREACHED();
Ivan Kotenkov75b1c3a2017-10-24 14:47:24592 return nullptr;
initial.commit09911bf2008-07-26 23:55:29593 }
594
avicee78e4e2016-09-30 17:08:14595 std::unique_ptr<BookmarkNode> new_node =
596 base::MakeUnique<BookmarkNode>(generate_next_node_id(), GURL());
[email protected]edb63cc2011-03-11 02:00:41597 new_node->set_date_folder_modified(Time::Now());
[email protected]aee236542011-12-01 04:34:03598 // Folders shouldn't have line breaks in their titles.
[email protected]0491ff72011-12-30 00:45:59599 new_node->SetTitle(title);
[email protected]037db002009-10-19 20:06:08600 new_node->set_type(BookmarkNode::FOLDER);
[email protected]eb59ad12014-04-24 00:05:08601 if (meta_info)
602 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29603
avicee78e4e2016-09-30 17:08:14604 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29605}
606
[email protected]e64e9012010-01-11 23:10:55607const BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent,
608 int index,
[email protected]96920152013-12-04 21:00:16609 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55610 const GURL& url) {
Ivan Kotenkov75b1c3a2017-10-24 14:47:24611 return AddURLWithCreationTimeAndMetaInfo(parent, index, title, url,
612 Time::Now(), nullptr);
initial.commit09911bf2008-07-26 23:55:29613}
614
[email protected]eb59ad12014-04-24 00:05:08615const BookmarkNode* BookmarkModel::AddURLWithCreationTimeAndMetaInfo(
[email protected]e64e9012010-01-11 23:10:55616 const BookmarkNode* parent,
617 int index,
[email protected]96920152013-12-04 21:00:16618 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55619 const GURL& url,
[email protected]eb59ad12014-04-24 00:05:08620 const Time& creation_time,
621 const BookmarkNode::MetaInfoMap* meta_info) {
[email protected]6b4d64c2011-07-29 21:33:24622 if (!loaded_ || !url.is_valid() || is_root_node(parent) ||
[email protected]f25387b2008-08-21 15:20:33623 !IsValidIndex(parent, index, true)) {
initial.commit09911bf2008-07-26 23:55:29624 NOTREACHED();
Ivan Kotenkov75b1c3a2017-10-24 14:47:24625 return nullptr;
initial.commit09911bf2008-07-26 23:55:29626 }
initial.commit09911bf2008-07-26 23:55:29627
[email protected]b61445c2012-10-27 00:11:42628 // Syncing may result in dates newer than the last modified date.
[email protected]8ad613b2012-10-12 21:28:45629 if (creation_time > parent->date_folder_modified())
630 SetDateFolderModified(parent, creation_time);
initial.commit09911bf2008-07-26 23:55:29631
avicee78e4e2016-09-30 17:08:14632 std::unique_ptr<BookmarkNode> new_node =
633 base::MakeUnique<BookmarkNode>(generate_next_node_id(), url);
[email protected]0491ff72011-12-30 00:45:59634 new_node->SetTitle(title);
[email protected]b3c33d462009-06-26 22:29:20635 new_node->set_date_added(creation_time);
[email protected]037db002009-10-19 20:06:08636 new_node->set_type(BookmarkNode::URL);
[email protected]eb59ad12014-04-24 00:05:08637 if (meta_info)
638 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29639
avicee78e4e2016-09-30 17:08:14640 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29641}
642
[email protected]b3c33d462009-06-26 22:29:20643void BookmarkModel::SortChildren(const BookmarkNode* parent) {
[email protected]23e39692014-06-06 21:10:13644 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24645
[email protected]6b4d64c2011-07-29 21:33:24646 if (!parent || !parent->is_folder() || is_root_node(parent) ||
[email protected]9c1a75a2011-03-10 02:38:12647 parent->child_count() <= 1) {
[email protected]e2f86d92009-02-25 00:22:01648 return;
649 }
650
tfarina2fa1d2fb2016-10-19 01:44:31651 for (BookmarkModelObserver& observer : observers_)
652 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18653
[email protected]ef762642009-03-05 16:30:25654 UErrorCode error = U_ZERO_ERROR;
dchengacd3f522016-04-21 22:30:41655 std::unique_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
[email protected]ef762642009-03-05 16:30:25656 if (U_FAILURE(error))
Ivan Kotenkov75b1c3a2017-10-24 14:47:24657 collator.reset(nullptr);
[email protected]b3c33d462009-06-26 22:29:20658 BookmarkNode* mutable_parent = AsMutable(parent);
659 std::sort(mutable_parent->children().begin(),
660 mutable_parent->children().end(),
[email protected]ef762642009-03-05 16:30:25661 SortComparator(collator.get()));
[email protected]e2f86d92009-02-25 00:22:01662
[email protected]997a0362009-03-12 03:10:51663 if (store_.get())
664 store_->ScheduleSave();
665
tfarina2fa1d2fb2016-10-19 01:44:31666 for (BookmarkModelObserver& observer : observers_)
667 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]e2f86d92009-02-25 00:22:01668}
669
[email protected]472f95e2013-06-10 16:49:18670void BookmarkModel::ReorderChildren(
671 const BookmarkNode* parent,
[email protected]257d5082013-08-06 07:46:43672 const std::vector<const BookmarkNode*>& ordered_nodes) {
[email protected]23e39692014-06-06 21:10:13673 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24674
[email protected]472f95e2013-06-10 16:49:18675 // Ensure that all children in |parent| are in |ordered_nodes|.
676 DCHECK_EQ(static_cast<size_t>(parent->child_count()), ordered_nodes.size());
avicee78e4e2016-09-30 17:08:14677 for (const BookmarkNode* node : ordered_nodes)
678 DCHECK_EQ(parent, node->parent());
[email protected]472f95e2013-06-10 16:49:18679
tfarina2fa1d2fb2016-10-19 01:44:31680 for (BookmarkModelObserver& observer : observers_)
681 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18682
avicee78e4e2016-09-30 17:08:14683 if (ordered_nodes.size() > 1) {
684 std::map<const BookmarkNode*, int> order;
685 for (size_t i = 0; i < ordered_nodes.size(); ++i)
686 order[ordered_nodes[i]] = i;
[email protected]472f95e2013-06-10 16:49:18687
avicee78e4e2016-09-30 17:08:14688 std::vector<std::unique_ptr<BookmarkNode>> new_children(
689 ordered_nodes.size());
690 BookmarkNode* mutable_parent = AsMutable(parent);
691 for (auto& child : mutable_parent->children()) {
692 size_t new_location = order[child.get()];
693 new_children[new_location] = std::move(child);
694 }
695 mutable_parent->children().swap(new_children);
696
697 if (store_.get())
698 store_->ScheduleSave();
699 }
[email protected]472f95e2013-06-10 16:49:18700
tfarina2fa1d2fb2016-10-19 01:44:31701 for (BookmarkModelObserver& observer : observers_)
702 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]472f95e2013-06-10 16:49:18703}
704
[email protected]c6a7a3d2011-03-12 01:04:30705void BookmarkModel::SetDateFolderModified(const BookmarkNode* parent,
706 const Time time) {
[email protected]eea8fd5532009-12-16 00:08:10707 DCHECK(parent);
[email protected]edb63cc2011-03-11 02:00:41708 AsMutable(parent)->set_date_folder_modified(time);
[email protected]eea8fd5532009-12-16 00:08:10709
710 if (store_.get())
711 store_->ScheduleSave();
712}
713
[email protected]c6a7a3d2011-03-12 01:04:30714void BookmarkModel::ResetDateFolderModified(const BookmarkNode* node) {
715 SetDateFolderModified(node, Time());
initial.commit09911bf2008-07-26 23:55:29716}
717
kkimlabsf1a7a3732014-11-04 10:30:46718void BookmarkModel::GetBookmarksMatching(const base::string16& text,
719 size_t max_count,
mattreynolds25e9a312016-12-14 21:52:13720 std::vector<TitledUrlMatch>* matches) {
kkimlabsf1a7a3732014-11-04 10:30:46721 GetBookmarksMatching(text, max_count,
722 query_parser::MatchingAlgorithm::DEFAULT, matches);
723}
724
[email protected]b3a84892014-04-23 04:28:07725void BookmarkModel::GetBookmarksMatching(
[email protected]96920152013-12-04 21:00:16726 const base::string16& text,
[email protected]e64e9012010-01-11 23:10:55727 size_t max_count,
kkimlabsf1a7a3732014-11-04 10:30:46728 query_parser::MatchingAlgorithm matching_algorithm,
mattreynolds25e9a312016-12-14 21:52:13729 std::vector<TitledUrlMatch>* matches) {
[email protected]01eec882009-05-22 18:13:28730 if (!loaded_)
731 return;
732
mattreynolds55324d62016-12-09 23:07:29733 index_->GetResultsMatching(text, max_count, matching_algorithm, matches);
[email protected]85d911c2009-05-19 03:59:42734}
735
[email protected]9876bb1c2008-12-16 20:42:25736void BookmarkModel::ClearStore() {
[email protected]265e88e2014-07-07 20:45:19737 store_.reset();
[email protected]9876bb1c2008-12-16 20:42:25738}
739
[email protected]bc770a032011-12-12 17:35:30740void BookmarkModel::SetPermanentNodeVisible(BookmarkNode::Type type,
741 bool value) {
[email protected]043a76d2014-06-05 16:36:24742 BookmarkPermanentNode* node = AsMutable(PermanentNode(type));
743 node->set_visible(value || client_->IsPermanentNodeVisible(node));
[email protected]996dbe82014-05-12 12:32:18744}
745
746const BookmarkPermanentNode* BookmarkModel::PermanentNode(
747 BookmarkNode::Type type) {
[email protected]1da5f712011-12-06 05:52:26748 DCHECK(loaded_);
[email protected]bc770a032011-12-12 17:35:30749 switch (type) {
750 case BookmarkNode::BOOKMARK_BAR:
[email protected]996dbe82014-05-12 12:32:18751 return bookmark_bar_node_;
[email protected]bc770a032011-12-12 17:35:30752 case BookmarkNode::OTHER_NODE:
[email protected]996dbe82014-05-12 12:32:18753 return other_node_;
[email protected]bc770a032011-12-12 17:35:30754 case BookmarkNode::MOBILE:
[email protected]996dbe82014-05-12 12:32:18755 return mobile_node_;
[email protected]bc770a032011-12-12 17:35:30756 default:
757 NOTREACHED();
Ivan Kotenkov75b1c3a2017-10-24 14:47:24758 return nullptr;
[email protected]bc770a032011-12-12 17:35:30759 }
[email protected]1da5f712011-12-06 05:52:26760}
761
avicee78e4e2016-09-30 17:08:14762void BookmarkModel::RestoreRemovedNode(const BookmarkNode* parent,
763 int index,
764 std::unique_ptr<BookmarkNode> node) {
765 BookmarkNode* node_ptr = node.get();
766 AddNode(AsMutable(parent), index, std::move(node));
jianli14436d52015-10-09 22:47:35767
768 // We might be restoring a folder node that have already contained a set of
769 // child nodes. We need to notify all of them.
avicee78e4e2016-09-30 17:08:14770 NotifyNodeAddedForAllDescendents(node_ptr);
jianli14436d52015-10-09 22:47:35771}
772
773void BookmarkModel::NotifyNodeAddedForAllDescendents(const BookmarkNode* node) {
774 for (int i = 0; i < node->child_count(); ++i) {
tfarina2fa1d2fb2016-10-19 01:44:31775 for (BookmarkModelObserver& observer : observers_)
776 observer.BookmarkNodeAdded(this, node, i);
jianli14436d52015-10-09 22:47:35777 NotifyNodeAddedForAllDescendents(node->GetChild(i));
778 }
779}
780
[email protected]dddc1b42008-10-09 20:56:59781bool BookmarkModel::IsBookmarkedNoLock(const GURL& url) {
[email protected]ea2e5aa52009-05-20 18:01:28782 BookmarkNode tmp_node(url);
[email protected]dddc1b42008-10-09 20:56:59783 return (nodes_ordered_by_url_set_.find(&tmp_node) !=
784 nodes_ordered_by_url_set_.end());
785}
786
[email protected]d8e41ed2008-09-11 15:22:32787void BookmarkModel::RemoveNode(BookmarkNode* node,
788 std::set<GURL>* removed_urls) {
[email protected]b3c33d462009-06-26 22:29:20789 if (!loaded_ || !node || is_permanent_node(node)) {
[email protected]f25387b2008-08-21 15:20:33790 NOTREACHED();
791 return;
792 }
793
[email protected]323dbf72013-03-30 17:08:33794 url_lock_.AssertAcquired();
[email protected]0890e60e2011-06-27 14:55:21795 if (node->is_url()) {
danduongf4fde322014-11-04 18:56:56796 RemoveNodeFromInternalMaps(node);
[email protected]5d4077542011-07-21 20:24:07797 removed_urls->insert(node->url());
initial.commit09911bf2008-07-26 23:55:29798 }
799
[email protected]abc2f262011-03-15 21:15:44800 CancelPendingFaviconLoadRequests(node);
initial.commit09911bf2008-07-26 23:55:29801
802 // Recurse through children.
[email protected]9c1a75a2011-03-10 02:38:12803 for (int i = node->child_count() - 1; i >= 0; --i)
[email protected]f25387b2008-08-21 15:20:33804 RemoveNode(node->GetChild(i), removed_urls);
initial.commit09911bf2008-07-26 23:55:29805}
806
dchengacd3f522016-04-21 22:30:41807void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
[email protected]6a848b52014-04-26 22:06:54808 DCHECK(details);
[email protected]01eec882009-05-22 18:13:28809 if (loaded_) {
810 // We should only ever be loaded once.
811 NOTREACHED();
812 return;
813 }
814
[email protected]01eec882009-05-22 18:13:28815 next_node_id_ = details->max_id();
[email protected]367d7072009-07-13 23:27:13816 if (details->computed_checksum() != details->stored_checksum() ||
817 details->ids_reassigned()) {
[email protected]367d7072009-07-13 23:27:13818 // If bookmarks file changed externally, the IDs may have changed
819 // externally. In that case, the decoder may have reassigned IDs to make
820 // them unique. So when the file has changed externally, we should save the
821 // bookmarks file to persist new IDs.
822 if (store_.get())
823 store_->ScheduleSave();
824 }
avicee78e4e2016-09-30 17:08:14825 std::unique_ptr<BookmarkPermanentNode> owned_bb_node =
826 details->owned_bb_node();
827 std::unique_ptr<BookmarkPermanentNode> owned_other_folder_node =
828 details->owned_other_folder_node();
829 std::unique_ptr<BookmarkPermanentNode> owned_mobile_folder_node =
830 details->owned_mobile_folder_node();
831 index_ = details->owned_index();
832
833 bookmark_bar_node_ = owned_bb_node.get();
834 other_node_ = owned_other_folder_node.get();
835 mobile_node_ = owned_mobile_folder_node.get();
[email protected]01eec882009-05-22 18:13:28836
[email protected]043a76d2014-06-05 16:36:24837 // Get any extra nodes and take ownership of them at the |root_|.
avicee78e4e2016-09-30 17:08:14838 std::vector<std::unique_ptr<BookmarkPermanentNode>> extra_nodes =
839 details->owned_extra_nodes();
[email protected]043a76d2014-06-05 16:36:24840
[email protected]82f4655a2011-10-18 13:05:43841 // WARNING: order is important here, various places assume the order is
[email protected]996dbe82014-05-12 12:32:18842 // constant (but can vary between embedders with the initial visibility
843 // of permanent nodes).
avicee78e4e2016-09-30 17:08:14844 std::vector<std::unique_ptr<BookmarkPermanentNode>> root_children;
845 root_children.push_back(std::move(owned_bb_node));
846 root_children.push_back(std::move(owned_other_folder_node));
847 root_children.push_back(std::move(owned_mobile_folder_node));
848 std::move(extra_nodes.begin(), extra_nodes.end(),
849 std::back_inserter(root_children));
robliaoad0efe962015-03-14 00:13:02850
[email protected]043a76d2014-06-05 16:36:24851 std::stable_sort(root_children.begin(),
852 root_children.end(),
sdefresne070a5102016-02-01 13:42:14853 VisibilityComparator(client_.get()));
[email protected]043a76d2014-06-05 16:36:24854 for (size_t i = 0; i < root_children.size(); ++i)
avicee78e4e2016-09-30 17:08:14855 root_.Add(std::move(root_children[i]), static_cast<int>(i));
[email protected]6c1164042009-05-08 14:41:08856
[email protected]39e113452013-11-26 00:43:06857 root_.SetMetaInfoMap(details->model_meta_info_map());
858 root_.set_sync_transaction_version(details->model_sync_transaction_version());
[email protected]1858410f2012-10-26 05:06:45859
[email protected]90ef13132008-08-27 03:27:46860 {
[email protected]20305ec2011-01-21 04:55:52861 base::AutoLock url_lock(url_lock_);
[email protected]90ef13132008-08-27 03:27:46862 // Update nodes_ordered_by_url_set_ from the nodes.
863 PopulateNodesByURL(&root_);
864 }
[email protected]f25387b2008-08-21 15:20:33865
initial.commit09911bf2008-07-26 23:55:29866 loaded_ = true;
867
[email protected]cbcd6412009-03-09 22:31:39868 loaded_signal_.Signal();
[email protected]90ef13132008-08-27 03:27:46869
[email protected]f25387b2008-08-21 15:20:33870 // Notify our direct observers.
tfarina2fa1d2fb2016-10-19 01:44:31871 for (BookmarkModelObserver& observer : observers_)
872 observer.BookmarkModelLoaded(this, details->ids_reassigned());
initial.commit09911bf2008-07-26 23:55:29873}
874
avicee78e4e2016-09-30 17:08:14875void BookmarkModel::RemoveAndDeleteNode(BookmarkNode* node_ptr) {
876 std::unique_ptr<BookmarkNode> node;
initial.commit09911bf2008-07-26 23:55:29877
avicee78e4e2016-09-30 17:08:14878 const BookmarkNode* parent = node_ptr->parent();
initial.commit09911bf2008-07-26 23:55:29879 DCHECK(parent);
avicee78e4e2016-09-30 17:08:14880 int index = parent->GetIndexOf(node_ptr);
deepak.m139312672015-05-04 16:29:43881 DCHECK_NE(-1, index);
[email protected]323dbf72013-03-30 17:08:33882
tfarina2fa1d2fb2016-10-19 01:44:31883 for (BookmarkModelObserver& observer : observers_)
884 observer.OnWillRemoveBookmarks(this, parent, index, node_ptr);
[email protected]472f95e2013-06-10 16:49:18885
[email protected]9109f8a12013-06-12 18:07:48886 std::set<GURL> removed_urls;
[email protected]90ef13132008-08-27 03:27:46887 {
[email protected]20305ec2011-01-21 04:55:52888 base::AutoLock url_lock(url_lock_);
avicee78e4e2016-09-30 17:08:14889 node = RemoveNodeAndGetRemovedUrls(node_ptr, &removed_urls);
[email protected]90ef13132008-08-27 03:27:46890 }
initial.commit09911bf2008-07-26 23:55:29891
[email protected]f25387b2008-08-21 15:20:33892 if (store_.get())
893 store_->ScheduleSave();
894
tfarina2fa1d2fb2016-10-19 01:44:31895 for (BookmarkModelObserver& observer : observers_)
896 observer.BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls);
jianli14436d52015-10-09 22:47:35897
dcheng51606352015-12-26 21:16:23898 undo_delegate()->OnBookmarkNodeRemoved(this, parent, index, std::move(node));
[email protected]323dbf72013-03-30 17:08:33899}
[email protected]f25387b2008-08-21 15:20:33900
danduongf4fde322014-11-04 18:56:56901void BookmarkModel::RemoveNodeFromInternalMaps(BookmarkNode* node) {
902 index_->Remove(node);
[email protected]5db00bca2013-12-23 00:43:09903 // NOTE: this is called in such a way that url_lock_ is already held. As
904 // such, this doesn't explicitly grab the lock.
danduongf4fde322014-11-04 18:56:56905 url_lock_.AssertAcquired();
[email protected]5db00bca2013-12-23 00:43:09906 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node);
907 DCHECK(i != nodes_ordered_by_url_set_.end());
908 // i points to the first node with the URL, advance until we find the
909 // node we're removing.
910 while (*i != node)
911 ++i;
912 nodes_ordered_by_url_set_.erase(i);
913}
914
avicee78e4e2016-09-30 17:08:14915std::unique_ptr<BookmarkNode> BookmarkModel::RemoveNodeAndGetRemovedUrls(
916 BookmarkNode* node_ptr,
917 std::set<GURL>* removed_urls) {
[email protected]323dbf72013-03-30 17:08:33918 // NOTE: this method should be always called with |url_lock_| held.
919 // This method does not explicitly acquires a lock.
920 url_lock_.AssertAcquired();
921 DCHECK(removed_urls);
avicee78e4e2016-09-30 17:08:14922 BookmarkNode* parent = node_ptr->parent();
[email protected]323dbf72013-03-30 17:08:33923 DCHECK(parent);
avicee78e4e2016-09-30 17:08:14924 std::unique_ptr<BookmarkNode> node = parent->Remove(node_ptr);
925 RemoveNode(node_ptr, removed_urls);
[email protected]323dbf72013-03-30 17:08:33926 // RemoveNode adds an entry to removed_urls for each node of type URL. As we
927 // allow duplicates we need to remove any entries that are still bookmarked.
928 for (std::set<GURL>::iterator i = removed_urls->begin();
929 i != removed_urls->end();) {
930 if (IsBookmarkedNoLock(*i)) {
931 // When we erase the iterator pointing at the erasee is
932 // invalidated, so using i++ here within the "erase" call is
933 // important as it advances the iterator before passing the
934 // old value through to erase.
935 removed_urls->erase(i++);
936 } else {
937 ++i;
938 }
939 }
avicee78e4e2016-09-30 17:08:14940
941 return node;
[email protected]323dbf72013-03-30 17:08:33942}
943
[email protected]d8e41ed2008-09-11 15:22:32944BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
945 int index,
avicee78e4e2016-09-30 17:08:14946 std::unique_ptr<BookmarkNode> node) {
947 BookmarkNode* node_ptr = node.get();
948 parent->Add(std::move(node), index);
initial.commit09911bf2008-07-26 23:55:29949
[email protected]f25387b2008-08-21 15:20:33950 if (store_.get())
951 store_->ScheduleSave();
952
jianli14436d52015-10-09 22:47:35953 {
danduongf4fde322014-11-04 18:56:56954 base::AutoLock url_lock(url_lock_);
avicee78e4e2016-09-30 17:08:14955 AddNodeToInternalMaps(node_ptr);
danduongf4fde322014-11-04 18:56:56956 }
957
tfarina2fa1d2fb2016-10-19 01:44:31958 for (BookmarkModelObserver& observer : observers_)
959 observer.BookmarkNodeAdded(this, parent, index);
[email protected]f25387b2008-08-21 15:20:33960
avicee78e4e2016-09-30 17:08:14961 return node_ptr;
initial.commit09911bf2008-07-26 23:55:29962}
963
danduongf4fde322014-11-04 18:56:56964void BookmarkModel::AddNodeToInternalMaps(BookmarkNode* node) {
danduongf4fde322014-11-04 18:56:56965 url_lock_.AssertAcquired();
jianli14436d52015-10-09 22:47:35966 if (node->is_url()) {
967 index_->Add(node);
968 nodes_ordered_by_url_set_.insert(node);
969 }
970 for (int i = 0; i < node->child_count(); ++i)
971 AddNodeToInternalMaps(node->GetChild(i));
danduongf4fde322014-11-04 18:56:56972}
973
[email protected]b3c33d462009-06-26 22:29:20974bool BookmarkModel::IsValidIndex(const BookmarkNode* parent,
[email protected]d8e41ed2008-09-11 15:22:32975 int index,
976 bool allow_end) {
[email protected]776e7492008-10-23 16:47:41977 return (parent && parent->is_folder() &&
[email protected]9c1a75a2011-03-10 02:38:12978 (index >= 0 && (index < parent->child_count() ||
979 (allow_end && index == parent->child_count()))));
[email protected]bd1b96702009-07-08 21:54:14980}
[email protected]f25387b2008-08-21 15:20:33981
[email protected]bc770a032011-12-12 17:35:30982BookmarkPermanentNode* BookmarkModel::CreatePermanentNode(
983 BookmarkNode::Type type) {
[email protected]e1f76c62011-06-30 20:15:39984 DCHECK(type == BookmarkNode::BOOKMARK_BAR ||
985 type == BookmarkNode::OTHER_NODE ||
[email protected]37bc9132011-12-01 22:29:29986 type == BookmarkNode::MOBILE);
[email protected]bc770a032011-12-12 17:35:30987 BookmarkPermanentNode* node =
988 new BookmarkPermanentNode(generate_next_node_id());
[email protected]043a76d2014-06-05 16:36:24989 node->set_type(type);
990 node->set_visible(client_->IsPermanentNodeVisible(node));
[email protected]bc770a032011-12-12 17:35:30991
992 int title_id;
993 switch (type) {
994 case BookmarkNode::BOOKMARK_BAR:
995 title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
996 break;
997 case BookmarkNode::OTHER_NODE:
998 title_id = IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME;
999 break;
1000 case BookmarkNode::MOBILE:
1001 title_id = IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME;
1002 break;
1003 default:
[email protected]97fdd162011-12-03 20:50:121004 NOTREACHED();
[email protected]bc770a032011-12-12 17:35:301005 title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
1006 break;
[email protected]7caca8a22010-08-21 18:25:311007 }
[email protected]0491ff72011-12-30 00:45:591008 node->SetTitle(l10n_util::GetStringUTF16(title_id));
initial.commit09911bf2008-07-26 23:55:291009 return node;
1010}
1011
[email protected]abc2f262011-03-15 21:15:441012void BookmarkModel::OnFaviconDataAvailable(
[email protected]0ea3db52012-12-07 01:32:011013 BookmarkNode* node,
[email protected]504fca82014-05-07 22:48:081014 favicon_base::IconType icon_type,
[email protected]7627e0b42014-04-17 17:20:531015 const favicon_base::FaviconImageResult& image_result) {
[email protected]4167c3a2008-08-21 18:12:201016 DCHECK(node);
[email protected]e95b717f2014-02-06 13:47:131017 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
[email protected]bcc38612012-10-23 01:10:271018 node->set_favicon_state(BookmarkNode::LOADED_FAVICON);
[email protected]65baa222012-08-30 15:43:511019 if (!image_result.image.IsEmpty()) {
[email protected]504fca82014-05-07 22:48:081020 node->set_favicon_type(icon_type);
[email protected]65baa222012-08-30 15:43:511021 node->set_favicon(image_result.image);
[email protected]2ad0e872012-11-30 01:24:461022 node->set_icon_url(image_result.icon_url);
[email protected]65baa222012-08-30 15:43:511023 FaviconLoaded(node);
[email protected]504fca82014-05-07 22:48:081024 } else if (icon_type == favicon_base::TOUCH_ICON) {
1025 // Couldn't load the touch icon, fallback to the regular favicon.
1026 DCHECK(client_->PreferTouchIcon());
1027 LoadFavicon(node, favicon_base::FAVICON);
initial.commit09911bf2008-07-26 23:55:291028 }
1029}
1030
tfarinac0baf0b2014-12-08 18:01:211031void BookmarkModel::LoadFavicon(BookmarkNode* node,
1032 favicon_base::IconType icon_type) {
[email protected]0890e60e2011-06-27 14:55:211033 if (node->is_folder())
initial.commit09911bf2008-07-26 23:55:291034 return;
1035
[email protected]5d4077542011-07-21 20:24:071036 DCHECK(node->url().is_valid());
[email protected]504fca82014-05-07 22:48:081037 node->set_favicon_state(BookmarkNode::LOADING_FAVICON);
[email protected]25244a932014-07-12 23:00:241038 base::CancelableTaskTracker::TaskId taskId =
1039 client_->GetFaviconImageForPageURL(
1040 node->url(),
1041 icon_type,
1042 base::Bind(
1043 &BookmarkModel::OnFaviconDataAvailable,
1044 base::Unretained(this),
1045 node,
1046 icon_type),
1047 &cancelable_task_tracker_);
[email protected]6a848b52014-04-26 22:06:541048 if (taskId != base::CancelableTaskTracker::kBadTaskId)
1049 node->set_favicon_load_task_id(taskId);
initial.commit09911bf2008-07-26 23:55:291050}
1051
[email protected]5b5c9b7f32011-07-21 01:07:181052void BookmarkModel::FaviconLoaded(const BookmarkNode* node) {
tfarina2fa1d2fb2016-10-19 01:44:311053 for (BookmarkModelObserver& observer : observers_)
1054 observer.BookmarkNodeFaviconChanged(this, node);
[email protected]5b5c9b7f32011-07-21 01:07:181055}
1056
[email protected]abc2f262011-03-15 21:15:441057void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) {
[email protected]e95b717f2014-02-06 13:47:131058 if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) {
[email protected]0ea3db52012-12-07 01:32:011059 cancelable_task_tracker_.TryCancel(node->favicon_load_task_id());
[email protected]e95b717f2014-02-06 13:47:131060 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
initial.commit09911bf2008-07-26 23:55:291061 }
1062}
1063
[email protected]d8e41ed2008-09-11 15:22:321064void BookmarkModel::PopulateNodesByURL(BookmarkNode* node) {
[email protected]90ef13132008-08-27 03:27:461065 // NOTE: this is called with url_lock_ already held. As such, this doesn't
1066 // explicitly grab the lock.
[email protected]f25387b2008-08-21 15:20:331067 if (node->is_url())
1068 nodes_ordered_by_url_set_.insert(node);
[email protected]9c1a75a2011-03-10 02:38:121069 for (int i = 0; i < node->child_count(); ++i)
[email protected]f25387b2008-08-21 15:20:331070 PopulateNodesByURL(node->GetChild(i));
1071}
[email protected]4d89f382009-05-12 06:56:491072
avibc5337b2015-12-25 23:16:331073int64_t BookmarkModel::generate_next_node_id() {
[email protected]4d89f382009-05-12 06:56:491074 return next_node_id_++;
1075}
[email protected]01eec882009-05-22 18:13:281076
dchengacd3f522016-04-21 22:30:411077std::unique_ptr<BookmarkLoadDetails> BookmarkModel::CreateLoadDetails() {
[email protected]bc770a032011-12-12 17:35:301078 BookmarkPermanentNode* bb_node =
1079 CreatePermanentNode(BookmarkNode::BOOKMARK_BAR);
1080 BookmarkPermanentNode* other_node =
1081 CreatePermanentNode(BookmarkNode::OTHER_NODE);
1082 BookmarkPermanentNode* mobile_node =
1083 CreatePermanentNode(BookmarkNode::MOBILE);
mattreynolds191b88722016-12-13 19:25:321084 std::unique_ptr<TitledUrlNodeSorter> node_sorter =
1085 base::MakeUnique<TypedCountSorter>(client_.get());
dchengacd3f522016-04-21 22:30:411086 return std::unique_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails(
1087 bb_node, other_node, mobile_node, client_->GetLoadExtraNodesCallback(),
mattreynolds25e9a312016-12-14 21:52:131088 new TitledUrlIndex(std::move(node_sorter)), next_node_id_));
[email protected]01eec882009-05-22 18:13:281089}
tfarinaa0ec34e2015-01-12 18:46:481090
jianli14436d52015-10-09 22:47:351091void BookmarkModel::SetUndoDelegate(BookmarkUndoDelegate* undo_delegate) {
1092 undo_delegate_ = undo_delegate;
1093 if (undo_delegate_)
1094 undo_delegate_->SetUndoProvider(this);
1095}
1096
1097BookmarkUndoDelegate* BookmarkModel::undo_delegate() const {
1098 return undo_delegate_ ? undo_delegate_ : empty_undo_delegate_.get();
1099}
1100
tfarinaa0ec34e2015-01-12 18:46:481101} // namespace bookmarks