blob: 124cee93c538c92d3007460008ace86a7e1fc212 [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"
Hans Wennborgdf87046c2020-04-28 11:06:2415#include "base/check_op.h"
Pauline Leitao44f5a812019-07-30 10:49:5116#include "base/guid.h"
[email protected]9a08fe82013-04-23 05:06:0517#include "base/i18n/string_compare.h"
[email protected]996dbe82014-05-12 12:32:1818#include "base/macros.h"
pkotwiczca240dd2015-07-09 16:15:3219#include "base/metrics/histogram_macros.h"
Hans Wennborgdf87046c2020-04-28 11:06:2420#include "base/notreached.h"
[email protected]6a848b52014-04-26 22:06:5421#include "base/strings/string_util.h"
[email protected]a90c8ca2014-05-20 17:16:0422#include "components/bookmarks/browser/bookmark_expanded_state_tracker.h"
Mikel Astiz1cc07d6df2020-07-27 08:59:5023#include "components/bookmarks/browser/bookmark_load_details.h"
[email protected]a90c8ca2014-05-20 17:16:0424#include "components/bookmarks/browser/bookmark_model_observer.h"
25#include "components/bookmarks/browser/bookmark_node_data.h"
26#include "components/bookmarks/browser/bookmark_storage.h"
jianli14436d52015-10-09 22:47:3527#include "components/bookmarks/browser/bookmark_undo_delegate.h"
[email protected]a90c8ca2014-05-20 17:16:0428#include "components/bookmarks/browser/bookmark_utils.h"
Scott Violeta772b27d2018-05-31 23:23:2129#include "components/bookmarks/browser/model_loader.h"
mattreynolds25e9a312016-12-14 21:52:1330#include "components/bookmarks/browser/titled_url_index.h"
31#include "components/bookmarks/browser/titled_url_match.h"
mattreynolds191b88722016-12-13 19:25:3232#include "components/bookmarks/browser/typed_count_sorter.h"
Scott Violet8aa6d57602018-04-25 15:46:2133#include "components/bookmarks/browser/url_and_title.h"
Scott Violet82ef0fa2018-05-23 18:23:3934#include "components/bookmarks/browser/url_index.h"
Scott Violete349e962018-05-03 20:45:2335#include "components/bookmarks/common/bookmark_constants.h"
[email protected]7627e0b42014-04-17 17:20:5336#include "components/favicon_base/favicon_types.h"
thakisfe8fa0a2017-02-23 19:46:3637#include "components/strings/grit/components_strings.h"
[email protected]c051a1b2011-01-21 23:30:1738#include "ui/base/l10n/l10n_util.h"
[email protected]65baa222012-08-30 15:43:5139#include "ui/gfx/favicon_size.h"
initial.commit09911bf2008-07-26 23:55:2940
[email protected]e1acf6f2008-10-27 20:43:3341using base::Time;
tfarinaa0ec34e2015-01-12 18:46:4842
43namespace bookmarks {
[email protected]e1acf6f2008-10-27 20:43:3344
[email protected]b3c33d462009-06-26 22:29:2045namespace {
46
47// Helper to get a mutable bookmark node.
[email protected]7b084b02011-07-08 16:06:4848BookmarkNode* AsMutable(const BookmarkNode* node) {
[email protected]b3c33d462009-06-26 22:29:2049 return const_cast<BookmarkNode*>(node);
50}
51
[email protected]996dbe82014-05-12 12:32:1852// 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());
Mikel Astizaf1a45f2020-03-10 21:15:3063 bool n1_visible = client_->IsPermanentNodeVisibleWhenEmpty(n1->type());
64 bool n2_visible = client_->IsPermanentNodeVisibleWhenEmpty(n2->type());
[email protected]996dbe82014-05-12 12:32:1865 return n1_visible != n2_visible && n1_visible;
66 }
67
68 private:
69 BookmarkClient* client_;
70};
71
[email protected]ef762642009-03-05 16:30:2572// Comparator used when sorting bookmarks. Folders are sorted first, then
[email protected]2c685cc22009-08-28 00:17:4473// bookmarks.
vmpstr3abe3302016-03-09 19:38:1974class SortComparator {
[email protected]ef762642009-03-05 16:30:2575 public:
[email protected]a48f87d2012-10-09 18:06:3376 explicit SortComparator(icu::Collator* collator) : collator_(collator) {}
[email protected]ef762642009-03-05 16:30:2577
avicee78e4e2016-09-30 17:08:1478 // Returns true if |n1| precedes |n2|.
79 bool operator()(const std::unique_ptr<BookmarkNode>& n1,
80 const std::unique_ptr<BookmarkNode>& n2) {
[email protected]037db002009-10-19 20:06:0881 if (n1->type() == n2->type()) {
[email protected]ef762642009-03-05 16:30:2582 // Types are the same, compare the names.
83 if (!collator_)
[email protected]440b37b22010-08-30 05:31:4084 return n1->GetTitle() < n2->GetTitle();
[email protected]9a08fe82013-04-23 05:06:0585 return base::i18n::CompareString16WithCollator(
estade1274f882015-04-11 05:13:3586 *collator_, n1->GetTitle(), n2->GetTitle()) == UCOL_LESS;
[email protected]ef762642009-03-05 16:30:2587 }
88 // Types differ, sort such that folders come first.
89 return n1->is_folder();
90 }
91
92 private:
[email protected]b5b2385a2009-08-18 05:12:2993 icu::Collator* collator_;
[email protected]ef762642009-03-05 16:30:2594};
95
jianli14436d52015-10-09 22:47:3596// Delegate that does nothing.
97class EmptyUndoDelegate : public BookmarkUndoDelegate {
98 public:
99 EmptyUndoDelegate() {}
100 ~EmptyUndoDelegate() override {}
101
102 private:
103 // BookmarkUndoDelegate:
104 void SetUndoProvider(BookmarkUndoProvider* provider) override {}
105 void OnBookmarkNodeRemoved(BookmarkModel* model,
106 const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30107 size_t index,
dchengacd3f522016-04-21 22:30:41108 std::unique_ptr<BookmarkNode> node) override {}
jianli14436d52015-10-09 22:47:35109
110 DISALLOW_COPY_AND_ASSIGN(EmptyUndoDelegate);
111};
112
Mikel Astize1634392020-02-25 17:12:40113#if DCHECK_IS_ON()
114void AddGuidsToIndexRecursive(const BookmarkNode* node,
115 std::set<std::string>* guid_index) {
116 bool success = guid_index->insert(node->guid()).second;
117 DCHECK(success);
118
119 // Recurse through children.
120 for (size_t i = node->children().size(); i > 0; --i)
121 AddGuidsToIndexRecursive(node->children()[i - 1].get(), guid_index);
122}
123#endif // DCHECK_IS_ON()
124
[email protected]bc770a032011-12-12 17:35:30125} // namespace
[email protected]97fdd162011-12-03 20:50:12126
[email protected]97fdd162011-12-03 20:50:12127// BookmarkModel --------------------------------------------------------------
128
dchengacd3f522016-04-21 22:30:41129BookmarkModel::BookmarkModel(std::unique_ptr<BookmarkClient> client)
sdefresne070a5102016-02-01 13:42:14130 : client_(std::move(client)),
Pauline Leitao44f5a812019-07-30 10:49:51131 owned_root_(std::make_unique<BookmarkNode>(/*id=*/0,
Mikel Astiz0bf1b2d12020-07-02 14:18:51132 BookmarkNode::kRootNodeGuid,
Pauline Leitao44f5a812019-07-30 10:49:51133 GURL())),
Scott Violet82ef0fa2018-05-23 18:23:39134 root_(owned_root_.get()),
François Degrosd6e2d7dd2017-11-22 05:37:02135 observers_(base::ObserverListPolicy::EXISTING_ONLY),
Scott Violete349e962018-05-03 20:45:23136 empty_undo_delegate_(std::make_unique<EmptyUndoDelegate>()) {
[email protected]6a848b52014-04-26 22:06:54137 DCHECK(client_);
sdefresne070a5102016-02-01 13:42:14138 client_->Init(this);
initial.commit09911bf2008-07-26 23:55:29139}
140
[email protected]d8e41ed2008-09-11 15:22:32141BookmarkModel::~BookmarkModel() {
Mikel Astizecaeb702019-12-03 07:11:12142 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
143
tfarina2fa1d2fb2016-10-19 01:44:31144 for (BookmarkModelObserver& observer : observers_)
145 observer.BookmarkModelBeingDeleted(this);
[email protected]3de6fd342008-09-05 02:44:51146
Zinovy Nisaa5aee392018-05-08 16:18:41147 if (store_) {
[email protected]f25387b2008-08-21 15:20:33148 // The store maintains a reference back to us. We need to tell it we're gone
149 // so that it doesn't try and invoke a method back on us again.
150 store_->BookmarkModelDeleted();
initial.commit09911bf2008-07-26 23:55:29151 }
152}
153
[email protected]afecfb72013-04-18 17:17:33154void BookmarkModel::Load(
[email protected]6a848b52014-04-26 22:06:54155 PrefService* pref_service,
[email protected]6a848b52014-04-26 22:06:54156 const base::FilePath& profile_path,
157 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
158 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) {
Mikel Astizecaeb702019-12-03 07:11:12159 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violete349e962018-05-03 20:45:23160 // If the store is non-null, it means Load was already invoked. Load should
161 // only be invoked once.
162 DCHECK(!store_);
[email protected]90ef13132008-08-27 03:27:46163
Scott Violete349e962018-05-03 20:45:23164 expanded_state_tracker_ =
165 std::make_unique<BookmarkExpandedStateTracker>(this, pref_service);
[email protected]90ef13132008-08-27 03:27:46166
Scott Violete349e962018-05-03 20:45:23167 store_ = std::make_unique<BookmarkStorage>(this, profile_path,
168 io_task_runner.get());
Scott Violeta772b27d2018-05-31 23:23:21169 // Creating ModelLoader schedules the load on |io_task_runner|.
tzik1d5d38a72018-07-27 04:40:10170 model_loader_ = ModelLoader::Create(
Scott Violeta772b27d2018-05-31 23:23:21171 profile_path.Append(kBookmarksFileName), io_task_runner.get(),
172 std::make_unique<BookmarkLoadDetails>(client_.get()),
Mikel Astizecaeb702019-12-03 07:11:12173 base::BindOnce(&BookmarkModel::DoneLoading, AsWeakPtr()));
174}
175
176scoped_refptr<ModelLoader> BookmarkModel::model_loader() {
177 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
178 return model_loader_;
[email protected]90ef13132008-08-27 03:27:46179}
180
[email protected]125b234182011-07-08 19:54:41181void BookmarkModel::AddObserver(BookmarkModelObserver* observer) {
Mikel Astizecaeb702019-12-03 07:11:12182 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]125b234182011-07-08 19:54:41183 observers_.AddObserver(observer);
184}
185
186void BookmarkModel::RemoveObserver(BookmarkModelObserver* observer) {
Mikel Astizecaeb702019-12-03 07:11:12187 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]125b234182011-07-08 19:54:41188 observers_.RemoveObserver(observer);
189}
190
[email protected]b68a8172012-02-17 00:25:18191void BookmarkModel::BeginExtensiveChanges() {
Mikel Astizecaeb702019-12-03 07:11:12192 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]b68a8172012-02-17 00:25:18193 if (++extensive_changes_ == 1) {
tfarina2fa1d2fb2016-10-19 01:44:31194 for (BookmarkModelObserver& observer : observers_)
195 observer.ExtensiveBookmarkChangesBeginning(this);
[email protected]b68a8172012-02-17 00:25:18196 }
[email protected]125b234182011-07-08 19:54:41197}
198
[email protected]b68a8172012-02-17 00:25:18199void BookmarkModel::EndExtensiveChanges() {
Mikel Astizecaeb702019-12-03 07:11:12200 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]b68a8172012-02-17 00:25:18201 --extensive_changes_;
202 DCHECK_GE(extensive_changes_, 0);
203 if (extensive_changes_ == 0) {
tfarina2fa1d2fb2016-10-19 01:44:31204 for (BookmarkModelObserver& observer : observers_)
205 observer.ExtensiveBookmarkChangesEnded(this);
[email protected]b68a8172012-02-17 00:25:18206 }
[email protected]125b234182011-07-08 19:54:41207}
208
[email protected]346453a2014-03-12 10:14:37209void BookmarkModel::BeginGroupedChanges() {
Mikel Astizecaeb702019-12-03 07:11:12210 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina2fa1d2fb2016-10-19 01:44:31211 for (BookmarkModelObserver& observer : observers_)
212 observer.GroupedBookmarkChangesBeginning(this);
[email protected]346453a2014-03-12 10:14:37213}
214
215void BookmarkModel::EndGroupedChanges() {
Mikel Astizecaeb702019-12-03 07:11:12216 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina2fa1d2fb2016-10-19 01:44:31217 for (BookmarkModelObserver& observer : observers_)
218 observer.GroupedBookmarkChangesEnded(this);
[email protected]346453a2014-03-12 10:14:37219}
220
deepak.m139312672015-05-04 16:29:43221void BookmarkModel::Remove(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12222 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina16f92ed42015-06-12 13:54:36223 DCHECK(loaded_);
deepak.m139312672015-05-04 16:29:43224 DCHECK(node);
tfarina16f92ed42015-06-12 13:54:36225 DCHECK(!is_root_node(node));
Scott Violet82ef0fa2018-05-23 18:23:39226 const BookmarkNode* parent = node->parent();
227 DCHECK(parent);
Peter Kasting8cf4c23e2019-06-06 00:38:30228 size_t index = size_t{parent->GetIndexOf(node)};
229 DCHECK_NE(size_t{-1}, index);
Mikel Astiz32dcf91d2019-11-12 19:20:36230
231 // Removing a permanent node is problematic and can cause crashes elsewhere
232 // that are difficult to trace back.
233 CHECK(!is_permanent_node(node)) << "for type " << node->type();
Scott Violet82ef0fa2018-05-23 18:23:39234
235 for (BookmarkModelObserver& observer : observers_)
236 observer.OnWillRemoveBookmarks(this, parent, index, node);
237
238 std::set<GURL> removed_urls;
239 std::unique_ptr<BookmarkNode> owned_node =
240 url_index_->Remove(AsMutable(node), &removed_urls);
Mikel Astizb810f7ac2019-11-06 16:57:00241 RemoveNodeFromIndexRecursive(owned_node.get());
Scott Violet82ef0fa2018-05-23 18:23:39242
243 if (store_)
244 store_->ScheduleSave();
245
246 for (BookmarkModelObserver& observer : observers_)
247 observer.BookmarkNodeRemoved(this, parent, index, node, removed_urls);
248
249 undo_delegate()->OnBookmarkNodeRemoved(this, parent, index,
250 std::move(owned_node));
[email protected]f25387b2008-08-21 15:20:33251}
252
[email protected]5cd942208a2014-06-11 06:16:46253void BookmarkModel::RemoveAllUserBookmarks() {
Mikel Astizecaeb702019-12-03 07:11:12254 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]9109f8a12013-06-12 18:07:48255 std::set<GURL> removed_urls;
jianli14436d52015-10-09 22:47:35256 struct RemoveNodeData {
jianli14436d52015-10-09 22:47:35257 const BookmarkNode* parent;
258 int index;
avicee78e4e2016-09-30 17:08:14259 std::unique_ptr<BookmarkNode> node;
jianli14436d52015-10-09 22:47:35260 };
261 std::vector<RemoveNodeData> removed_node_data_list;
[email protected]472f95e2013-06-10 16:49:18262
tfarina2fa1d2fb2016-10-19 01:44:31263 for (BookmarkModelObserver& observer : observers_)
264 observer.OnWillRemoveAllUserBookmarks(this);
[email protected]472f95e2013-06-10 16:49:18265
[email protected]323dbf72013-03-30 17:08:33266 BeginExtensiveChanges();
267 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and
268 // its immediate children. For removing all non permanent nodes just remove
269 // all children of non-root permanent nodes.
270 {
Peter Kastingb0d21f22019-06-25 00:26:16271 for (const auto& permanent_node : root_->children()) {
272 if (!client_->CanBeEditedByUser(permanent_node.get()))
[email protected]043a76d2014-06-05 16:36:24273 continue;
274
Peter Kastingb0d21f22019-06-25 00:26:16275 for (size_t j = permanent_node->children().size(); j > 0; --j) {
Scott Violet82ef0fa2018-05-23 18:23:39276 std::unique_ptr<BookmarkNode> node = url_index_->Remove(
Peter Kastingb0d21f22019-06-25 00:26:16277 permanent_node->children()[j - 1].get(), &removed_urls);
Mikel Astizb810f7ac2019-11-06 16:57:00278 RemoveNodeFromIndexRecursive(node.get());
Peter Kastingb0d21f22019-06-25 00:26:16279 removed_node_data_list.push_back(
280 {permanent_node.get(), j - 1, std::move(node)});
[email protected]323dbf72013-03-30 17:08:33281 }
282 }
283 }
284 EndExtensiveChanges();
Zinovy Nisaa5aee392018-05-08 16:18:41285 if (store_)
[email protected]323dbf72013-03-30 17:08:33286 store_->ScheduleSave();
287
tfarina2fa1d2fb2016-10-19 01:44:31288 for (BookmarkModelObserver& observer : observers_)
289 observer.BookmarkAllUserNodesRemoved(this, removed_urls);
jianli14436d52015-10-09 22:47:35290
291 BeginGroupedChanges();
avicee78e4e2016-09-30 17:08:14292 for (auto& removed_node_data : removed_node_data_list) {
293 undo_delegate()->OnBookmarkNodeRemoved(this, removed_node_data.parent,
294 removed_node_data.index,
295 std::move(removed_node_data.node));
jianli14436d52015-10-09 22:47:35296 }
297 EndGroupedChanges();
[email protected]5cd942208a2014-06-11 06:16:46298}
299
[email protected]b3c33d462009-06-26 22:29:20300void BookmarkModel::Move(const BookmarkNode* node,
301 const BookmarkNode* new_parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30302 size_t index) {
Mikel Astizecaeb702019-12-03 07:11:12303 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastinga71b6c82019-05-31 18:41:33304 DCHECK(loaded_);
305 DCHECK(node);
306 DCHECK(IsValidIndex(new_parent, index, true));
307 DCHECK(!is_root_node(new_parent));
308 DCHECK(!is_permanent_node(node));
309 DCHECK(!new_parent->HasAncestor(node));
initial.commit09911bf2008-07-26 23:55:29310
[email protected]2d48ee842011-03-08 23:27:29311 const BookmarkNode* old_parent = node->parent();
Peter Kasting8cf4c23e2019-06-06 00:38:30312 size_t old_index = old_parent->GetIndexOf(node);
initial.commit09911bf2008-07-26 23:55:29313
314 if (old_parent == new_parent &&
315 (index == old_index || index == old_index + 1)) {
316 // Node is already in this position, nothing to do.
317 return;
318 }
319
[email protected]9e583642012-12-05 02:48:32320 SetDateFolderModified(new_parent, Time::Now());
321
initial.commit09911bf2008-07-26 23:55:29322 if (old_parent == new_parent && index > old_index)
323 index--;
avicee78e4e2016-09-30 17:08:14324
325 BookmarkNode* mutable_old_parent = AsMutable(old_parent);
326 std::unique_ptr<BookmarkNode> owned_node =
Peter Kasting04fd72422019-06-03 19:21:03327 mutable_old_parent->Remove(old_index);
[email protected]b3c33d462009-06-26 22:29:20328 BookmarkNode* mutable_new_parent = AsMutable(new_parent);
avicee78e4e2016-09-30 17:08:14329 mutable_new_parent->Add(std::move(owned_node), index);
initial.commit09911bf2008-07-26 23:55:29330
Zinovy Nisaa5aee392018-05-08 16:18:41331 if (store_)
[email protected]f25387b2008-08-21 15:20:33332 store_->ScheduleSave();
333
tfarina2fa1d2fb2016-10-19 01:44:31334 for (BookmarkModelObserver& observer : observers_)
335 observer.BookmarkNodeMoved(this, old_parent, old_index, new_parent, index);
initial.commit09911bf2008-07-26 23:55:29336}
337
[email protected]4e187ef652010-03-11 05:21:35338void BookmarkModel::Copy(const BookmarkNode* node,
339 const BookmarkNode* new_parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30340 size_t index) {
Mikel Astizecaeb702019-12-03 07:11:12341 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastinga71b6c82019-05-31 18:41:33342 DCHECK(loaded_);
343 DCHECK(node);
344 DCHECK(IsValidIndex(new_parent, index, true));
345 DCHECK(!is_root_node(new_parent));
346 DCHECK(!is_permanent_node(node));
347 DCHECK(!new_parent->HasAncestor(node));
[email protected]4e187ef652010-03-11 05:21:35348
[email protected]c6a7a3d2011-03-12 01:04:30349 SetDateFolderModified(new_parent, Time::Now());
[email protected]67a8ae42013-05-20 09:42:39350 BookmarkNodeData drag_data(node);
[email protected]b1864502010-11-13 00:55:51351 // CloneBookmarkNode will use BookmarkModel methods to do the job, so we
[email protected]1a566fae2010-04-16 01:05:06352 // don't need to send notifications here.
tfarina8f3c40cc2015-01-20 21:22:50353 CloneBookmarkNode(this, drag_data.elements, new_parent, index, true);
[email protected]4e187ef652010-03-11 05:21:35354
Zinovy Nisaa5aee392018-05-08 16:18:41355 if (store_)
[email protected]4e187ef652010-03-11 05:21:35356 store_->ScheduleSave();
[email protected]4e187ef652010-03-11 05:21:35357}
358
[email protected]6a4e5a02012-06-26 19:47:48359const gfx::Image& BookmarkModel::GetFavicon(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12360 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]ea2e5aa52009-05-20 18:01:28361 DCHECK(node);
[email protected]bcc38612012-10-23 01:10:27362 if (node->favicon_state() == BookmarkNode::INVALID_FAVICON) {
[email protected]b3c33d462009-06-26 22:29:20363 BookmarkNode* mutable_node = AsMutable(node);
Mikel Astiza5ea2552017-11-06 22:50:15364 LoadFavicon(mutable_node, client_->PreferTouchIcon()
365 ? favicon_base::IconType::kTouchIcon
366 : favicon_base::IconType::kFavicon);
[email protected]ea2e5aa52009-05-20 18:01:28367 }
368 return node->favicon();
369}
370
[email protected]504fca82014-05-07 22:48:08371favicon_base::IconType BookmarkModel::GetFaviconType(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12372 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]504fca82014-05-07 22:48:08373 DCHECK(node);
374 return node->favicon_type();
375}
376
[email protected]6a848b52014-04-26 22:06:54377void BookmarkModel::SetTitle(const BookmarkNode* node,
378 const base::string16& title) {
Mikel Astizecaeb702019-12-03 07:11:12379 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina5ebd5362015-05-12 21:50:10380 DCHECK(node);
381
[email protected]0491ff72011-12-30 00:45:59382 if (node->GetTitle() == title)
initial.commit09911bf2008-07-26 23:55:29383 return;
[email protected]f25387b2008-08-21 15:20:33384
[email protected]043a76d2014-06-05 16:36:24385 if (is_permanent_node(node) && !client_->CanSetPermanentNodeTitle(node)) {
[email protected]baf4f922009-10-19 16:44:07386 NOTREACHED();
387 return;
388 }
389
tfarina2fa1d2fb2016-10-19 01:44:31390 for (BookmarkModelObserver& observer : observers_)
391 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18392
[email protected]85d911c2009-05-19 03:59:42393 // The title index doesn't support changing the title, instead we remove then
Matt Reynoldse33ab142017-11-09 03:06:48394 // add it back. Only do this for URL nodes. A directory node can have its
395 // title changed but should be excluded from the index.
396 if (node->is_url())
Mikel Astizc69bf852020-01-30 21:48:53397 titled_url_index_->Remove(node);
Mikel Astizb9980c02020-01-31 17:11:31398 url_index_->SetTitle(AsMutable(node), title);
Matt Reynoldse33ab142017-11-09 03:06:48399 if (node->is_url())
Mikel Astizc69bf852020-01-30 21:48:53400 titled_url_index_->Add(node);
[email protected]85d911c2009-05-19 03:59:42401
Zinovy Nisaa5aee392018-05-08 16:18:41402 if (store_)
[email protected]f25387b2008-08-21 15:20:33403 store_->ScheduleSave();
404
tfarina2fa1d2fb2016-10-19 01:44:31405 for (BookmarkModelObserver& observer : observers_)
406 observer.BookmarkNodeChanged(this, node);
initial.commit09911bf2008-07-26 23:55:29407}
408
[email protected]e5486602010-02-09 21:27:55409void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) {
Mikel Astizecaeb702019-12-03 07:11:12410 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
411 DCHECK(node);
412 DCHECK(!node->is_folder());
[email protected]e5486602010-02-09 21:27:55413
[email protected]5d4077542011-07-21 20:24:07414 if (node->url() == url)
[email protected]e5486602010-02-09 21:27:55415 return;
416
[email protected]5b5c9b7f32011-07-21 01:07:18417 BookmarkNode* mutable_node = AsMutable(node);
418 mutable_node->InvalidateFavicon();
419 CancelPendingFaviconLoadRequests(mutable_node);
[email protected]e5486602010-02-09 21:27:55420
tfarina2fa1d2fb2016-10-19 01:44:31421 for (BookmarkModelObserver& observer : observers_)
422 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18423
Mikel Astize1634392020-02-25 17:12:40424 // The title index doesn't support changing the URL, instead we remove then
425 // add it back.
Mikel Astizc69bf852020-01-30 21:48:53426 titled_url_index_->Remove(mutable_node);
Scott Violet82ef0fa2018-05-23 18:23:39427 url_index_->SetUrl(mutable_node, url);
Mikel Astize1634392020-02-25 17:12:40428 titled_url_index_->Add(mutable_node);
[email protected]e5486602010-02-09 21:27:55429
Zinovy Nisaa5aee392018-05-08 16:18:41430 if (store_)
[email protected]e5486602010-02-09 21:27:55431 store_->ScheduleSave();
432
tfarina2fa1d2fb2016-10-19 01:44:31433 for (BookmarkModelObserver& observer : observers_)
434 observer.BookmarkNodeChanged(this, node);
[email protected]e5486602010-02-09 21:27:55435}
436
[email protected]1858410f2012-10-26 05:06:45437void BookmarkModel::SetNodeMetaInfo(const BookmarkNode* node,
438 const std::string& key,
439 const std::string& value) {
Mikel Astizecaeb702019-12-03 07:11:12440 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
441
[email protected]39e113452013-11-26 00:43:06442 std::string old_value;
443 if (node->GetMetaInfo(key, &old_value) && old_value == value)
444 return;
445
tfarina2fa1d2fb2016-10-19 01:44:31446 for (BookmarkModelObserver& observer : observers_)
447 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40448
[email protected]1858410f2012-10-26 05:06:45449 if (AsMutable(node)->SetMetaInfo(key, value) && store_.get())
450 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40451
tfarina2fa1d2fb2016-10-19 01:44:31452 for (BookmarkModelObserver& observer : observers_)
453 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45454}
455
[email protected]e38a87d2013-12-05 01:35:18456void BookmarkModel::SetNodeMetaInfoMap(
457 const BookmarkNode* node,
458 const BookmarkNode::MetaInfoMap& meta_info_map) {
Mikel Astizecaeb702019-12-03 07:11:12459 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
460
[email protected]e38a87d2013-12-05 01:35:18461 const BookmarkNode::MetaInfoMap* old_meta_info_map = node->GetMetaInfoMap();
462 if ((!old_meta_info_map && meta_info_map.empty()) ||
463 (old_meta_info_map && meta_info_map == *old_meta_info_map))
464 return;
465
tfarina2fa1d2fb2016-10-19 01:44:31466 for (BookmarkModelObserver& observer : observers_)
467 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]e38a87d2013-12-05 01:35:18468
469 AsMutable(node)->SetMetaInfoMap(meta_info_map);
Zinovy Nisaa5aee392018-05-08 16:18:41470 if (store_)
[email protected]e38a87d2013-12-05 01:35:18471 store_->ScheduleSave();
472
tfarina2fa1d2fb2016-10-19 01:44:31473 for (BookmarkModelObserver& observer : observers_)
474 observer.BookmarkMetaInfoChanged(this, node);
[email protected]e38a87d2013-12-05 01:35:18475}
476
[email protected]1858410f2012-10-26 05:06:45477void BookmarkModel::DeleteNodeMetaInfo(const BookmarkNode* node,
478 const std::string& key) {
Mikel Astizecaeb702019-12-03 07:11:12479 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
480
[email protected]39e113452013-11-26 00:43:06481 const BookmarkNode::MetaInfoMap* meta_info_map = node->GetMetaInfoMap();
482 if (!meta_info_map || meta_info_map->find(key) == meta_info_map->end())
483 return;
484
tfarina2fa1d2fb2016-10-19 01:44:31485 for (BookmarkModelObserver& observer : observers_)
486 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40487
[email protected]1858410f2012-10-26 05:06:45488 if (AsMutable(node)->DeleteMetaInfo(key) && store_.get())
489 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40490
tfarina2fa1d2fb2016-10-19 01:44:31491 for (BookmarkModelObserver& observer : observers_)
492 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45493}
494
rfevangd75d32212014-12-06 01:27:22495void BookmarkModel::AddNonClonedKey(const std::string& key) {
Mikel Astizecaeb702019-12-03 07:11:12496 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
rfevangd75d32212014-12-06 01:27:22497 non_cloned_keys_.insert(key);
498}
499
pkotwiczca240dd2015-07-09 16:15:32500void BookmarkModel::OnFaviconsChanged(const std::set<GURL>& page_urls,
501 const GURL& icon_url) {
Mikel Astizecaeb702019-12-03 07:11:12502 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
503
Scott Violet82ef0fa2018-05-23 18:23:39504 if (!loaded_)
505 return;
506
pkotwiczca240dd2015-07-09 16:15:32507 std::set<const BookmarkNode*> to_update;
508 for (const GURL& page_url : page_urls) {
[email protected]6a848b52014-04-26 22:06:54509 std::vector<const BookmarkNode*> nodes;
pkotwiczca240dd2015-07-09 16:15:32510 GetNodesByURL(page_url, &nodes);
511 to_update.insert(nodes.begin(), nodes.end());
512 }
513
514 if (!icon_url.is_empty()) {
515 // Log Histogram to determine how often |icon_url| is non empty in
516 // practice.
517 // TODO(pkotwicz): Do something more efficient if |icon_url| is non-empty
518 // many times a day for each user.
519 UMA_HISTOGRAM_BOOLEAN("Bookmarks.OnFaviconsChangedIconURL", true);
520
Scott Violet82ef0fa2018-05-23 18:23:39521 url_index_->GetNodesWithIconUrl(icon_url, &to_update);
[email protected]6a848b52014-04-26 22:06:54522 }
pkotwiczca240dd2015-07-09 16:15:32523
524 for (const BookmarkNode* node : to_update) {
525 // Rerequest the favicon.
526 BookmarkNode* mutable_node = AsMutable(node);
527 mutable_node->InvalidateFavicon();
528 CancelPendingFaviconLoadRequests(mutable_node);
tfarina2fa1d2fb2016-10-19 01:44:31529 for (BookmarkModelObserver& observer : observers_)
530 observer.BookmarkNodeFaviconChanged(this, node);
pkotwiczca240dd2015-07-09 16:15:32531 }
[email protected]6a848b52014-04-26 22:06:54532}
533
tfarina5ebd5362015-05-12 21:50:10534void BookmarkModel::SetDateAdded(const BookmarkNode* node, Time date_added) {
Mikel Astizecaeb702019-12-03 07:11:12535 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
536 DCHECK(node);
537 DCHECK(!is_permanent_node(node));
[email protected]b61445c2012-10-27 00:11:42538
539 if (node->date_added() == date_added)
540 return;
541
[email protected]b61445c2012-10-27 00:11:42542 AsMutable(node)->set_date_added(date_added);
543
544 // Syncing might result in dates newer than the folder's last modified date.
545 if (date_added > node->parent()->date_folder_modified()) {
546 // Will trigger store_->ScheduleSave().
547 SetDateFolderModified(node->parent(), date_added);
Zinovy Nisaa5aee392018-05-08 16:18:41548 } else if (store_) {
[email protected]b61445c2012-10-27 00:11:42549 store_->ScheduleSave();
550 }
551}
552
[email protected]848cd05e2008-09-19 18:33:48553void BookmarkModel::GetNodesByURL(const GURL& url,
[email protected]b3c33d462009-06-26 22:29:20554 std::vector<const BookmarkNode*>* nodes) {
Mikel Astizecaeb702019-12-03 07:11:12555 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
556
Scott Violet82ef0fa2018-05-23 18:23:39557 if (url_index_)
558 url_index_->GetNodesByUrl(url, nodes);
[email protected]848cd05e2008-09-19 18:33:48559}
560
[email protected]23e39692014-06-06 21:10:13561const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL(
[email protected]b3c33d462009-06-26 22:29:20562 const GURL& url) {
Mikel Astizecaeb702019-12-03 07:11:12563 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
564
[email protected]b3c33d462009-06-26 22:29:20565 std::vector<const BookmarkNode*> nodes;
[email protected]848cd05e2008-09-19 18:33:48566 GetNodesByURL(url, &nodes);
tfarinaa0ec34e2015-01-12 18:46:48567 std::sort(nodes.begin(), nodes.end(), &MoreRecentlyAdded);
[email protected]23e39692014-06-06 21:10:13568
569 // Look for the first node that the user can edit.
570 for (size_t i = 0; i < nodes.size(); ++i) {
571 if (client_->CanBeEditedByUser(nodes[i]))
572 return nodes[i];
573 }
574
Ivan Kotenkov75b1c3a2017-10-24 14:47:24575 return nullptr;
initial.commit09911bf2008-07-26 23:55:29576}
577
[email protected]cf8e8172011-07-23 00:46:24578bool BookmarkModel::HasBookmarks() {
Mikel Astizecaeb702019-12-03 07:11:12579 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violet82ef0fa2018-05-23 18:23:39580 return url_index_ && url_index_->HasBookmarks();
[email protected]cf8e8172011-07-23 00:46:24581}
582
Marti Wongc67da222017-09-01 02:30:01583bool BookmarkModel::HasNoUserCreatedBookmarksOrFolders() {
Mikel Astizecaeb702019-12-03 07:11:12584 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastingfc86fec62019-05-21 20:43:47585 return bookmark_bar_node_->children().empty() &&
586 other_node_->children().empty() && mobile_node_->children().empty();
Marti Wongc67da222017-09-01 02:30:01587}
588
[email protected]cf8e8172011-07-23 00:46:24589bool BookmarkModel::IsBookmarked(const GURL& url) {
Mikel Astizecaeb702019-12-03 07:11:12590 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violet82ef0fa2018-05-23 18:23:39591 return url_index_ && url_index_->IsBookmarked(url);
[email protected]cf8e8172011-07-23 00:46:24592}
593
Scott Violet8aa6d57602018-04-25 15:46:21594void BookmarkModel::GetBookmarks(std::vector<UrlAndTitle>* bookmarks) {
Mikel Astizecaeb702019-12-03 07:11:12595 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violet82ef0fa2018-05-23 18:23:39596 if (url_index_)
597 url_index_->GetBookmarks(bookmarks);
[email protected]90ef13132008-08-27 03:27:46598}
599
Pauline Leitao6a341952019-09-13 15:00:43600const BookmarkNode* BookmarkModel::AddFolder(
[email protected]eb59ad12014-04-24 00:05:08601 const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30602 size_t index,
[email protected]eb59ad12014-04-24 00:05:08603 const base::string16& title,
Pauline Leitao6a341952019-09-13 15:00:43604 const BookmarkNode::MetaInfoMap* meta_info,
605 base::Optional<std::string> guid) {
Mikel Astizecaeb702019-12-03 07:11:12606 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastinga71b6c82019-05-31 18:41:33607 DCHECK(loaded_);
Mikel Astiz9f8d40e2020-02-13 17:47:13608 DCHECK(parent);
609 DCHECK(parent->is_folder());
Peter Kastinga71b6c82019-05-31 18:41:33610 DCHECK(!is_root_node(parent));
611 DCHECK(IsValidIndex(parent, index, true));
initial.commit09911bf2008-07-26 23:55:29612
Pauline Leitao6a341952019-09-13 15:00:43613 if (guid)
Mikel Astiz0afae3ca2020-02-18 21:07:36614 DCHECK(base::IsValidGUIDOutputString(*guid));
Pauline Leitao6a341952019-09-13 15:00:43615 else
616 guid = base::GenerateGUID();
617
618 auto new_node =
619 std::make_unique<BookmarkNode>(generate_next_node_id(), *guid, GURL());
[email protected]edb63cc2011-03-11 02:00:41620 new_node->set_date_folder_modified(Time::Now());
[email protected]aee236542011-12-01 04:34:03621 // Folders shouldn't have line breaks in their titles.
[email protected]0491ff72011-12-30 00:45:59622 new_node->SetTitle(title);
[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
Pauline Leitao6a341952019-09-13 15:00:43629const BookmarkNode* BookmarkModel::AddURL(
[email protected]e64e9012010-01-11 23:10:55630 const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30631 size_t index,
[email protected]96920152013-12-04 21:00:16632 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55633 const GURL& url,
Pauline Leitao6a341952019-09-13 15:00:43634 const BookmarkNode::MetaInfoMap* meta_info,
635 base::Optional<base::Time> creation_time,
636 base::Optional<std::string> guid) {
Mikel Astizecaeb702019-12-03 07:11:12637 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastinga71b6c82019-05-31 18:41:33638 DCHECK(loaded_);
639 DCHECK(url.is_valid());
Mikel Astiz9f8d40e2020-02-13 17:47:13640 DCHECK(parent);
641 DCHECK(parent->is_folder());
Peter Kastinga71b6c82019-05-31 18:41:33642 DCHECK(!is_root_node(parent));
643 DCHECK(IsValidIndex(parent, index, true));
initial.commit09911bf2008-07-26 23:55:29644
Pauline Leitao6a341952019-09-13 15:00:43645 if (guid)
Mikel Astiz0afae3ca2020-02-18 21:07:36646 DCHECK(base::IsValidGUIDOutputString(*guid));
Pauline Leitao6a341952019-09-13 15:00:43647 else
648 guid = base::GenerateGUID();
initial.commit09911bf2008-07-26 23:55:29649
Pauline Leitao6a341952019-09-13 15:00:43650 if (!creation_time)
651 creation_time = Time::Now();
652
653 // Syncing may result in dates newer than the last modified date.
654 if (*creation_time > parent->date_folder_modified())
655 SetDateFolderModified(parent, *creation_time);
656
657 auto new_node =
658 std::make_unique<BookmarkNode>(generate_next_node_id(), *guid, url);
[email protected]0491ff72011-12-30 00:45:59659 new_node->SetTitle(title);
Pauline Leitao6a341952019-09-13 15:00:43660 new_node->set_date_added(*creation_time);
[email protected]eb59ad12014-04-24 00:05:08661 if (meta_info)
662 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29663
avicee78e4e2016-09-30 17:08:14664 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29665}
666
[email protected]b3c33d462009-06-26 22:29:20667void BookmarkModel::SortChildren(const BookmarkNode* parent) {
Mikel Astizecaeb702019-12-03 07:11:12668 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]23e39692014-06-06 21:10:13669 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24670
[email protected]6b4d64c2011-07-29 21:33:24671 if (!parent || !parent->is_folder() || is_root_node(parent) ||
Peter Kastingb0d21f22019-06-25 00:26:16672 parent->children().size() <= 1) {
[email protected]e2f86d92009-02-25 00:22:01673 return;
674 }
675
tfarina2fa1d2fb2016-10-19 01:44:31676 for (BookmarkModelObserver& observer : observers_)
677 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18678
[email protected]ef762642009-03-05 16:30:25679 UErrorCode error = U_ZERO_ERROR;
dchengacd3f522016-04-21 22:30:41680 std::unique_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
[email protected]ef762642009-03-05 16:30:25681 if (U_FAILURE(error))
Ivan Kotenkov75b1c3a2017-10-24 14:47:24682 collator.reset(nullptr);
[email protected]b3c33d462009-06-26 22:29:20683 BookmarkNode* mutable_parent = AsMutable(parent);
Peter Kastingfc86fec62019-05-21 20:43:47684 std::sort(mutable_parent->children_.begin(), mutable_parent->children_.end(),
[email protected]ef762642009-03-05 16:30:25685 SortComparator(collator.get()));
[email protected]e2f86d92009-02-25 00:22:01686
Zinovy Nisaa5aee392018-05-08 16:18:41687 if (store_)
[email protected]997a0362009-03-12 03:10:51688 store_->ScheduleSave();
689
tfarina2fa1d2fb2016-10-19 01:44:31690 for (BookmarkModelObserver& observer : observers_)
691 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]e2f86d92009-02-25 00:22:01692}
693
[email protected]472f95e2013-06-10 16:49:18694void BookmarkModel::ReorderChildren(
695 const BookmarkNode* parent,
[email protected]257d5082013-08-06 07:46:43696 const std::vector<const BookmarkNode*>& ordered_nodes) {
Mikel Astizecaeb702019-12-03 07:11:12697 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]23e39692014-06-06 21:10:13698 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24699
[email protected]472f95e2013-06-10 16:49:18700 // Ensure that all children in |parent| are in |ordered_nodes|.
Peter Kastingb0d21f22019-06-25 00:26:16701 DCHECK_EQ(parent->children().size(), ordered_nodes.size());
avicee78e4e2016-09-30 17:08:14702 for (const BookmarkNode* node : ordered_nodes)
703 DCHECK_EQ(parent, node->parent());
[email protected]472f95e2013-06-10 16:49:18704
tfarina2fa1d2fb2016-10-19 01:44:31705 for (BookmarkModelObserver& observer : observers_)
706 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18707
avicee78e4e2016-09-30 17:08:14708 if (ordered_nodes.size() > 1) {
709 std::map<const BookmarkNode*, int> order;
710 for (size_t i = 0; i < ordered_nodes.size(); ++i)
711 order[ordered_nodes[i]] = i;
[email protected]472f95e2013-06-10 16:49:18712
avicee78e4e2016-09-30 17:08:14713 std::vector<std::unique_ptr<BookmarkNode>> new_children(
714 ordered_nodes.size());
715 BookmarkNode* mutable_parent = AsMutable(parent);
Peter Kastingfc86fec62019-05-21 20:43:47716 for (auto& child : mutable_parent->children_) {
avicee78e4e2016-09-30 17:08:14717 size_t new_location = order[child.get()];
718 new_children[new_location] = std::move(child);
719 }
Peter Kastingfc86fec62019-05-21 20:43:47720 mutable_parent->children_.swap(new_children);
avicee78e4e2016-09-30 17:08:14721
Zinovy Nisaa5aee392018-05-08 16:18:41722 if (store_)
avicee78e4e2016-09-30 17:08:14723 store_->ScheduleSave();
724 }
[email protected]472f95e2013-06-10 16:49:18725
tfarina2fa1d2fb2016-10-19 01:44:31726 for (BookmarkModelObserver& observer : observers_)
727 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]472f95e2013-06-10 16:49:18728}
729
[email protected]c6a7a3d2011-03-12 01:04:30730void BookmarkModel::SetDateFolderModified(const BookmarkNode* parent,
731 const Time time) {
Mikel Astizecaeb702019-12-03 07:11:12732 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]eea8fd5532009-12-16 00:08:10733 DCHECK(parent);
[email protected]edb63cc2011-03-11 02:00:41734 AsMutable(parent)->set_date_folder_modified(time);
[email protected]eea8fd5532009-12-16 00:08:10735
Zinovy Nisaa5aee392018-05-08 16:18:41736 if (store_)
[email protected]eea8fd5532009-12-16 00:08:10737 store_->ScheduleSave();
738}
739
[email protected]c6a7a3d2011-03-12 01:04:30740void BookmarkModel::ResetDateFolderModified(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12741 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]c6a7a3d2011-03-12 01:04:30742 SetDateFolderModified(node, Time());
initial.commit09911bf2008-07-26 23:55:29743}
744
kkimlabsf1a7a3732014-11-04 10:30:46745void BookmarkModel::GetBookmarksMatching(const base::string16& text,
746 size_t max_count,
mattreynolds25e9a312016-12-14 21:52:13747 std::vector<TitledUrlMatch>* matches) {
Mikel Astizecaeb702019-12-03 07:11:12748 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
kkimlabsf1a7a3732014-11-04 10:30:46749 GetBookmarksMatching(text, max_count,
750 query_parser::MatchingAlgorithm::DEFAULT, matches);
751}
752
[email protected]b3a84892014-04-23 04:28:07753void BookmarkModel::GetBookmarksMatching(
[email protected]96920152013-12-04 21:00:16754 const base::string16& text,
[email protected]e64e9012010-01-11 23:10:55755 size_t max_count,
kkimlabsf1a7a3732014-11-04 10:30:46756 query_parser::MatchingAlgorithm matching_algorithm,
mattreynolds25e9a312016-12-14 21:52:13757 std::vector<TitledUrlMatch>* matches) {
Mikel Astizecaeb702019-12-03 07:11:12758 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
759
[email protected]01eec882009-05-22 18:13:28760 if (!loaded_)
761 return;
762
Mikel Astizc69bf852020-01-30 21:48:53763 titled_url_index_->GetResultsMatching(text, max_count, matching_algorithm,
764 matches);
[email protected]85d911c2009-05-19 03:59:42765}
766
[email protected]9876bb1c2008-12-16 20:42:25767void BookmarkModel::ClearStore() {
Mikel Astizecaeb702019-12-03 07:11:12768 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]265e88e2014-07-07 20:45:19769 store_.reset();
[email protected]9876bb1c2008-12-16 20:42:25770}
771
avicee78e4e2016-09-30 17:08:14772void BookmarkModel::RestoreRemovedNode(const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30773 size_t index,
avicee78e4e2016-09-30 17:08:14774 std::unique_ptr<BookmarkNode> node) {
Mikel Astizecaeb702019-12-03 07:11:12775 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
776
avicee78e4e2016-09-30 17:08:14777 BookmarkNode* node_ptr = node.get();
778 AddNode(AsMutable(parent), index, std::move(node));
jianli14436d52015-10-09 22:47:35779
780 // We might be restoring a folder node that have already contained a set of
781 // child nodes. We need to notify all of them.
avicee78e4e2016-09-30 17:08:14782 NotifyNodeAddedForAllDescendents(node_ptr);
jianli14436d52015-10-09 22:47:35783}
784
785void BookmarkModel::NotifyNodeAddedForAllDescendents(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12786 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
787
Peter Kasting8cf4c23e2019-06-06 00:38:30788 for (size_t i = 0; i < node->children().size(); ++i) {
tfarina2fa1d2fb2016-10-19 01:44:31789 for (BookmarkModelObserver& observer : observers_)
790 observer.BookmarkNodeAdded(this, node, i);
Peter Kasting51745902019-06-28 21:54:55791 NotifyNodeAddedForAllDescendents(node->children()[i].get());
jianli14436d52015-10-09 22:47:35792 }
793}
794
Mikel Astizb810f7ac2019-11-06 16:57:00795void BookmarkModel::RemoveNodeFromIndexRecursive(BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12796 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violete349e962018-05-03 20:45:23797 DCHECK(loaded_);
798 DCHECK(!is_permanent_node(node));
[email protected]f25387b2008-08-21 15:20:33799
Scott Violet82ef0fa2018-05-23 18:23:39800 if (node->is_url())
Mikel Astizc69bf852020-01-30 21:48:53801 titled_url_index_->Remove(node);
initial.commit09911bf2008-07-26 23:55:29802
Mikel Astize1634392020-02-25 17:12:40803 // Note that |guid_index_| is used for DCHECK-enabled builds only.
804#if DCHECK_IS_ON()
805 DCHECK(guid_index_.erase(node->guid()))
806 << "Bookmark GUID missing in index: " << node->guid();
807#endif // DCHECK_IS_ON()
808
[email protected]abc2f262011-03-15 21:15:44809 CancelPendingFaviconLoadRequests(node);
initial.commit09911bf2008-07-26 23:55:29810
811 // Recurse through children.
Peter Kastingb0d21f22019-06-25 00:26:16812 for (size_t i = node->children().size(); i > 0; --i)
Mikel Astizb810f7ac2019-11-06 16:57:00813 RemoveNodeFromIndexRecursive(node->children()[i - 1].get());
initial.commit09911bf2008-07-26 23:55:29814}
815
dchengacd3f522016-04-21 22:30:41816void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
Mikel Astizecaeb702019-12-03 07:11:12817 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]6a848b52014-04-26 22:06:54818 DCHECK(details);
Scott Violete349e962018-05-03 20:45:23819 DCHECK(!loaded_);
[email protected]01eec882009-05-22 18:13:28820
[email protected]01eec882009-05-22 18:13:28821 next_node_id_ = details->max_id();
[email protected]367d7072009-07-13 23:27:13822 if (details->computed_checksum() != details->stored_checksum() ||
Pauline Leitao44f5a812019-07-30 10:49:51823 details->ids_reassigned() || details->guids_reassigned()) {
[email protected]367d7072009-07-13 23:27:13824 // If bookmarks file changed externally, the IDs may have changed
825 // externally. In that case, the decoder may have reassigned IDs to make
826 // them unique. So when the file has changed externally, we should save the
Pauline Leitao44f5a812019-07-30 10:49:51827 // bookmarks file to persist such changes. The same applies if new GUIDs
828 // have been assigned to bookmarks.
Scott Violete349e962018-05-03 20:45:23829 if (store_)
[email protected]367d7072009-07-13 23:27:13830 store_->ScheduleSave();
831 }
Scott Violete349e962018-05-03 20:45:23832
Mikel Astizc69bf852020-01-30 21:48:53833 titled_url_index_ = details->owned_index();
Scott Violeta772b27d2018-05-31 23:23:21834 url_index_ = details->url_index();
Scott Violet82ef0fa2018-05-23 18:23:39835 root_ = details->root_node();
836 // See declaration for details on why |owned_root_| is reset.
837 owned_root_.reset();
Scott Violete349e962018-05-03 20:45:23838 bookmark_bar_node_ = details->bb_node();
839 other_node_ = details->other_folder_node();
840 mobile_node_ = details->mobile_folder_node();
841
Mikel Astize1634392020-02-25 17:12:40842#if DCHECK_IS_ON()
843 AddGuidsToIndexRecursive(root_, &guid_index_);
844#endif // DCHECK_IS_ON()
845
Mikel Astizc69bf852020-01-30 21:48:53846 titled_url_index_->SetNodeSorter(
847 std::make_unique<TypedCountSorter>(client_.get()));
Scott Violete349e962018-05-03 20:45:23848 // Sorting the permanent nodes has to happen on the main thread, so we do it
849 // here, after loading completes.
Peter Kastingfc86fec62019-05-21 20:43:47850 std::stable_sort(root_->children_.begin(), root_->children_.end(),
sdefresne070a5102016-02-01 13:42:14851 VisibilityComparator(client_.get()));
[email protected]6c1164042009-05-08 14:41:08852
Scott Violete349e962018-05-03 20:45:23853 root_->SetMetaInfoMap(details->model_meta_info_map());
[email protected]1858410f2012-10-26 05:06:45854
initial.commit09911bf2008-07-26 23:55:29855 loaded_ = true;
Mohamed Amir Yosefd19506182018-06-19 13:02:14856 client_->DecodeBookmarkSyncMetadata(
857 details->sync_metadata_str(),
858 store_ ? base::BindRepeating(&BookmarkStorage::ScheduleSave,
859 base::Unretained(store_.get()))
860 : base::DoNothing());
initial.commit09911bf2008-07-26 23:55:29861
[email protected]f25387b2008-08-21 15:20:33862 // Notify our direct observers.
tfarina2fa1d2fb2016-10-19 01:44:31863 for (BookmarkModelObserver& observer : observers_)
864 observer.BookmarkModelLoaded(this, details->ids_reassigned());
initial.commit09911bf2008-07-26 23:55:29865}
866
[email protected]d8e41ed2008-09-11 15:22:32867BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30868 size_t index,
avicee78e4e2016-09-30 17:08:14869 std::unique_ptr<BookmarkNode> node) {
Mikel Astizecaeb702019-12-03 07:11:12870 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
871
avicee78e4e2016-09-30 17:08:14872 BookmarkNode* node_ptr = node.get();
Scott Violet82ef0fa2018-05-23 18:23:39873 url_index_->Add(parent, index, std::move(node));
initial.commit09911bf2008-07-26 23:55:29874
Zinovy Nisaa5aee392018-05-08 16:18:41875 if (store_)
[email protected]f25387b2008-08-21 15:20:33876 store_->ScheduleSave();
877
Scott Violet82ef0fa2018-05-23 18:23:39878 AddNodeToIndexRecursive(node_ptr);
danduongf4fde322014-11-04 18:56:56879
tfarina2fa1d2fb2016-10-19 01:44:31880 for (BookmarkModelObserver& observer : observers_)
881 observer.BookmarkNodeAdded(this, parent, index);
[email protected]f25387b2008-08-21 15:20:33882
avicee78e4e2016-09-30 17:08:14883 return node_ptr;
initial.commit09911bf2008-07-26 23:55:29884}
885
Scott Violet82ef0fa2018-05-23 18:23:39886void BookmarkModel::AddNodeToIndexRecursive(BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12887 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
888
Scott Violet82ef0fa2018-05-23 18:23:39889 if (node->is_url())
Mikel Astizc69bf852020-01-30 21:48:53890 titled_url_index_->Add(node);
Mikel Astize1634392020-02-25 17:12:40891
892 // The node's GUID must be unique. Note that |guid_index_| is used for
893 // DCHECK-enabled builds only.
894#if DCHECK_IS_ON()
895 DCHECK(guid_index_.insert(node->guid()).second)
896 << "Duplicate bookmark GUID: " << node->guid();
897#endif // DCHECK_IS_ON()
898
Peter Kastingb0d21f22019-06-25 00:26:16899 for (const auto& child : node->children())
900 AddNodeToIndexRecursive(child.get());
danduongf4fde322014-11-04 18:56:56901}
902
[email protected]b3c33d462009-06-26 22:29:20903bool BookmarkModel::IsValidIndex(const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30904 size_t index,
[email protected]d8e41ed2008-09-11 15:22:32905 bool allow_end) {
Mikel Astizecaeb702019-12-03 07:11:12906 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kasting8cf4c23e2019-06-06 00:38:30907 return parent && parent->is_folder() &&
908 (index < parent->children().size() ||
909 (allow_end && index == parent->children().size()));
[email protected]bd1b96702009-07-08 21:54:14910}
[email protected]f25387b2008-08-21 15:20:33911
[email protected]abc2f262011-03-15 21:15:44912void BookmarkModel::OnFaviconDataAvailable(
[email protected]0ea3db52012-12-07 01:32:01913 BookmarkNode* node,
[email protected]504fca82014-05-07 22:48:08914 favicon_base::IconType icon_type,
[email protected]7627e0b42014-04-17 17:20:53915 const favicon_base::FaviconImageResult& image_result) {
Mikel Astizecaeb702019-12-03 07:11:12916 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]4167c3a2008-08-21 18:12:20917 DCHECK(node);
Mikel Astizecaeb702019-12-03 07:11:12918
[email protected]e95b717f2014-02-06 13:47:13919 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
[email protected]bcc38612012-10-23 01:10:27920 node->set_favicon_state(BookmarkNode::LOADED_FAVICON);
[email protected]65baa222012-08-30 15:43:51921 if (!image_result.image.IsEmpty()) {
[email protected]504fca82014-05-07 22:48:08922 node->set_favicon_type(icon_type);
[email protected]65baa222012-08-30 15:43:51923 node->set_favicon(image_result.image);
[email protected]2ad0e872012-11-30 01:24:46924 node->set_icon_url(image_result.icon_url);
[email protected]65baa222012-08-30 15:43:51925 FaviconLoaded(node);
Mikel Astiza5ea2552017-11-06 22:50:15926 } else if (icon_type == favicon_base::IconType::kTouchIcon) {
[email protected]504fca82014-05-07 22:48:08927 // Couldn't load the touch icon, fallback to the regular favicon.
928 DCHECK(client_->PreferTouchIcon());
Mikel Astiza5ea2552017-11-06 22:50:15929 LoadFavicon(node, favicon_base::IconType::kFavicon);
Mikel Astiz55b3fe202017-11-08 20:54:50930 } else {
931 // No favicon available, but we still notify observers.
932 FaviconLoaded(node);
initial.commit09911bf2008-07-26 23:55:29933 }
934}
935
tfarinac0baf0b2014-12-08 18:01:21936void BookmarkModel::LoadFavicon(BookmarkNode* node,
937 favicon_base::IconType icon_type) {
Mikel Astizecaeb702019-12-03 07:11:12938 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
939
[email protected]0890e60e2011-06-27 14:55:21940 if (node->is_folder())
initial.commit09911bf2008-07-26 23:55:29941 return;
942
[email protected]5d4077542011-07-21 20:24:07943 DCHECK(node->url().is_valid());
[email protected]504fca82014-05-07 22:48:08944 node->set_favicon_state(BookmarkNode::LOADING_FAVICON);
[email protected]25244a932014-07-12 23:00:24945 base::CancelableTaskTracker::TaskId taskId =
946 client_->GetFaviconImageForPageURL(
danakje8f4a2022019-12-13 20:37:39947 node->url(), icon_type,
948 base::BindOnce(&BookmarkModel::OnFaviconDataAvailable,
949 base::Unretained(this), node, icon_type),
[email protected]25244a932014-07-12 23:00:24950 &cancelable_task_tracker_);
[email protected]6a848b52014-04-26 22:06:54951 if (taskId != base::CancelableTaskTracker::kBadTaskId)
952 node->set_favicon_load_task_id(taskId);
initial.commit09911bf2008-07-26 23:55:29953}
954
[email protected]5b5c9b7f32011-07-21 01:07:18955void BookmarkModel::FaviconLoaded(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12956 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina2fa1d2fb2016-10-19 01:44:31957 for (BookmarkModelObserver& observer : observers_)
958 observer.BookmarkNodeFaviconChanged(this, node);
[email protected]5b5c9b7f32011-07-21 01:07:18959}
960
[email protected]abc2f262011-03-15 21:15:44961void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12962 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]e95b717f2014-02-06 13:47:13963 if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) {
[email protected]0ea3db52012-12-07 01:32:01964 cancelable_task_tracker_.TryCancel(node->favicon_load_task_id());
[email protected]e95b717f2014-02-06 13:47:13965 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
initial.commit09911bf2008-07-26 23:55:29966 }
967}
968
avibc5337b2015-12-25 23:16:33969int64_t BookmarkModel::generate_next_node_id() {
Mikel Astizecaeb702019-12-03 07:11:12970 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violete349e962018-05-03 20:45:23971 DCHECK(loaded_);
[email protected]4d89f382009-05-12 06:56:49972 return next_node_id_++;
973}
[email protected]01eec882009-05-22 18:13:28974
jianli14436d52015-10-09 22:47:35975void BookmarkModel::SetUndoDelegate(BookmarkUndoDelegate* undo_delegate) {
Mikel Astizecaeb702019-12-03 07:11:12976 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
jianli14436d52015-10-09 22:47:35977 undo_delegate_ = undo_delegate;
978 if (undo_delegate_)
979 undo_delegate_->SetUndoProvider(this);
980}
981
982BookmarkUndoDelegate* BookmarkModel::undo_delegate() const {
Mikel Astizecaeb702019-12-03 07:11:12983 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
jianli14436d52015-10-09 22:47:35984 return undo_delegate_ ? undo_delegate_ : empty_undo_delegate_.get();
985}
986
tfarinaa0ec34e2015-01-12 18:46:48987} // namespace bookmarks