blob: 147ea6eb6de3fae1462cc86562f2da54b59c3b27 [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>
Gyuyoung Kim6afb5082018-01-19 13:35:579#include <memory>
Mikel Astiz55b3fe202017-11-08 20:54:5010#include <string>
dcheng51606352015-12-26 21:16:2311#include <utility>
[email protected]4e425be42011-01-15 06:56:0912
[email protected]bbdd2982011-10-08 18:14:2413#include "base/bind.h"
14#include "base/bind_helpers.h"
[email protected]9a08fe82013-04-23 05:06:0515#include "base/i18n/string_compare.h"
[email protected]6a848b52014-04-26 22:06:5416#include "base/logging.h"
[email protected]996dbe82014-05-12 12:32:1817#include "base/macros.h"
pkotwiczca240dd2015-07-09 16:15:3218#include "base/metrics/histogram_macros.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"
Scott Violet8aa6d57602018-04-25 15:46:2129#include "components/bookmarks/browser/url_and_title.h"
Scott Violete349e962018-05-03 20:45:2330#include "components/bookmarks/common/bookmark_constants.h"
[email protected]7627e0b42014-04-17 17:20:5331#include "components/favicon_base/favicon_types.h"
thakisfe8fa0a2017-02-23 19:46:3632#include "components/strings/grit/components_strings.h"
[email protected]c051a1b2011-01-21 23:30:1733#include "ui/base/l10n/l10n_util.h"
[email protected]65baa222012-08-30 15:43:5134#include "ui/gfx/favicon_size.h"
initial.commit09911bf2008-07-26 23:55:2935
[email protected]e1acf6f2008-10-27 20:43:3336using base::Time;
tfarinaa0ec34e2015-01-12 18:46:4837
38namespace bookmarks {
[email protected]e1acf6f2008-10-27 20:43:3339
[email protected]b3c33d462009-06-26 22:29:2040namespace {
41
42// Helper to get a mutable bookmark node.
[email protected]7b084b02011-07-08 16:06:4843BookmarkNode* AsMutable(const BookmarkNode* node) {
[email protected]b3c33d462009-06-26 22:29:2044 return const_cast<BookmarkNode*>(node);
45}
46
[email protected]996dbe82014-05-12 12:32:1847// Helper to get a mutable permanent bookmark node.
48BookmarkPermanentNode* AsMutable(const BookmarkPermanentNode* node) {
49 return const_cast<BookmarkPermanentNode*>(node);
50}
51
52// Comparator used when sorting permanent nodes. Nodes that are initially
53// visible are sorted before nodes that are initially hidden.
vmpstr3abe3302016-03-09 19:38:1954class VisibilityComparator {
[email protected]996dbe82014-05-12 12:32:1855 public:
56 explicit VisibilityComparator(BookmarkClient* client) : client_(client) {}
57
avicee78e4e2016-09-30 17:08:1458 // Returns true if |n1| precedes |n2|.
Scott Violete349e962018-05-03 20:45:2359 bool operator()(const std::unique_ptr<BookmarkNode>& n1,
60 const std::unique_ptr<BookmarkNode>& n2) {
61 DCHECK(n1->is_permanent_node());
62 DCHECK(n2->is_permanent_node());
63 bool n1_visible = client_->IsPermanentNodeVisible(
64 static_cast<BookmarkPermanentNode*>(n1.get()));
65 bool n2_visible = client_->IsPermanentNodeVisible(
66 static_cast<BookmarkPermanentNode*>(n2.get()));
[email protected]996dbe82014-05-12 12:32:1867 return n1_visible != n2_visible && n1_visible;
68 }
69
70 private:
71 BookmarkClient* client_;
72};
73
[email protected]ef762642009-03-05 16:30:2574// Comparator used when sorting bookmarks. Folders are sorted first, then
[email protected]2c685cc22009-08-28 00:17:4475// bookmarks.
vmpstr3abe3302016-03-09 19:38:1976class SortComparator {
[email protected]ef762642009-03-05 16:30:2577 public:
[email protected]a48f87d2012-10-09 18:06:3378 explicit SortComparator(icu::Collator* collator) : collator_(collator) {}
[email protected]ef762642009-03-05 16:30:2579
avicee78e4e2016-09-30 17:08:1480 // Returns true if |n1| precedes |n2|.
81 bool operator()(const std::unique_ptr<BookmarkNode>& n1,
82 const std::unique_ptr<BookmarkNode>& n2) {
[email protected]037db002009-10-19 20:06:0883 if (n1->type() == n2->type()) {
[email protected]ef762642009-03-05 16:30:2584 // Types are the same, compare the names.
85 if (!collator_)
[email protected]440b37b22010-08-30 05:31:4086 return n1->GetTitle() < n2->GetTitle();
[email protected]9a08fe82013-04-23 05:06:0587 return base::i18n::CompareString16WithCollator(
estade1274f882015-04-11 05:13:3588 *collator_, n1->GetTitle(), n2->GetTitle()) == UCOL_LESS;
[email protected]ef762642009-03-05 16:30:2589 }
90 // Types differ, sort such that folders come first.
91 return n1->is_folder();
92 }
93
94 private:
[email protected]b5b2385a2009-08-18 05:12:2995 icu::Collator* collator_;
[email protected]ef762642009-03-05 16:30:2596};
97
jianli14436d52015-10-09 22:47:3598// Delegate that does nothing.
99class EmptyUndoDelegate : public BookmarkUndoDelegate {
100 public:
101 EmptyUndoDelegate() {}
102 ~EmptyUndoDelegate() override {}
103
104 private:
105 // BookmarkUndoDelegate:
106 void SetUndoProvider(BookmarkUndoProvider* provider) override {}
107 void OnBookmarkNodeRemoved(BookmarkModel* model,
108 const BookmarkNode* parent,
109 int index,
dchengacd3f522016-04-21 22:30:41110 std::unique_ptr<BookmarkNode> node) override {}
jianli14436d52015-10-09 22:47:35111
112 DISALLOW_COPY_AND_ASSIGN(EmptyUndoDelegate);
113};
114
Scott Violete349e962018-05-03 20:45:23115void FinishedLoadOnMainThread(
116 base::OnceCallback<void(std::unique_ptr<BookmarkLoadDetails>)> callback,
117 std::unique_ptr<BookmarkLoadDetails> details) {
118 std::move(callback).Run(std::move(details));
119}
120
121void DoLoadOnBackgroundThread(
122 const base::FilePath& profile_path,
123 scoped_refptr<base::SequencedTaskRunner> result_task_runner,
124 base::OnceCallback<void(std::unique_ptr<BookmarkLoadDetails>)> callback,
125 std::unique_ptr<BookmarkLoadDetails> details) {
126 LoadBookmarks(profile_path, details.get());
127 result_task_runner->PostTask(
128 FROM_HERE, base::BindOnce(&FinishedLoadOnMainThread, std::move(callback),
129 std::move(details)));
130}
131
[email protected]bc770a032011-12-12 17:35:30132} // namespace
[email protected]97fdd162011-12-03 20:50:12133
[email protected]97fdd162011-12-03 20:50:12134// BookmarkModel --------------------------------------------------------------
135
dchengacd3f522016-04-21 22:30:41136BookmarkModel::BookmarkModel(std::unique_ptr<BookmarkClient> client)
sdefresne070a5102016-02-01 13:42:14137 : client_(std::move(client)),
Scott Violete349e962018-05-03 20:45:23138 root_(std::make_unique<BookmarkNode>(GURL())),
François Degrosd6e2d7dd2017-11-22 05:37:02139 observers_(base::ObserverListPolicy::EXISTING_ONLY),
gab77f88322016-06-02 13:47:03140 loaded_signal_(base::WaitableEvent::ResetPolicy::MANUAL,
141 base::WaitableEvent::InitialState::NOT_SIGNALED),
Scott Violete349e962018-05-03 20:45:23142 empty_undo_delegate_(std::make_unique<EmptyUndoDelegate>()) {
[email protected]6a848b52014-04-26 22:06:54143 DCHECK(client_);
sdefresne070a5102016-02-01 13:42:14144 client_->Init(this);
initial.commit09911bf2008-07-26 23:55:29145}
146
[email protected]d8e41ed2008-09-11 15:22:32147BookmarkModel::~BookmarkModel() {
tfarina2fa1d2fb2016-10-19 01:44:31148 for (BookmarkModelObserver& observer : observers_)
149 observer.BookmarkModelBeingDeleted(this);
[email protected]3de6fd342008-09-05 02:44:51150
Zinovy Nisaa5aee392018-05-08 16:18:41151 if (store_) {
[email protected]f25387b2008-08-21 15:20:33152 // The store maintains a reference back to us. We need to tell it we're gone
153 // so that it doesn't try and invoke a method back on us again.
154 store_->BookmarkModelDeleted();
initial.commit09911bf2008-07-26 23:55:29155 }
156}
157
[email protected]f61f4782012-06-08 21:54:21158void BookmarkModel::Shutdown() {
[email protected]88e6a232011-09-14 14:53:20159 if (loaded_)
160 return;
161
[email protected]f61f4782012-06-08 21:54:21162 // See comment in HistoryService::ShutdownOnUIThread where this is invoked for
163 // details. It is also called when the BookmarkModel is deleted.
[email protected]88e6a232011-09-14 14:53:20164 loaded_signal_.Signal();
165}
166
[email protected]afecfb72013-04-18 17:17:33167void BookmarkModel::Load(
[email protected]6a848b52014-04-26 22:06:54168 PrefService* pref_service,
[email protected]6a848b52014-04-26 22:06:54169 const base::FilePath& profile_path,
170 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
171 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) {
Scott Violete349e962018-05-03 20:45:23172 // If the store is non-null, it means Load was already invoked. Load should
173 // only be invoked once.
174 DCHECK(!store_);
[email protected]90ef13132008-08-27 03:27:46175
Scott Violete349e962018-05-03 20:45:23176 expanded_state_tracker_ =
177 std::make_unique<BookmarkExpandedStateTracker>(this, pref_service);
[email protected]90ef13132008-08-27 03:27:46178
Scott Violete349e962018-05-03 20:45:23179 store_ = std::make_unique<BookmarkStorage>(this, profile_path,
180 io_task_runner.get());
181 auto done_loading_callback =
182 base::BindOnce(&BookmarkModel::DoneLoading, weak_factory_.GetWeakPtr());
183 io_task_runner->PostTask(
184 FROM_HERE,
185 base::BindOnce(&DoLoadOnBackgroundThread,
186 profile_path.Append(kBookmarksFileName), ui_task_runner,
187 std::move(done_loading_callback),
188 std::make_unique<BookmarkLoadDetails>(client_.get())));
[email protected]90ef13132008-08-27 03:27:46189}
190
[email protected]125b234182011-07-08 19:54:41191void BookmarkModel::AddObserver(BookmarkModelObserver* observer) {
192 observers_.AddObserver(observer);
193}
194
195void BookmarkModel::RemoveObserver(BookmarkModelObserver* observer) {
196 observers_.RemoveObserver(observer);
197}
198
[email protected]b68a8172012-02-17 00:25:18199void BookmarkModel::BeginExtensiveChanges() {
200 if (++extensive_changes_ == 1) {
tfarina2fa1d2fb2016-10-19 01:44:31201 for (BookmarkModelObserver& observer : observers_)
202 observer.ExtensiveBookmarkChangesBeginning(this);
[email protected]b68a8172012-02-17 00:25:18203 }
[email protected]125b234182011-07-08 19:54:41204}
205
[email protected]b68a8172012-02-17 00:25:18206void BookmarkModel::EndExtensiveChanges() {
207 --extensive_changes_;
208 DCHECK_GE(extensive_changes_, 0);
209 if (extensive_changes_ == 0) {
tfarina2fa1d2fb2016-10-19 01:44:31210 for (BookmarkModelObserver& observer : observers_)
211 observer.ExtensiveBookmarkChangesEnded(this);
[email protected]b68a8172012-02-17 00:25:18212 }
[email protected]125b234182011-07-08 19:54:41213}
214
[email protected]346453a2014-03-12 10:14:37215void BookmarkModel::BeginGroupedChanges() {
tfarina2fa1d2fb2016-10-19 01:44:31216 for (BookmarkModelObserver& observer : observers_)
217 observer.GroupedBookmarkChangesBeginning(this);
[email protected]346453a2014-03-12 10:14:37218}
219
220void BookmarkModel::EndGroupedChanges() {
tfarina2fa1d2fb2016-10-19 01:44:31221 for (BookmarkModelObserver& observer : observers_)
222 observer.GroupedBookmarkChangesEnded(this);
[email protected]346453a2014-03-12 10:14:37223}
224
deepak.m139312672015-05-04 16:29:43225void BookmarkModel::Remove(const BookmarkNode* node) {
tfarina16f92ed42015-06-12 13:54:36226 DCHECK(loaded_);
deepak.m139312672015-05-04 16:29:43227 DCHECK(node);
tfarina16f92ed42015-06-12 13:54:36228 DCHECK(!is_root_node(node));
deepak.m139312672015-05-04 16:29:43229 RemoveAndDeleteNode(AsMutable(node));
[email protected]f25387b2008-08-21 15:20:33230}
231
[email protected]5cd942208a2014-06-11 06:16:46232void BookmarkModel::RemoveAllUserBookmarks() {
[email protected]9109f8a12013-06-12 18:07:48233 std::set<GURL> removed_urls;
jianli14436d52015-10-09 22:47:35234 struct RemoveNodeData {
jianli14436d52015-10-09 22:47:35235 const BookmarkNode* parent;
236 int index;
avicee78e4e2016-09-30 17:08:14237 std::unique_ptr<BookmarkNode> node;
jianli14436d52015-10-09 22:47:35238 };
239 std::vector<RemoveNodeData> removed_node_data_list;
[email protected]472f95e2013-06-10 16:49:18240
tfarina2fa1d2fb2016-10-19 01:44:31241 for (BookmarkModelObserver& observer : observers_)
242 observer.OnWillRemoveAllUserBookmarks(this);
[email protected]472f95e2013-06-10 16:49:18243
[email protected]323dbf72013-03-30 17:08:33244 BeginExtensiveChanges();
245 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and
246 // its immediate children. For removing all non permanent nodes just remove
247 // all children of non-root permanent nodes.
248 {
249 base::AutoLock url_lock(url_lock_);
Scott Violete349e962018-05-03 20:45:23250 for (int i = 0; i < root_->child_count(); ++i) {
251 const BookmarkNode* permanent_node = root_->GetChild(i);
[email protected]043a76d2014-06-05 16:36:24252
[email protected]23e39692014-06-06 21:10:13253 if (!client_->CanBeEditedByUser(permanent_node))
[email protected]043a76d2014-06-05 16:36:24254 continue;
255
[email protected]323dbf72013-03-30 17:08:33256 for (int j = permanent_node->child_count() - 1; j >= 0; --j) {
avicee78e4e2016-09-30 17:08:14257 std::unique_ptr<BookmarkNode> node = RemoveNodeAndGetRemovedUrls(
258 AsMutable(permanent_node->GetChild(j)), &removed_urls);
259 removed_node_data_list.push_back({permanent_node, j, std::move(node)});
[email protected]323dbf72013-03-30 17:08:33260 }
261 }
262 }
263 EndExtensiveChanges();
Zinovy Nisaa5aee392018-05-08 16:18:41264 if (store_)
[email protected]323dbf72013-03-30 17:08:33265 store_->ScheduleSave();
266
tfarina2fa1d2fb2016-10-19 01:44:31267 for (BookmarkModelObserver& observer : observers_)
268 observer.BookmarkAllUserNodesRemoved(this, removed_urls);
jianli14436d52015-10-09 22:47:35269
270 BeginGroupedChanges();
avicee78e4e2016-09-30 17:08:14271 for (auto& removed_node_data : removed_node_data_list) {
272 undo_delegate()->OnBookmarkNodeRemoved(this, removed_node_data.parent,
273 removed_node_data.index,
274 std::move(removed_node_data.node));
jianli14436d52015-10-09 22:47:35275 }
276 EndGroupedChanges();
[email protected]5cd942208a2014-06-11 06:16:46277}
278
[email protected]b3c33d462009-06-26 22:29:20279void BookmarkModel::Move(const BookmarkNode* node,
280 const BookmarkNode* new_parent,
[email protected]d8e41ed2008-09-11 15:22:32281 int index) {
[email protected]f25387b2008-08-21 15:20:33282 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
[email protected]6b4d64c2011-07-29 21:33:24283 is_root_node(new_parent) || is_permanent_node(node)) {
initial.commit09911bf2008-07-26 23:55:29284 NOTREACHED();
285 return;
286 }
287
288 if (new_parent->HasAncestor(node)) {
289 // Can't make an ancestor of the node be a child of the node.
290 NOTREACHED();
291 return;
292 }
293
[email protected]2d48ee842011-03-08 23:27:29294 const BookmarkNode* old_parent = node->parent();
[email protected]368f3a72011-03-08 17:17:48295 int old_index = old_parent->GetIndexOf(node);
initial.commit09911bf2008-07-26 23:55:29296
297 if (old_parent == new_parent &&
298 (index == old_index || index == old_index + 1)) {
299 // Node is already in this position, nothing to do.
300 return;
301 }
302
[email protected]9e583642012-12-05 02:48:32303 SetDateFolderModified(new_parent, Time::Now());
304
initial.commit09911bf2008-07-26 23:55:29305 if (old_parent == new_parent && index > old_index)
306 index--;
avicee78e4e2016-09-30 17:08:14307
308 BookmarkNode* mutable_old_parent = AsMutable(old_parent);
309 std::unique_ptr<BookmarkNode> owned_node =
310 mutable_old_parent->Remove(AsMutable(node));
[email protected]b3c33d462009-06-26 22:29:20311 BookmarkNode* mutable_new_parent = AsMutable(new_parent);
avicee78e4e2016-09-30 17:08:14312 mutable_new_parent->Add(std::move(owned_node), index);
initial.commit09911bf2008-07-26 23:55:29313
Zinovy Nisaa5aee392018-05-08 16:18:41314 if (store_)
[email protected]f25387b2008-08-21 15:20:33315 store_->ScheduleSave();
316
tfarina2fa1d2fb2016-10-19 01:44:31317 for (BookmarkModelObserver& observer : observers_)
318 observer.BookmarkNodeMoved(this, old_parent, old_index, new_parent, index);
initial.commit09911bf2008-07-26 23:55:29319}
320
[email protected]4e187ef652010-03-11 05:21:35321void BookmarkModel::Copy(const BookmarkNode* node,
322 const BookmarkNode* new_parent,
323 int index) {
324 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
[email protected]6b4d64c2011-07-29 21:33:24325 is_root_node(new_parent) || is_permanent_node(node)) {
[email protected]4e187ef652010-03-11 05:21:35326 NOTREACHED();
327 return;
328 }
329
330 if (new_parent->HasAncestor(node)) {
331 // Can't make an ancestor of the node be a child of the node.
332 NOTREACHED();
333 return;
334 }
335
[email protected]c6a7a3d2011-03-12 01:04:30336 SetDateFolderModified(new_parent, Time::Now());
[email protected]67a8ae42013-05-20 09:42:39337 BookmarkNodeData drag_data(node);
[email protected]b1864502010-11-13 00:55:51338 // CloneBookmarkNode will use BookmarkModel methods to do the job, so we
[email protected]1a566fae2010-04-16 01:05:06339 // don't need to send notifications here.
tfarina8f3c40cc2015-01-20 21:22:50340 CloneBookmarkNode(this, drag_data.elements, new_parent, index, true);
[email protected]4e187ef652010-03-11 05:21:35341
Zinovy Nisaa5aee392018-05-08 16:18:41342 if (store_)
[email protected]4e187ef652010-03-11 05:21:35343 store_->ScheduleSave();
[email protected]4e187ef652010-03-11 05:21:35344}
345
[email protected]6a4e5a02012-06-26 19:47:48346const gfx::Image& BookmarkModel::GetFavicon(const BookmarkNode* node) {
[email protected]ea2e5aa52009-05-20 18:01:28347 DCHECK(node);
[email protected]bcc38612012-10-23 01:10:27348 if (node->favicon_state() == BookmarkNode::INVALID_FAVICON) {
[email protected]b3c33d462009-06-26 22:29:20349 BookmarkNode* mutable_node = AsMutable(node);
Mikel Astiza5ea2552017-11-06 22:50:15350 LoadFavicon(mutable_node, client_->PreferTouchIcon()
351 ? favicon_base::IconType::kTouchIcon
352 : favicon_base::IconType::kFavicon);
[email protected]ea2e5aa52009-05-20 18:01:28353 }
354 return node->favicon();
355}
356
[email protected]504fca82014-05-07 22:48:08357favicon_base::IconType BookmarkModel::GetFaviconType(const BookmarkNode* node) {
358 DCHECK(node);
359 return node->favicon_type();
360}
361
[email protected]6a848b52014-04-26 22:06:54362void BookmarkModel::SetTitle(const BookmarkNode* node,
363 const base::string16& title) {
tfarina5ebd5362015-05-12 21:50:10364 DCHECK(node);
365
[email protected]0491ff72011-12-30 00:45:59366 if (node->GetTitle() == title)
initial.commit09911bf2008-07-26 23:55:29367 return;
[email protected]f25387b2008-08-21 15:20:33368
[email protected]043a76d2014-06-05 16:36:24369 if (is_permanent_node(node) && !client_->CanSetPermanentNodeTitle(node)) {
[email protected]baf4f922009-10-19 16:44:07370 NOTREACHED();
371 return;
372 }
373
tfarina2fa1d2fb2016-10-19 01:44:31374 for (BookmarkModelObserver& observer : observers_)
375 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18376
[email protected]85d911c2009-05-19 03:59:42377 // The title index doesn't support changing the title, instead we remove then
Matt Reynoldse33ab142017-11-09 03:06:48378 // add it back. Only do this for URL nodes. A directory node can have its
379 // title changed but should be excluded from the index.
380 if (node->is_url())
381 index_->Remove(node);
[email protected]0491ff72011-12-30 00:45:59382 AsMutable(node)->SetTitle(title);
Matt Reynoldse33ab142017-11-09 03:06:48383 if (node->is_url())
384 index_->Add(node);
[email protected]85d911c2009-05-19 03:59:42385
Zinovy Nisaa5aee392018-05-08 16:18:41386 if (store_)
[email protected]f25387b2008-08-21 15:20:33387 store_->ScheduleSave();
388
tfarina2fa1d2fb2016-10-19 01:44:31389 for (BookmarkModelObserver& observer : observers_)
390 observer.BookmarkNodeChanged(this, node);
initial.commit09911bf2008-07-26 23:55:29391}
392
[email protected]e5486602010-02-09 21:27:55393void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) {
tfarina5ebd5362015-05-12 21:50:10394 DCHECK(node && !node->is_folder());
[email protected]e5486602010-02-09 21:27:55395
[email protected]5d4077542011-07-21 20:24:07396 if (node->url() == url)
[email protected]e5486602010-02-09 21:27:55397 return;
398
[email protected]5b5c9b7f32011-07-21 01:07:18399 BookmarkNode* mutable_node = AsMutable(node);
400 mutable_node->InvalidateFavicon();
401 CancelPendingFaviconLoadRequests(mutable_node);
[email protected]e5486602010-02-09 21:27:55402
tfarina2fa1d2fb2016-10-19 01:44:31403 for (BookmarkModelObserver& observer : observers_)
404 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18405
[email protected]e5486602010-02-09 21:27:55406 {
[email protected]20305ec2011-01-21 04:55:52407 base::AutoLock url_lock(url_lock_);
danduongf4fde322014-11-04 18:56:56408 RemoveNodeFromInternalMaps(mutable_node);
[email protected]5d4077542011-07-21 20:24:07409 mutable_node->set_url(url);
danduongf4fde322014-11-04 18:56:56410 AddNodeToInternalMaps(mutable_node);
[email protected]e5486602010-02-09 21:27:55411 }
412
Zinovy Nisaa5aee392018-05-08 16:18:41413 if (store_)
[email protected]e5486602010-02-09 21:27:55414 store_->ScheduleSave();
415
tfarina2fa1d2fb2016-10-19 01:44:31416 for (BookmarkModelObserver& observer : observers_)
417 observer.BookmarkNodeChanged(this, node);
[email protected]e5486602010-02-09 21:27:55418}
419
[email protected]1858410f2012-10-26 05:06:45420void BookmarkModel::SetNodeMetaInfo(const BookmarkNode* node,
421 const std::string& key,
422 const std::string& value) {
[email protected]39e113452013-11-26 00:43:06423 std::string old_value;
424 if (node->GetMetaInfo(key, &old_value) && old_value == value)
425 return;
426
tfarina2fa1d2fb2016-10-19 01:44:31427 for (BookmarkModelObserver& observer : observers_)
428 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40429
[email protected]1858410f2012-10-26 05:06:45430 if (AsMutable(node)->SetMetaInfo(key, value) && store_.get())
431 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40432
tfarina2fa1d2fb2016-10-19 01:44:31433 for (BookmarkModelObserver& observer : observers_)
434 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45435}
436
[email protected]e38a87d2013-12-05 01:35:18437void BookmarkModel::SetNodeMetaInfoMap(
438 const BookmarkNode* node,
439 const BookmarkNode::MetaInfoMap& meta_info_map) {
440 const BookmarkNode::MetaInfoMap* old_meta_info_map = node->GetMetaInfoMap();
441 if ((!old_meta_info_map && meta_info_map.empty()) ||
442 (old_meta_info_map && meta_info_map == *old_meta_info_map))
443 return;
444
tfarina2fa1d2fb2016-10-19 01:44:31445 for (BookmarkModelObserver& observer : observers_)
446 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]e38a87d2013-12-05 01:35:18447
448 AsMutable(node)->SetMetaInfoMap(meta_info_map);
Zinovy Nisaa5aee392018-05-08 16:18:41449 if (store_)
[email protected]e38a87d2013-12-05 01:35:18450 store_->ScheduleSave();
451
tfarina2fa1d2fb2016-10-19 01:44:31452 for (BookmarkModelObserver& observer : observers_)
453 observer.BookmarkMetaInfoChanged(this, node);
[email protected]e38a87d2013-12-05 01:35:18454}
455
[email protected]1858410f2012-10-26 05:06:45456void BookmarkModel::DeleteNodeMetaInfo(const BookmarkNode* node,
457 const std::string& key) {
[email protected]39e113452013-11-26 00:43:06458 const BookmarkNode::MetaInfoMap* meta_info_map = node->GetMetaInfoMap();
459 if (!meta_info_map || meta_info_map->find(key) == meta_info_map->end())
460 return;
461
tfarina2fa1d2fb2016-10-19 01:44:31462 for (BookmarkModelObserver& observer : observers_)
463 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40464
[email protected]1858410f2012-10-26 05:06:45465 if (AsMutable(node)->DeleteMetaInfo(key) && store_.get())
466 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40467
tfarina2fa1d2fb2016-10-19 01:44:31468 for (BookmarkModelObserver& observer : observers_)
469 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45470}
471
rfevangd75d32212014-12-06 01:27:22472void BookmarkModel::AddNonClonedKey(const std::string& key) {
473 non_cloned_keys_.insert(key);
474}
475
[email protected]39e113452013-11-26 00:43:06476void BookmarkModel::SetNodeSyncTransactionVersion(
477 const BookmarkNode* node,
avibc5337b2015-12-25 23:16:33478 int64_t sync_transaction_version) {
[email protected]043a76d2014-06-05 16:36:24479 DCHECK(client_->CanSyncNode(node));
480
[email protected]39e113452013-11-26 00:43:06481 if (sync_transaction_version == node->sync_transaction_version())
482 return;
483
484 AsMutable(node)->set_sync_transaction_version(sync_transaction_version);
Zinovy Nisaa5aee392018-05-08 16:18:41485 if (store_)
[email protected]39e113452013-11-26 00:43:06486 store_->ScheduleSave();
487}
488
pkotwiczca240dd2015-07-09 16:15:32489void BookmarkModel::OnFaviconsChanged(const std::set<GURL>& page_urls,
490 const GURL& icon_url) {
491 std::set<const BookmarkNode*> to_update;
492 for (const GURL& page_url : page_urls) {
[email protected]6a848b52014-04-26 22:06:54493 std::vector<const BookmarkNode*> nodes;
pkotwiczca240dd2015-07-09 16:15:32494 GetNodesByURL(page_url, &nodes);
495 to_update.insert(nodes.begin(), nodes.end());
496 }
497
498 if (!icon_url.is_empty()) {
499 // Log Histogram to determine how often |icon_url| is non empty in
500 // practice.
501 // TODO(pkotwicz): Do something more efficient if |icon_url| is non-empty
502 // many times a day for each user.
503 UMA_HISTOGRAM_BOOLEAN("Bookmarks.OnFaviconsChangedIconURL", true);
504
505 base::AutoLock url_lock(url_lock_);
506 for (const BookmarkNode* node : nodes_ordered_by_url_set_) {
ssid144fb7b82017-06-01 02:32:26507 if (node->icon_url() && icon_url == *node->icon_url())
pkotwiczca240dd2015-07-09 16:15:32508 to_update.insert(node);
[email protected]6a848b52014-04-26 22:06:54509 }
510 }
pkotwiczca240dd2015-07-09 16:15:32511
512 for (const BookmarkNode* node : to_update) {
513 // Rerequest the favicon.
514 BookmarkNode* mutable_node = AsMutable(node);
515 mutable_node->InvalidateFavicon();
516 CancelPendingFaviconLoadRequests(mutable_node);
tfarina2fa1d2fb2016-10-19 01:44:31517 for (BookmarkModelObserver& observer : observers_)
518 observer.BookmarkNodeFaviconChanged(this, node);
pkotwiczca240dd2015-07-09 16:15:32519 }
[email protected]6a848b52014-04-26 22:06:54520}
521
tfarina5ebd5362015-05-12 21:50:10522void BookmarkModel::SetDateAdded(const BookmarkNode* node, Time date_added) {
523 DCHECK(node && !is_permanent_node(node));
[email protected]b61445c2012-10-27 00:11:42524
525 if (node->date_added() == date_added)
526 return;
527
[email protected]b61445c2012-10-27 00:11:42528 AsMutable(node)->set_date_added(date_added);
529
530 // Syncing might result in dates newer than the folder's last modified date.
531 if (date_added > node->parent()->date_folder_modified()) {
532 // Will trigger store_->ScheduleSave().
533 SetDateFolderModified(node->parent(), date_added);
Zinovy Nisaa5aee392018-05-08 16:18:41534 } else if (store_) {
[email protected]b61445c2012-10-27 00:11:42535 store_->ScheduleSave();
536 }
537}
538
[email protected]848cd05e2008-09-19 18:33:48539void BookmarkModel::GetNodesByURL(const GURL& url,
[email protected]b3c33d462009-06-26 22:29:20540 std::vector<const BookmarkNode*>* nodes) {
[email protected]20305ec2011-01-21 04:55:52541 base::AutoLock url_lock(url_lock_);
[email protected]ea2e5aa52009-05-20 18:01:28542 BookmarkNode tmp_node(url);
initial.commit09911bf2008-07-26 23:55:29543 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node);
[email protected]5d4077542011-07-21 20:24:07544 while (i != nodes_ordered_by_url_set_.end() && (*i)->url() == url) {
[email protected]848cd05e2008-09-19 18:33:48545 nodes->push_back(*i);
546 ++i;
547 }
548}
549
[email protected]23e39692014-06-06 21:10:13550const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL(
[email protected]b3c33d462009-06-26 22:29:20551 const GURL& url) {
552 std::vector<const BookmarkNode*> nodes;
[email protected]848cd05e2008-09-19 18:33:48553 GetNodesByURL(url, &nodes);
tfarinaa0ec34e2015-01-12 18:46:48554 std::sort(nodes.begin(), nodes.end(), &MoreRecentlyAdded);
[email protected]23e39692014-06-06 21:10:13555
556 // Look for the first node that the user can edit.
557 for (size_t i = 0; i < nodes.size(); ++i) {
558 if (client_->CanBeEditedByUser(nodes[i]))
559 return nodes[i];
560 }
561
Ivan Kotenkov75b1c3a2017-10-24 14:47:24562 return nullptr;
initial.commit09911bf2008-07-26 23:55:29563}
564
[email protected]cf8e8172011-07-23 00:46:24565bool BookmarkModel::HasBookmarks() {
566 base::AutoLock url_lock(url_lock_);
567 return !nodes_ordered_by_url_set_.empty();
568}
569
Marti Wongc67da222017-09-01 02:30:01570bool BookmarkModel::HasNoUserCreatedBookmarksOrFolders() {
571 return bookmark_bar_node_->empty() && other_node_->empty() &&
572 mobile_node_->empty();
573}
574
[email protected]cf8e8172011-07-23 00:46:24575bool BookmarkModel::IsBookmarked(const GURL& url) {
576 base::AutoLock url_lock(url_lock_);
577 return IsBookmarkedNoLock(url);
578}
579
Scott Violet8aa6d57602018-04-25 15:46:21580void BookmarkModel::GetBookmarks(std::vector<UrlAndTitle>* bookmarks) {
[email protected]20305ec2011-01-21 04:55:52581 base::AutoLock url_lock(url_lock_);
Ivan Kotenkov75b1c3a2017-10-24 14:47:24582 const GURL* last_url = nullptr;
[email protected]90ef13132008-08-27 03:27:46583 for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin();
584 i != nodes_ordered_by_url_set_.end(); ++i) {
[email protected]5d4077542011-07-21 20:24:07585 const GURL* url = &((*i)->url());
[email protected]848cd05e2008-09-19 18:33:48586 // Only add unique URLs.
[email protected]0f7bee52012-08-06 20:04:17587 if (!last_url || *url != *last_url) {
Scott Violet8aa6d57602018-04-25 15:46:21588 UrlAndTitle bookmark;
[email protected]0f7bee52012-08-06 20:04:17589 bookmark.url = *url;
590 bookmark.title = (*i)->GetTitle();
591 bookmarks->push_back(bookmark);
592 }
[email protected]848cd05e2008-09-19 18:33:48593 last_url = url;
[email protected]90ef13132008-08-27 03:27:46594 }
595}
596
[email protected]cf8e8172011-07-23 00:46:24597void BookmarkModel::BlockTillLoaded() {
598 loaded_signal_.Wait();
[email protected]848cd05e2008-09-19 18:33:48599}
600
[email protected]39703292011-03-18 17:03:40601const BookmarkNode* BookmarkModel::AddFolder(const BookmarkNode* parent,
602 int index,
[email protected]96920152013-12-04 21:00:16603 const base::string16& title) {
Ivan Kotenkov75b1c3a2017-10-24 14:47:24604 return AddFolderWithMetaInfo(parent, index, title, nullptr);
[email protected]eb59ad12014-04-24 00:05:08605}
606const BookmarkNode* BookmarkModel::AddFolderWithMetaInfo(
607 const BookmarkNode* parent,
608 int index,
609 const base::string16& title,
610 const BookmarkNode::MetaInfoMap* meta_info) {
[email protected]6b4d64c2011-07-29 21:33:24611 if (!loaded_ || is_root_node(parent) || !IsValidIndex(parent, index, true)) {
initial.commit09911bf2008-07-26 23:55:29612 // Can't add to the root.
613 NOTREACHED();
Ivan Kotenkov75b1c3a2017-10-24 14:47:24614 return nullptr;
initial.commit09911bf2008-07-26 23:55:29615 }
616
avicee78e4e2016-09-30 17:08:14617 std::unique_ptr<BookmarkNode> new_node =
Jinho Bangbefb1c22018-01-16 18:40:10618 std::make_unique<BookmarkNode>(generate_next_node_id(), GURL());
[email protected]edb63cc2011-03-11 02:00:41619 new_node->set_date_folder_modified(Time::Now());
[email protected]aee236542011-12-01 04:34:03620 // Folders shouldn't have line breaks in their titles.
[email protected]0491ff72011-12-30 00:45:59621 new_node->SetTitle(title);
[email protected]037db002009-10-19 20:06:08622 new_node->set_type(BookmarkNode::FOLDER);
[email protected]eb59ad12014-04-24 00:05:08623 if (meta_info)
624 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29625
avicee78e4e2016-09-30 17:08:14626 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29627}
628
[email protected]e64e9012010-01-11 23:10:55629const BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent,
630 int index,
[email protected]96920152013-12-04 21:00:16631 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55632 const GURL& url) {
Ivan Kotenkov75b1c3a2017-10-24 14:47:24633 return AddURLWithCreationTimeAndMetaInfo(parent, index, title, url,
634 Time::Now(), nullptr);
initial.commit09911bf2008-07-26 23:55:29635}
636
[email protected]eb59ad12014-04-24 00:05:08637const BookmarkNode* BookmarkModel::AddURLWithCreationTimeAndMetaInfo(
[email protected]e64e9012010-01-11 23:10:55638 const BookmarkNode* parent,
639 int index,
[email protected]96920152013-12-04 21:00:16640 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55641 const GURL& url,
[email protected]eb59ad12014-04-24 00:05:08642 const Time& creation_time,
643 const BookmarkNode::MetaInfoMap* meta_info) {
[email protected]6b4d64c2011-07-29 21:33:24644 if (!loaded_ || !url.is_valid() || is_root_node(parent) ||
[email protected]f25387b2008-08-21 15:20:33645 !IsValidIndex(parent, index, true)) {
initial.commit09911bf2008-07-26 23:55:29646 NOTREACHED();
Ivan Kotenkov75b1c3a2017-10-24 14:47:24647 return nullptr;
initial.commit09911bf2008-07-26 23:55:29648 }
initial.commit09911bf2008-07-26 23:55:29649
[email protected]b61445c2012-10-27 00:11:42650 // Syncing may result in dates newer than the last modified date.
[email protected]8ad613b2012-10-12 21:28:45651 if (creation_time > parent->date_folder_modified())
652 SetDateFolderModified(parent, creation_time);
initial.commit09911bf2008-07-26 23:55:29653
avicee78e4e2016-09-30 17:08:14654 std::unique_ptr<BookmarkNode> new_node =
Jinho Bangbefb1c22018-01-16 18:40:10655 std::make_unique<BookmarkNode>(generate_next_node_id(), url);
[email protected]0491ff72011-12-30 00:45:59656 new_node->SetTitle(title);
[email protected]b3c33d462009-06-26 22:29:20657 new_node->set_date_added(creation_time);
[email protected]037db002009-10-19 20:06:08658 new_node->set_type(BookmarkNode::URL);
[email protected]eb59ad12014-04-24 00:05:08659 if (meta_info)
660 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29661
avicee78e4e2016-09-30 17:08:14662 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29663}
664
[email protected]b3c33d462009-06-26 22:29:20665void BookmarkModel::SortChildren(const BookmarkNode* parent) {
[email protected]23e39692014-06-06 21:10:13666 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24667
[email protected]6b4d64c2011-07-29 21:33:24668 if (!parent || !parent->is_folder() || is_root_node(parent) ||
[email protected]9c1a75a2011-03-10 02:38:12669 parent->child_count() <= 1) {
[email protected]e2f86d92009-02-25 00:22:01670 return;
671 }
672
tfarina2fa1d2fb2016-10-19 01:44:31673 for (BookmarkModelObserver& observer : observers_)
674 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18675
[email protected]ef762642009-03-05 16:30:25676 UErrorCode error = U_ZERO_ERROR;
dchengacd3f522016-04-21 22:30:41677 std::unique_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
[email protected]ef762642009-03-05 16:30:25678 if (U_FAILURE(error))
Ivan Kotenkov75b1c3a2017-10-24 14:47:24679 collator.reset(nullptr);
[email protected]b3c33d462009-06-26 22:29:20680 BookmarkNode* mutable_parent = AsMutable(parent);
681 std::sort(mutable_parent->children().begin(),
682 mutable_parent->children().end(),
[email protected]ef762642009-03-05 16:30:25683 SortComparator(collator.get()));
[email protected]e2f86d92009-02-25 00:22:01684
Zinovy Nisaa5aee392018-05-08 16:18:41685 if (store_)
[email protected]997a0362009-03-12 03:10:51686 store_->ScheduleSave();
687
tfarina2fa1d2fb2016-10-19 01:44:31688 for (BookmarkModelObserver& observer : observers_)
689 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]e2f86d92009-02-25 00:22:01690}
691
[email protected]472f95e2013-06-10 16:49:18692void BookmarkModel::ReorderChildren(
693 const BookmarkNode* parent,
[email protected]257d5082013-08-06 07:46:43694 const std::vector<const BookmarkNode*>& ordered_nodes) {
[email protected]23e39692014-06-06 21:10:13695 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24696
[email protected]472f95e2013-06-10 16:49:18697 // Ensure that all children in |parent| are in |ordered_nodes|.
698 DCHECK_EQ(static_cast<size_t>(parent->child_count()), ordered_nodes.size());
avicee78e4e2016-09-30 17:08:14699 for (const BookmarkNode* node : ordered_nodes)
700 DCHECK_EQ(parent, node->parent());
[email protected]472f95e2013-06-10 16:49:18701
tfarina2fa1d2fb2016-10-19 01:44:31702 for (BookmarkModelObserver& observer : observers_)
703 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18704
avicee78e4e2016-09-30 17:08:14705 if (ordered_nodes.size() > 1) {
706 std::map<const BookmarkNode*, int> order;
707 for (size_t i = 0; i < ordered_nodes.size(); ++i)
708 order[ordered_nodes[i]] = i;
[email protected]472f95e2013-06-10 16:49:18709
avicee78e4e2016-09-30 17:08:14710 std::vector<std::unique_ptr<BookmarkNode>> new_children(
711 ordered_nodes.size());
712 BookmarkNode* mutable_parent = AsMutable(parent);
713 for (auto& child : mutable_parent->children()) {
714 size_t new_location = order[child.get()];
715 new_children[new_location] = std::move(child);
716 }
717 mutable_parent->children().swap(new_children);
718
Zinovy Nisaa5aee392018-05-08 16:18:41719 if (store_)
avicee78e4e2016-09-30 17:08:14720 store_->ScheduleSave();
721 }
[email protected]472f95e2013-06-10 16:49:18722
tfarina2fa1d2fb2016-10-19 01:44:31723 for (BookmarkModelObserver& observer : observers_)
724 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]472f95e2013-06-10 16:49:18725}
726
[email protected]c6a7a3d2011-03-12 01:04:30727void BookmarkModel::SetDateFolderModified(const BookmarkNode* parent,
728 const Time time) {
[email protected]eea8fd5532009-12-16 00:08:10729 DCHECK(parent);
[email protected]edb63cc2011-03-11 02:00:41730 AsMutable(parent)->set_date_folder_modified(time);
[email protected]eea8fd5532009-12-16 00:08:10731
Zinovy Nisaa5aee392018-05-08 16:18:41732 if (store_)
[email protected]eea8fd5532009-12-16 00:08:10733 store_->ScheduleSave();
734}
735
[email protected]c6a7a3d2011-03-12 01:04:30736void BookmarkModel::ResetDateFolderModified(const BookmarkNode* node) {
737 SetDateFolderModified(node, Time());
initial.commit09911bf2008-07-26 23:55:29738}
739
kkimlabsf1a7a3732014-11-04 10:30:46740void BookmarkModel::GetBookmarksMatching(const base::string16& text,
741 size_t max_count,
mattreynolds25e9a312016-12-14 21:52:13742 std::vector<TitledUrlMatch>* matches) {
kkimlabsf1a7a3732014-11-04 10:30:46743 GetBookmarksMatching(text, max_count,
744 query_parser::MatchingAlgorithm::DEFAULT, matches);
745}
746
[email protected]b3a84892014-04-23 04:28:07747void BookmarkModel::GetBookmarksMatching(
[email protected]96920152013-12-04 21:00:16748 const base::string16& text,
[email protected]e64e9012010-01-11 23:10:55749 size_t max_count,
kkimlabsf1a7a3732014-11-04 10:30:46750 query_parser::MatchingAlgorithm matching_algorithm,
mattreynolds25e9a312016-12-14 21:52:13751 std::vector<TitledUrlMatch>* matches) {
[email protected]01eec882009-05-22 18:13:28752 if (!loaded_)
753 return;
754
mattreynolds55324d62016-12-09 23:07:29755 index_->GetResultsMatching(text, max_count, matching_algorithm, matches);
[email protected]85d911c2009-05-19 03:59:42756}
757
[email protected]9876bb1c2008-12-16 20:42:25758void BookmarkModel::ClearStore() {
[email protected]265e88e2014-07-07 20:45:19759 store_.reset();
[email protected]9876bb1c2008-12-16 20:42:25760}
761
[email protected]bc770a032011-12-12 17:35:30762void BookmarkModel::SetPermanentNodeVisible(BookmarkNode::Type type,
763 bool value) {
[email protected]043a76d2014-06-05 16:36:24764 BookmarkPermanentNode* node = AsMutable(PermanentNode(type));
765 node->set_visible(value || client_->IsPermanentNodeVisible(node));
[email protected]996dbe82014-05-12 12:32:18766}
767
768const BookmarkPermanentNode* BookmarkModel::PermanentNode(
769 BookmarkNode::Type type) {
[email protected]1da5f712011-12-06 05:52:26770 DCHECK(loaded_);
[email protected]bc770a032011-12-12 17:35:30771 switch (type) {
772 case BookmarkNode::BOOKMARK_BAR:
[email protected]996dbe82014-05-12 12:32:18773 return bookmark_bar_node_;
[email protected]bc770a032011-12-12 17:35:30774 case BookmarkNode::OTHER_NODE:
[email protected]996dbe82014-05-12 12:32:18775 return other_node_;
[email protected]bc770a032011-12-12 17:35:30776 case BookmarkNode::MOBILE:
[email protected]996dbe82014-05-12 12:32:18777 return mobile_node_;
[email protected]bc770a032011-12-12 17:35:30778 default:
779 NOTREACHED();
Ivan Kotenkov75b1c3a2017-10-24 14:47:24780 return nullptr;
[email protected]bc770a032011-12-12 17:35:30781 }
[email protected]1da5f712011-12-06 05:52:26782}
783
avicee78e4e2016-09-30 17:08:14784void BookmarkModel::RestoreRemovedNode(const BookmarkNode* parent,
785 int index,
786 std::unique_ptr<BookmarkNode> node) {
787 BookmarkNode* node_ptr = node.get();
788 AddNode(AsMutable(parent), index, std::move(node));
jianli14436d52015-10-09 22:47:35789
790 // We might be restoring a folder node that have already contained a set of
791 // child nodes. We need to notify all of them.
avicee78e4e2016-09-30 17:08:14792 NotifyNodeAddedForAllDescendents(node_ptr);
jianli14436d52015-10-09 22:47:35793}
794
795void BookmarkModel::NotifyNodeAddedForAllDescendents(const BookmarkNode* node) {
796 for (int i = 0; i < node->child_count(); ++i) {
tfarina2fa1d2fb2016-10-19 01:44:31797 for (BookmarkModelObserver& observer : observers_)
798 observer.BookmarkNodeAdded(this, node, i);
jianli14436d52015-10-09 22:47:35799 NotifyNodeAddedForAllDescendents(node->GetChild(i));
800 }
801}
802
[email protected]dddc1b42008-10-09 20:56:59803bool BookmarkModel::IsBookmarkedNoLock(const GURL& url) {
[email protected]ea2e5aa52009-05-20 18:01:28804 BookmarkNode tmp_node(url);
[email protected]dddc1b42008-10-09 20:56:59805 return (nodes_ordered_by_url_set_.find(&tmp_node) !=
806 nodes_ordered_by_url_set_.end());
807}
808
[email protected]d8e41ed2008-09-11 15:22:32809void BookmarkModel::RemoveNode(BookmarkNode* node,
810 std::set<GURL>* removed_urls) {
Scott Violete349e962018-05-03 20:45:23811 DCHECK(node);
812 DCHECK(loaded_);
813 DCHECK(!is_permanent_node(node));
[email protected]f25387b2008-08-21 15:20:33814
[email protected]323dbf72013-03-30 17:08:33815 url_lock_.AssertAcquired();
[email protected]0890e60e2011-06-27 14:55:21816 if (node->is_url()) {
danduongf4fde322014-11-04 18:56:56817 RemoveNodeFromInternalMaps(node);
[email protected]5d4077542011-07-21 20:24:07818 removed_urls->insert(node->url());
initial.commit09911bf2008-07-26 23:55:29819 }
820
[email protected]abc2f262011-03-15 21:15:44821 CancelPendingFaviconLoadRequests(node);
initial.commit09911bf2008-07-26 23:55:29822
823 // Recurse through children.
[email protected]9c1a75a2011-03-10 02:38:12824 for (int i = node->child_count() - 1; i >= 0; --i)
[email protected]f25387b2008-08-21 15:20:33825 RemoveNode(node->GetChild(i), removed_urls);
initial.commit09911bf2008-07-26 23:55:29826}
827
dchengacd3f522016-04-21 22:30:41828void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
[email protected]6a848b52014-04-26 22:06:54829 DCHECK(details);
Scott Violete349e962018-05-03 20:45:23830 DCHECK(!loaded_);
[email protected]01eec882009-05-22 18:13:28831
[email protected]01eec882009-05-22 18:13:28832 next_node_id_ = details->max_id();
[email protected]367d7072009-07-13 23:27:13833 if (details->computed_checksum() != details->stored_checksum() ||
834 details->ids_reassigned()) {
835 // If bookmarks file changed externally, the IDs may have changed
836 // externally. In that case, the decoder may have reassigned IDs to make
837 // them unique. So when the file has changed externally, we should save the
838 // bookmarks file to persist new IDs.
Scott Violete349e962018-05-03 20:45:23839 if (store_)
[email protected]367d7072009-07-13 23:27:13840 store_->ScheduleSave();
841 }
Scott Violete349e962018-05-03 20:45:23842
843 root_ = details->owned_root_node();
844 bookmark_bar_node_ = details->bb_node();
845 other_node_ = details->other_folder_node();
846 mobile_node_ = details->mobile_folder_node();
847
avicee78e4e2016-09-30 17:08:14848 index_ = details->owned_index();
Scott Violet3c914002018-05-03 18:23:05849 index_->SetNodeSorter(std::make_unique<TypedCountSorter>(client_.get()));
Scott Violete349e962018-05-03 20:45:23850 // Sorting the permanent nodes has to happen on the main thread, so we do it
851 // here, after loading completes.
852 std::stable_sort(root_->children().begin(), root_->children().end(),
sdefresne070a5102016-02-01 13:42:14853 VisibilityComparator(client_.get()));
[email protected]6c1164042009-05-08 14:41:08854
Scott Violete349e962018-05-03 20:45:23855 root_->SetMetaInfoMap(details->model_meta_info_map());
856 root_->set_sync_transaction_version(
857 details->model_sync_transaction_version());
[email protected]1858410f2012-10-26 05:06:45858
[email protected]90ef13132008-08-27 03:27:46859 {
[email protected]20305ec2011-01-21 04:55:52860 base::AutoLock url_lock(url_lock_);
[email protected]90ef13132008-08-27 03:27:46861 // Update nodes_ordered_by_url_set_ from the nodes.
Scott Violete349e962018-05-03 20:45:23862 PopulateNodesByURL(root_.get());
[email protected]90ef13132008-08-27 03:27:46863 }
[email protected]f25387b2008-08-21 15:20:33864
initial.commit09911bf2008-07-26 23:55:29865 loaded_ = true;
866
[email protected]cbcd6412009-03-09 22:31:39867 loaded_signal_.Signal();
[email protected]90ef13132008-08-27 03:27:46868
[email protected]f25387b2008-08-21 15:20:33869 // Notify our direct observers.
tfarina2fa1d2fb2016-10-19 01:44:31870 for (BookmarkModelObserver& observer : observers_)
871 observer.BookmarkModelLoaded(this, details->ids_reassigned());
initial.commit09911bf2008-07-26 23:55:29872}
873
avicee78e4e2016-09-30 17:08:14874void BookmarkModel::RemoveAndDeleteNode(BookmarkNode* node_ptr) {
875 std::unique_ptr<BookmarkNode> node;
initial.commit09911bf2008-07-26 23:55:29876
avicee78e4e2016-09-30 17:08:14877 const BookmarkNode* parent = node_ptr->parent();
initial.commit09911bf2008-07-26 23:55:29878 DCHECK(parent);
avicee78e4e2016-09-30 17:08:14879 int index = parent->GetIndexOf(node_ptr);
deepak.m139312672015-05-04 16:29:43880 DCHECK_NE(-1, index);
[email protected]323dbf72013-03-30 17:08:33881
tfarina2fa1d2fb2016-10-19 01:44:31882 for (BookmarkModelObserver& observer : observers_)
883 observer.OnWillRemoveBookmarks(this, parent, index, node_ptr);
[email protected]472f95e2013-06-10 16:49:18884
[email protected]9109f8a12013-06-12 18:07:48885 std::set<GURL> removed_urls;
[email protected]90ef13132008-08-27 03:27:46886 {
[email protected]20305ec2011-01-21 04:55:52887 base::AutoLock url_lock(url_lock_);
avicee78e4e2016-09-30 17:08:14888 node = RemoveNodeAndGetRemovedUrls(node_ptr, &removed_urls);
[email protected]90ef13132008-08-27 03:27:46889 }
initial.commit09911bf2008-07-26 23:55:29890
Zinovy Nisaa5aee392018-05-08 16:18:41891 if (store_)
[email protected]f25387b2008-08-21 15:20:33892 store_->ScheduleSave();
893
tfarina2fa1d2fb2016-10-19 01:44:31894 for (BookmarkModelObserver& observer : observers_)
895 observer.BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls);
jianli14436d52015-10-09 22:47:35896
dcheng51606352015-12-26 21:16:23897 undo_delegate()->OnBookmarkNodeRemoved(this, parent, index, std::move(node));
[email protected]323dbf72013-03-30 17:08:33898}
[email protected]f25387b2008-08-21 15:20:33899
danduongf4fde322014-11-04 18:56:56900void BookmarkModel::RemoveNodeFromInternalMaps(BookmarkNode* node) {
901 index_->Remove(node);
[email protected]5db00bca2013-12-23 00:43:09902 // NOTE: this is called in such a way that url_lock_ is already held. As
903 // such, this doesn't explicitly grab the lock.
danduongf4fde322014-11-04 18:56:56904 url_lock_.AssertAcquired();
[email protected]5db00bca2013-12-23 00:43:09905 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node);
906 DCHECK(i != nodes_ordered_by_url_set_.end());
907 // i points to the first node with the URL, advance until we find the
908 // node we're removing.
909 while (*i != node)
910 ++i;
911 nodes_ordered_by_url_set_.erase(i);
912}
913
avicee78e4e2016-09-30 17:08:14914std::unique_ptr<BookmarkNode> BookmarkModel::RemoveNodeAndGetRemovedUrls(
915 BookmarkNode* node_ptr,
916 std::set<GURL>* removed_urls) {
[email protected]323dbf72013-03-30 17:08:33917 // NOTE: this method should be always called with |url_lock_| held.
918 // This method does not explicitly acquires a lock.
919 url_lock_.AssertAcquired();
920 DCHECK(removed_urls);
avicee78e4e2016-09-30 17:08:14921 BookmarkNode* parent = node_ptr->parent();
[email protected]323dbf72013-03-30 17:08:33922 DCHECK(parent);
avicee78e4e2016-09-30 17:08:14923 std::unique_ptr<BookmarkNode> node = parent->Remove(node_ptr);
924 RemoveNode(node_ptr, removed_urls);
[email protected]323dbf72013-03-30 17:08:33925 // RemoveNode adds an entry to removed_urls for each node of type URL. As we
926 // allow duplicates we need to remove any entries that are still bookmarked.
927 for (std::set<GURL>::iterator i = removed_urls->begin();
928 i != removed_urls->end();) {
929 if (IsBookmarkedNoLock(*i)) {
930 // When we erase the iterator pointing at the erasee is
931 // invalidated, so using i++ here within the "erase" call is
932 // important as it advances the iterator before passing the
933 // old value through to erase.
934 removed_urls->erase(i++);
935 } else {
936 ++i;
937 }
938 }
avicee78e4e2016-09-30 17:08:14939
940 return node;
[email protected]323dbf72013-03-30 17:08:33941}
942
[email protected]d8e41ed2008-09-11 15:22:32943BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
944 int index,
avicee78e4e2016-09-30 17:08:14945 std::unique_ptr<BookmarkNode> node) {
946 BookmarkNode* node_ptr = node.get();
947 parent->Add(std::move(node), index);
initial.commit09911bf2008-07-26 23:55:29948
Zinovy Nisaa5aee392018-05-08 16:18:41949 if (store_)
[email protected]f25387b2008-08-21 15:20:33950 store_->ScheduleSave();
951
jianli14436d52015-10-09 22:47:35952 {
danduongf4fde322014-11-04 18:56:56953 base::AutoLock url_lock(url_lock_);
avicee78e4e2016-09-30 17:08:14954 AddNodeToInternalMaps(node_ptr);
danduongf4fde322014-11-04 18:56:56955 }
956
tfarina2fa1d2fb2016-10-19 01:44:31957 for (BookmarkModelObserver& observer : observers_)
958 observer.BookmarkNodeAdded(this, parent, index);
[email protected]f25387b2008-08-21 15:20:33959
avicee78e4e2016-09-30 17:08:14960 return node_ptr;
initial.commit09911bf2008-07-26 23:55:29961}
962
danduongf4fde322014-11-04 18:56:56963void BookmarkModel::AddNodeToInternalMaps(BookmarkNode* node) {
danduongf4fde322014-11-04 18:56:56964 url_lock_.AssertAcquired();
jianli14436d52015-10-09 22:47:35965 if (node->is_url()) {
966 index_->Add(node);
967 nodes_ordered_by_url_set_.insert(node);
968 }
969 for (int i = 0; i < node->child_count(); ++i)
970 AddNodeToInternalMaps(node->GetChild(i));
danduongf4fde322014-11-04 18:56:56971}
972
[email protected]b3c33d462009-06-26 22:29:20973bool BookmarkModel::IsValidIndex(const BookmarkNode* parent,
[email protected]d8e41ed2008-09-11 15:22:32974 int index,
975 bool allow_end) {
[email protected]776e7492008-10-23 16:47:41976 return (parent && parent->is_folder() &&
[email protected]9c1a75a2011-03-10 02:38:12977 (index >= 0 && (index < parent->child_count() ||
978 (allow_end && index == parent->child_count()))));
[email protected]bd1b96702009-07-08 21:54:14979}
[email protected]f25387b2008-08-21 15:20:33980
[email protected]abc2f262011-03-15 21:15:44981void BookmarkModel::OnFaviconDataAvailable(
[email protected]0ea3db52012-12-07 01:32:01982 BookmarkNode* node,
[email protected]504fca82014-05-07 22:48:08983 favicon_base::IconType icon_type,
[email protected]7627e0b42014-04-17 17:20:53984 const favicon_base::FaviconImageResult& image_result) {
[email protected]4167c3a2008-08-21 18:12:20985 DCHECK(node);
[email protected]e95b717f2014-02-06 13:47:13986 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
[email protected]bcc38612012-10-23 01:10:27987 node->set_favicon_state(BookmarkNode::LOADED_FAVICON);
[email protected]65baa222012-08-30 15:43:51988 if (!image_result.image.IsEmpty()) {
[email protected]504fca82014-05-07 22:48:08989 node->set_favicon_type(icon_type);
[email protected]65baa222012-08-30 15:43:51990 node->set_favicon(image_result.image);
[email protected]2ad0e872012-11-30 01:24:46991 node->set_icon_url(image_result.icon_url);
[email protected]65baa222012-08-30 15:43:51992 FaviconLoaded(node);
Mikel Astiza5ea2552017-11-06 22:50:15993 } else if (icon_type == favicon_base::IconType::kTouchIcon) {
[email protected]504fca82014-05-07 22:48:08994 // Couldn't load the touch icon, fallback to the regular favicon.
995 DCHECK(client_->PreferTouchIcon());
Mikel Astiza5ea2552017-11-06 22:50:15996 LoadFavicon(node, favicon_base::IconType::kFavicon);
Mikel Astiz55b3fe202017-11-08 20:54:50997 } else {
998 // No favicon available, but we still notify observers.
999 FaviconLoaded(node);
initial.commit09911bf2008-07-26 23:55:291000 }
1001}
1002
tfarinac0baf0b2014-12-08 18:01:211003void BookmarkModel::LoadFavicon(BookmarkNode* node,
1004 favicon_base::IconType icon_type) {
[email protected]0890e60e2011-06-27 14:55:211005 if (node->is_folder())
initial.commit09911bf2008-07-26 23:55:291006 return;
1007
[email protected]5d4077542011-07-21 20:24:071008 DCHECK(node->url().is_valid());
[email protected]504fca82014-05-07 22:48:081009 node->set_favicon_state(BookmarkNode::LOADING_FAVICON);
[email protected]25244a932014-07-12 23:00:241010 base::CancelableTaskTracker::TaskId taskId =
1011 client_->GetFaviconImageForPageURL(
1012 node->url(),
1013 icon_type,
1014 base::Bind(
1015 &BookmarkModel::OnFaviconDataAvailable,
1016 base::Unretained(this),
1017 node,
1018 icon_type),
1019 &cancelable_task_tracker_);
[email protected]6a848b52014-04-26 22:06:541020 if (taskId != base::CancelableTaskTracker::kBadTaskId)
1021 node->set_favicon_load_task_id(taskId);
initial.commit09911bf2008-07-26 23:55:291022}
1023
[email protected]5b5c9b7f32011-07-21 01:07:181024void BookmarkModel::FaviconLoaded(const BookmarkNode* node) {
tfarina2fa1d2fb2016-10-19 01:44:311025 for (BookmarkModelObserver& observer : observers_)
1026 observer.BookmarkNodeFaviconChanged(this, node);
[email protected]5b5c9b7f32011-07-21 01:07:181027}
1028
[email protected]abc2f262011-03-15 21:15:441029void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) {
[email protected]e95b717f2014-02-06 13:47:131030 if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) {
[email protected]0ea3db52012-12-07 01:32:011031 cancelable_task_tracker_.TryCancel(node->favicon_load_task_id());
[email protected]e95b717f2014-02-06 13:47:131032 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
initial.commit09911bf2008-07-26 23:55:291033 }
1034}
1035
[email protected]d8e41ed2008-09-11 15:22:321036void BookmarkModel::PopulateNodesByURL(BookmarkNode* node) {
[email protected]90ef13132008-08-27 03:27:461037 // NOTE: this is called with url_lock_ already held. As such, this doesn't
1038 // explicitly grab the lock.
[email protected]f25387b2008-08-21 15:20:331039 if (node->is_url())
1040 nodes_ordered_by_url_set_.insert(node);
[email protected]9c1a75a2011-03-10 02:38:121041 for (int i = 0; i < node->child_count(); ++i)
[email protected]f25387b2008-08-21 15:20:331042 PopulateNodesByURL(node->GetChild(i));
1043}
[email protected]4d89f382009-05-12 06:56:491044
avibc5337b2015-12-25 23:16:331045int64_t BookmarkModel::generate_next_node_id() {
Scott Violete349e962018-05-03 20:45:231046 DCHECK(loaded_);
[email protected]4d89f382009-05-12 06:56:491047 return next_node_id_++;
1048}
[email protected]01eec882009-05-22 18:13:281049
jianli14436d52015-10-09 22:47:351050void BookmarkModel::SetUndoDelegate(BookmarkUndoDelegate* undo_delegate) {
1051 undo_delegate_ = undo_delegate;
1052 if (undo_delegate_)
1053 undo_delegate_->SetUndoProvider(this);
1054}
1055
1056BookmarkUndoDelegate* BookmarkModel::undo_delegate() const {
1057 return undo_delegate_ ? undo_delegate_ : empty_undo_delegate_.get();
1058}
1059
tfarinaa0ec34e2015-01-12 18:46:481060} // namespace bookmarks