blob: 8b44e07cda45a9e35550572760cec32351bf9ee2 [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"
danakjdb9ae7942020-11-11 16:01:3514#include "base/callback_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
[email protected]bc770a032011-12-12 17:35:30113} // namespace
[email protected]97fdd162011-12-03 20:50:12114
[email protected]97fdd162011-12-03 20:50:12115// BookmarkModel --------------------------------------------------------------
116
dchengacd3f522016-04-21 22:30:41117BookmarkModel::BookmarkModel(std::unique_ptr<BookmarkClient> client)
sdefresne070a5102016-02-01 13:42:14118 : client_(std::move(client)),
Daniel Hosseinian26cb15fe2020-11-14 01:14:36119 owned_root_(std::make_unique<BookmarkNode>(
120 /*id=*/0,
121 base::GUID::ParseLowercase(BookmarkNode::kRootNodeGuid),
122 GURL())),
Scott Violet82ef0fa2018-05-23 18:23:39123 root_(owned_root_.get()),
François Degrosd6e2d7dd2017-11-22 05:37:02124 observers_(base::ObserverListPolicy::EXISTING_ONLY),
Scott Violete349e962018-05-03 20:45:23125 empty_undo_delegate_(std::make_unique<EmptyUndoDelegate>()) {
[email protected]6a848b52014-04-26 22:06:54126 DCHECK(client_);
sdefresne070a5102016-02-01 13:42:14127 client_->Init(this);
initial.commit09911bf2008-07-26 23:55:29128}
129
[email protected]d8e41ed2008-09-11 15:22:32130BookmarkModel::~BookmarkModel() {
Mikel Astizecaeb702019-12-03 07:11:12131 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
132
tfarina2fa1d2fb2016-10-19 01:44:31133 for (BookmarkModelObserver& observer : observers_)
134 observer.BookmarkModelBeingDeleted(this);
[email protected]3de6fd342008-09-05 02:44:51135
Zinovy Nisaa5aee392018-05-08 16:18:41136 if (store_) {
[email protected]f25387b2008-08-21 15:20:33137 // The store maintains a reference back to us. We need to tell it we're gone
138 // so that it doesn't try and invoke a method back on us again.
139 store_->BookmarkModelDeleted();
initial.commit09911bf2008-07-26 23:55:29140 }
141}
142
Mikel Astiz22ac6162020-07-29 09:39:27143void BookmarkModel::Load(PrefService* pref_service,
144 const base::FilePath& profile_path) {
Mikel Astizecaeb702019-12-03 07:11:12145 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violete349e962018-05-03 20:45:23146 // If the store is non-null, it means Load was already invoked. Load should
147 // only be invoked once.
148 DCHECK(!store_);
[email protected]90ef13132008-08-27 03:27:46149
Scott Violete349e962018-05-03 20:45:23150 expanded_state_tracker_ =
151 std::make_unique<BookmarkExpandedStateTracker>(this, pref_service);
[email protected]90ef13132008-08-27 03:27:46152
Mikel Astiz22ac6162020-07-29 09:39:27153 store_ = std::make_unique<BookmarkStorage>(this, profile_path);
154 // Creating ModelLoader schedules the load on a backend task runner.
tzik1d5d38a72018-07-27 04:40:10155 model_loader_ = ModelLoader::Create(
Mikel Astiz22ac6162020-07-29 09:39:27156 profile_path.Append(kBookmarksFileName),
Scott Violeta772b27d2018-05-31 23:23:21157 std::make_unique<BookmarkLoadDetails>(client_.get()),
Mikel Astizecaeb702019-12-03 07:11:12158 base::BindOnce(&BookmarkModel::DoneLoading, AsWeakPtr()));
159}
160
161scoped_refptr<ModelLoader> BookmarkModel::model_loader() {
162 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
163 return model_loader_;
[email protected]90ef13132008-08-27 03:27:46164}
165
[email protected]125b234182011-07-08 19:54:41166void BookmarkModel::AddObserver(BookmarkModelObserver* observer) {
Mikel Astizecaeb702019-12-03 07:11:12167 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]125b234182011-07-08 19:54:41168 observers_.AddObserver(observer);
169}
170
171void BookmarkModel::RemoveObserver(BookmarkModelObserver* observer) {
Mikel Astizecaeb702019-12-03 07:11:12172 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]125b234182011-07-08 19:54:41173 observers_.RemoveObserver(observer);
174}
175
[email protected]b68a8172012-02-17 00:25:18176void BookmarkModel::BeginExtensiveChanges() {
Mikel Astizecaeb702019-12-03 07:11:12177 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]b68a8172012-02-17 00:25:18178 if (++extensive_changes_ == 1) {
tfarina2fa1d2fb2016-10-19 01:44:31179 for (BookmarkModelObserver& observer : observers_)
180 observer.ExtensiveBookmarkChangesBeginning(this);
[email protected]b68a8172012-02-17 00:25:18181 }
[email protected]125b234182011-07-08 19:54:41182}
183
[email protected]b68a8172012-02-17 00:25:18184void BookmarkModel::EndExtensiveChanges() {
Mikel Astizecaeb702019-12-03 07:11:12185 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]b68a8172012-02-17 00:25:18186 --extensive_changes_;
187 DCHECK_GE(extensive_changes_, 0);
188 if (extensive_changes_ == 0) {
tfarina2fa1d2fb2016-10-19 01:44:31189 for (BookmarkModelObserver& observer : observers_)
190 observer.ExtensiveBookmarkChangesEnded(this);
[email protected]b68a8172012-02-17 00:25:18191 }
[email protected]125b234182011-07-08 19:54:41192}
193
[email protected]346453a2014-03-12 10:14:37194void BookmarkModel::BeginGroupedChanges() {
Mikel Astizecaeb702019-12-03 07:11:12195 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina2fa1d2fb2016-10-19 01:44:31196 for (BookmarkModelObserver& observer : observers_)
197 observer.GroupedBookmarkChangesBeginning(this);
[email protected]346453a2014-03-12 10:14:37198}
199
200void BookmarkModel::EndGroupedChanges() {
Mikel Astizecaeb702019-12-03 07:11:12201 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina2fa1d2fb2016-10-19 01:44:31202 for (BookmarkModelObserver& observer : observers_)
203 observer.GroupedBookmarkChangesEnded(this);
[email protected]346453a2014-03-12 10:14:37204}
205
deepak.m139312672015-05-04 16:29:43206void BookmarkModel::Remove(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12207 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina16f92ed42015-06-12 13:54:36208 DCHECK(loaded_);
deepak.m139312672015-05-04 16:29:43209 DCHECK(node);
tfarina16f92ed42015-06-12 13:54:36210 DCHECK(!is_root_node(node));
Scott Violet82ef0fa2018-05-23 18:23:39211 const BookmarkNode* parent = node->parent();
212 DCHECK(parent);
Peter Kasting8cf4c23e2019-06-06 00:38:30213 size_t index = size_t{parent->GetIndexOf(node)};
214 DCHECK_NE(size_t{-1}, index);
Mikel Astiz32dcf91d2019-11-12 19:20:36215
216 // Removing a permanent node is problematic and can cause crashes elsewhere
217 // that are difficult to trace back.
218 CHECK(!is_permanent_node(node)) << "for type " << node->type();
Scott Violet82ef0fa2018-05-23 18:23:39219
220 for (BookmarkModelObserver& observer : observers_)
221 observer.OnWillRemoveBookmarks(this, parent, index, node);
222
223 std::set<GURL> removed_urls;
224 std::unique_ptr<BookmarkNode> owned_node =
225 url_index_->Remove(AsMutable(node), &removed_urls);
Mikel Astizb810f7ac2019-11-06 16:57:00226 RemoveNodeFromIndexRecursive(owned_node.get());
Scott Violet82ef0fa2018-05-23 18:23:39227
228 if (store_)
229 store_->ScheduleSave();
230
231 for (BookmarkModelObserver& observer : observers_)
232 observer.BookmarkNodeRemoved(this, parent, index, node, removed_urls);
233
234 undo_delegate()->OnBookmarkNodeRemoved(this, parent, index,
235 std::move(owned_node));
[email protected]f25387b2008-08-21 15:20:33236}
237
[email protected]5cd942208a2014-06-11 06:16:46238void BookmarkModel::RemoveAllUserBookmarks() {
Mikel Astizecaeb702019-12-03 07:11:12239 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]9109f8a12013-06-12 18:07:48240 std::set<GURL> removed_urls;
jianli14436d52015-10-09 22:47:35241 struct RemoveNodeData {
jianli14436d52015-10-09 22:47:35242 const BookmarkNode* parent;
243 int index;
avicee78e4e2016-09-30 17:08:14244 std::unique_ptr<BookmarkNode> node;
jianli14436d52015-10-09 22:47:35245 };
246 std::vector<RemoveNodeData> removed_node_data_list;
[email protected]472f95e2013-06-10 16:49:18247
tfarina2fa1d2fb2016-10-19 01:44:31248 for (BookmarkModelObserver& observer : observers_)
249 observer.OnWillRemoveAllUserBookmarks(this);
[email protected]472f95e2013-06-10 16:49:18250
[email protected]323dbf72013-03-30 17:08:33251 BeginExtensiveChanges();
252 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and
253 // its immediate children. For removing all non permanent nodes just remove
254 // all children of non-root permanent nodes.
255 {
Peter Kastingb0d21f22019-06-25 00:26:16256 for (const auto& permanent_node : root_->children()) {
257 if (!client_->CanBeEditedByUser(permanent_node.get()))
[email protected]043a76d2014-06-05 16:36:24258 continue;
259
Peter Kastingb0d21f22019-06-25 00:26:16260 for (size_t j = permanent_node->children().size(); j > 0; --j) {
Scott Violet82ef0fa2018-05-23 18:23:39261 std::unique_ptr<BookmarkNode> node = url_index_->Remove(
Peter Kastingb0d21f22019-06-25 00:26:16262 permanent_node->children()[j - 1].get(), &removed_urls);
Mikel Astizb810f7ac2019-11-06 16:57:00263 RemoveNodeFromIndexRecursive(node.get());
Peter Kastingb0d21f22019-06-25 00:26:16264 removed_node_data_list.push_back(
265 {permanent_node.get(), j - 1, std::move(node)});
[email protected]323dbf72013-03-30 17:08:33266 }
267 }
268 }
269 EndExtensiveChanges();
Zinovy Nisaa5aee392018-05-08 16:18:41270 if (store_)
[email protected]323dbf72013-03-30 17:08:33271 store_->ScheduleSave();
272
tfarina2fa1d2fb2016-10-19 01:44:31273 for (BookmarkModelObserver& observer : observers_)
274 observer.BookmarkAllUserNodesRemoved(this, removed_urls);
jianli14436d52015-10-09 22:47:35275
276 BeginGroupedChanges();
avicee78e4e2016-09-30 17:08:14277 for (auto& removed_node_data : removed_node_data_list) {
278 undo_delegate()->OnBookmarkNodeRemoved(this, removed_node_data.parent,
279 removed_node_data.index,
280 std::move(removed_node_data.node));
jianli14436d52015-10-09 22:47:35281 }
282 EndGroupedChanges();
[email protected]5cd942208a2014-06-11 06:16:46283}
284
[email protected]b3c33d462009-06-26 22:29:20285void BookmarkModel::Move(const BookmarkNode* node,
286 const BookmarkNode* new_parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30287 size_t index) {
Mikel Astizecaeb702019-12-03 07:11:12288 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastinga71b6c82019-05-31 18:41:33289 DCHECK(loaded_);
290 DCHECK(node);
291 DCHECK(IsValidIndex(new_parent, index, true));
292 DCHECK(!is_root_node(new_parent));
293 DCHECK(!is_permanent_node(node));
294 DCHECK(!new_parent->HasAncestor(node));
initial.commit09911bf2008-07-26 23:55:29295
[email protected]2d48ee842011-03-08 23:27:29296 const BookmarkNode* old_parent = node->parent();
Peter Kasting8cf4c23e2019-06-06 00:38:30297 size_t old_index = old_parent->GetIndexOf(node);
initial.commit09911bf2008-07-26 23:55:29298
299 if (old_parent == new_parent &&
300 (index == old_index || index == old_index + 1)) {
301 // Node is already in this position, nothing to do.
302 return;
303 }
304
[email protected]9e583642012-12-05 02:48:32305 SetDateFolderModified(new_parent, Time::Now());
306
initial.commit09911bf2008-07-26 23:55:29307 if (old_parent == new_parent && index > old_index)
308 index--;
avicee78e4e2016-09-30 17:08:14309
310 BookmarkNode* mutable_old_parent = AsMutable(old_parent);
311 std::unique_ptr<BookmarkNode> owned_node =
Peter Kasting04fd72422019-06-03 19:21:03312 mutable_old_parent->Remove(old_index);
[email protected]b3c33d462009-06-26 22:29:20313 BookmarkNode* mutable_new_parent = AsMutable(new_parent);
avicee78e4e2016-09-30 17:08:14314 mutable_new_parent->Add(std::move(owned_node), index);
initial.commit09911bf2008-07-26 23:55:29315
Zinovy Nisaa5aee392018-05-08 16:18:41316 if (store_)
[email protected]f25387b2008-08-21 15:20:33317 store_->ScheduleSave();
318
tfarina2fa1d2fb2016-10-19 01:44:31319 for (BookmarkModelObserver& observer : observers_)
320 observer.BookmarkNodeMoved(this, old_parent, old_index, new_parent, index);
initial.commit09911bf2008-07-26 23:55:29321}
322
[email protected]4e187ef652010-03-11 05:21:35323void BookmarkModel::Copy(const BookmarkNode* node,
324 const BookmarkNode* new_parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30325 size_t index) {
Mikel Astizecaeb702019-12-03 07:11:12326 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastinga71b6c82019-05-31 18:41:33327 DCHECK(loaded_);
328 DCHECK(node);
329 DCHECK(IsValidIndex(new_parent, index, true));
330 DCHECK(!is_root_node(new_parent));
331 DCHECK(!is_permanent_node(node));
332 DCHECK(!new_parent->HasAncestor(node));
[email protected]4e187ef652010-03-11 05:21:35333
[email protected]c6a7a3d2011-03-12 01:04:30334 SetDateFolderModified(new_parent, Time::Now());
[email protected]67a8ae42013-05-20 09:42:39335 BookmarkNodeData drag_data(node);
[email protected]b1864502010-11-13 00:55:51336 // CloneBookmarkNode will use BookmarkModel methods to do the job, so we
[email protected]1a566fae2010-04-16 01:05:06337 // don't need to send notifications here.
tfarina8f3c40cc2015-01-20 21:22:50338 CloneBookmarkNode(this, drag_data.elements, new_parent, index, true);
[email protected]4e187ef652010-03-11 05:21:35339
Zinovy Nisaa5aee392018-05-08 16:18:41340 if (store_)
[email protected]4e187ef652010-03-11 05:21:35341 store_->ScheduleSave();
[email protected]4e187ef652010-03-11 05:21:35342}
343
[email protected]6a4e5a02012-06-26 19:47:48344const gfx::Image& BookmarkModel::GetFavicon(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12345 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]ea2e5aa52009-05-20 18:01:28346 DCHECK(node);
[email protected]bcc38612012-10-23 01:10:27347 if (node->favicon_state() == BookmarkNode::INVALID_FAVICON) {
[email protected]b3c33d462009-06-26 22:29:20348 BookmarkNode* mutable_node = AsMutable(node);
Mikel Astizbf0fc33a2020-08-03 11:19:03349 LoadFavicon(mutable_node);
[email protected]ea2e5aa52009-05-20 18:01:28350 }
351 return node->favicon();
352}
353
[email protected]6a848b52014-04-26 22:06:54354void BookmarkModel::SetTitle(const BookmarkNode* node,
Jan Wilken Dörriefa241ba2021-03-11 17:57:01355 const std::u16string& title) {
Mikel Astizecaeb702019-12-03 07:11:12356 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina5ebd5362015-05-12 21:50:10357 DCHECK(node);
358
[email protected]0491ff72011-12-30 00:45:59359 if (node->GetTitle() == title)
initial.commit09911bf2008-07-26 23:55:29360 return;
[email protected]f25387b2008-08-21 15:20:33361
[email protected]043a76d2014-06-05 16:36:24362 if (is_permanent_node(node) && !client_->CanSetPermanentNodeTitle(node)) {
[email protected]baf4f922009-10-19 16:44:07363 NOTREACHED();
364 return;
365 }
366
tfarina2fa1d2fb2016-10-19 01:44:31367 for (BookmarkModelObserver& observer : observers_)
368 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18369
[email protected]85d911c2009-05-19 03:59:42370 // The title index doesn't support changing the title, instead we remove then
Matt Reynoldse33ab142017-11-09 03:06:48371 // add it back. Only do this for URL nodes. A directory node can have its
372 // title changed but should be excluded from the index.
373 if (node->is_url())
Mikel Astizc69bf852020-01-30 21:48:53374 titled_url_index_->Remove(node);
Mikel Astizb9980c02020-01-31 17:11:31375 url_index_->SetTitle(AsMutable(node), title);
Matt Reynoldse33ab142017-11-09 03:06:48376 if (node->is_url())
Mikel Astizc69bf852020-01-30 21:48:53377 titled_url_index_->Add(node);
[email protected]85d911c2009-05-19 03:59:42378
Zinovy Nisaa5aee392018-05-08 16:18:41379 if (store_)
[email protected]f25387b2008-08-21 15:20:33380 store_->ScheduleSave();
381
tfarina2fa1d2fb2016-10-19 01:44:31382 for (BookmarkModelObserver& observer : observers_)
383 observer.BookmarkNodeChanged(this, node);
initial.commit09911bf2008-07-26 23:55:29384}
385
[email protected]e5486602010-02-09 21:27:55386void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) {
Mikel Astizecaeb702019-12-03 07:11:12387 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
388 DCHECK(node);
389 DCHECK(!node->is_folder());
[email protected]e5486602010-02-09 21:27:55390
[email protected]5d4077542011-07-21 20:24:07391 if (node->url() == url)
[email protected]e5486602010-02-09 21:27:55392 return;
393
[email protected]5b5c9b7f32011-07-21 01:07:18394 BookmarkNode* mutable_node = AsMutable(node);
395 mutable_node->InvalidateFavicon();
396 CancelPendingFaviconLoadRequests(mutable_node);
[email protected]e5486602010-02-09 21:27:55397
tfarina2fa1d2fb2016-10-19 01:44:31398 for (BookmarkModelObserver& observer : observers_)
399 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18400
Mikel Astize1634392020-02-25 17:12:40401 // The title index doesn't support changing the URL, instead we remove then
402 // add it back.
Mikel Astizc69bf852020-01-30 21:48:53403 titled_url_index_->Remove(mutable_node);
Scott Violet82ef0fa2018-05-23 18:23:39404 url_index_->SetUrl(mutable_node, url);
Mikel Astize1634392020-02-25 17:12:40405 titled_url_index_->Add(mutable_node);
[email protected]e5486602010-02-09 21:27:55406
Zinovy Nisaa5aee392018-05-08 16:18:41407 if (store_)
[email protected]e5486602010-02-09 21:27:55408 store_->ScheduleSave();
409
tfarina2fa1d2fb2016-10-19 01:44:31410 for (BookmarkModelObserver& observer : observers_)
411 observer.BookmarkNodeChanged(this, node);
[email protected]e5486602010-02-09 21:27:55412}
413
[email protected]1858410f2012-10-26 05:06:45414void BookmarkModel::SetNodeMetaInfo(const BookmarkNode* node,
415 const std::string& key,
416 const std::string& value) {
Mikel Astizecaeb702019-12-03 07:11:12417 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
418
[email protected]39e113452013-11-26 00:43:06419 std::string old_value;
420 if (node->GetMetaInfo(key, &old_value) && old_value == value)
421 return;
422
tfarina2fa1d2fb2016-10-19 01:44:31423 for (BookmarkModelObserver& observer : observers_)
424 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40425
[email protected]1858410f2012-10-26 05:06:45426 if (AsMutable(node)->SetMetaInfo(key, value) && store_.get())
427 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40428
tfarina2fa1d2fb2016-10-19 01:44:31429 for (BookmarkModelObserver& observer : observers_)
430 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45431}
432
[email protected]e38a87d2013-12-05 01:35:18433void BookmarkModel::SetNodeMetaInfoMap(
434 const BookmarkNode* node,
435 const BookmarkNode::MetaInfoMap& meta_info_map) {
Mikel Astizecaeb702019-12-03 07:11:12436 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
437
[email protected]e38a87d2013-12-05 01:35:18438 const BookmarkNode::MetaInfoMap* old_meta_info_map = node->GetMetaInfoMap();
439 if ((!old_meta_info_map && meta_info_map.empty()) ||
440 (old_meta_info_map && meta_info_map == *old_meta_info_map))
441 return;
442
tfarina2fa1d2fb2016-10-19 01:44:31443 for (BookmarkModelObserver& observer : observers_)
444 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]e38a87d2013-12-05 01:35:18445
446 AsMutable(node)->SetMetaInfoMap(meta_info_map);
Zinovy Nisaa5aee392018-05-08 16:18:41447 if (store_)
[email protected]e38a87d2013-12-05 01:35:18448 store_->ScheduleSave();
449
tfarina2fa1d2fb2016-10-19 01:44:31450 for (BookmarkModelObserver& observer : observers_)
451 observer.BookmarkMetaInfoChanged(this, node);
[email protected]e38a87d2013-12-05 01:35:18452}
453
[email protected]1858410f2012-10-26 05:06:45454void BookmarkModel::DeleteNodeMetaInfo(const BookmarkNode* node,
455 const std::string& key) {
Mikel Astizecaeb702019-12-03 07:11:12456 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
457
[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) {
Mikel Astizecaeb702019-12-03 07:11:12473 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
rfevangd75d32212014-12-06 01:27:22474 non_cloned_keys_.insert(key);
475}
476
pkotwiczca240dd2015-07-09 16:15:32477void BookmarkModel::OnFaviconsChanged(const std::set<GURL>& page_urls,
478 const GURL& icon_url) {
Mikel Astizecaeb702019-12-03 07:11:12479 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
480
Scott Violet82ef0fa2018-05-23 18:23:39481 if (!loaded_)
482 return;
483
pkotwiczca240dd2015-07-09 16:15:32484 std::set<const BookmarkNode*> to_update;
485 for (const GURL& page_url : page_urls) {
[email protected]6a848b52014-04-26 22:06:54486 std::vector<const BookmarkNode*> nodes;
pkotwiczca240dd2015-07-09 16:15:32487 GetNodesByURL(page_url, &nodes);
488 to_update.insert(nodes.begin(), nodes.end());
489 }
490
491 if (!icon_url.is_empty()) {
492 // Log Histogram to determine how often |icon_url| is non empty in
493 // practice.
494 // TODO(pkotwicz): Do something more efficient if |icon_url| is non-empty
495 // many times a day for each user.
496 UMA_HISTOGRAM_BOOLEAN("Bookmarks.OnFaviconsChangedIconURL", true);
497
Scott Violet82ef0fa2018-05-23 18:23:39498 url_index_->GetNodesWithIconUrl(icon_url, &to_update);
[email protected]6a848b52014-04-26 22:06:54499 }
pkotwiczca240dd2015-07-09 16:15:32500
501 for (const BookmarkNode* node : to_update) {
502 // Rerequest the favicon.
503 BookmarkNode* mutable_node = AsMutable(node);
504 mutable_node->InvalidateFavicon();
505 CancelPendingFaviconLoadRequests(mutable_node);
tfarina2fa1d2fb2016-10-19 01:44:31506 for (BookmarkModelObserver& observer : observers_)
507 observer.BookmarkNodeFaviconChanged(this, node);
pkotwiczca240dd2015-07-09 16:15:32508 }
[email protected]6a848b52014-04-26 22:06:54509}
510
tfarina5ebd5362015-05-12 21:50:10511void BookmarkModel::SetDateAdded(const BookmarkNode* node, Time date_added) {
Mikel Astizecaeb702019-12-03 07:11:12512 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
513 DCHECK(node);
514 DCHECK(!is_permanent_node(node));
[email protected]b61445c2012-10-27 00:11:42515
516 if (node->date_added() == date_added)
517 return;
518
[email protected]b61445c2012-10-27 00:11:42519 AsMutable(node)->set_date_added(date_added);
520
521 // Syncing might result in dates newer than the folder's last modified date.
522 if (date_added > node->parent()->date_folder_modified()) {
523 // Will trigger store_->ScheduleSave().
524 SetDateFolderModified(node->parent(), date_added);
Zinovy Nisaa5aee392018-05-08 16:18:41525 } else if (store_) {
[email protected]b61445c2012-10-27 00:11:42526 store_->ScheduleSave();
527 }
528}
529
[email protected]848cd05e2008-09-19 18:33:48530void BookmarkModel::GetNodesByURL(const GURL& url,
[email protected]b3c33d462009-06-26 22:29:20531 std::vector<const BookmarkNode*>* nodes) {
Mikel Astizecaeb702019-12-03 07:11:12532 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
533
Scott Violet82ef0fa2018-05-23 18:23:39534 if (url_index_)
535 url_index_->GetNodesByUrl(url, nodes);
[email protected]848cd05e2008-09-19 18:33:48536}
537
[email protected]23e39692014-06-06 21:10:13538const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL(
[email protected]b3c33d462009-06-26 22:29:20539 const GURL& url) {
Mikel Astizecaeb702019-12-03 07:11:12540 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
541
[email protected]b3c33d462009-06-26 22:29:20542 std::vector<const BookmarkNode*> nodes;
[email protected]848cd05e2008-09-19 18:33:48543 GetNodesByURL(url, &nodes);
tfarinaa0ec34e2015-01-12 18:46:48544 std::sort(nodes.begin(), nodes.end(), &MoreRecentlyAdded);
[email protected]23e39692014-06-06 21:10:13545
546 // Look for the first node that the user can edit.
547 for (size_t i = 0; i < nodes.size(); ++i) {
548 if (client_->CanBeEditedByUser(nodes[i]))
549 return nodes[i];
550 }
551
Ivan Kotenkov75b1c3a2017-10-24 14:47:24552 return nullptr;
initial.commit09911bf2008-07-26 23:55:29553}
554
[email protected]cf8e8172011-07-23 00:46:24555bool BookmarkModel::HasBookmarks() {
Mikel Astizecaeb702019-12-03 07:11:12556 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violet82ef0fa2018-05-23 18:23:39557 return url_index_ && url_index_->HasBookmarks();
[email protected]cf8e8172011-07-23 00:46:24558}
559
Marti Wongc67da222017-09-01 02:30:01560bool BookmarkModel::HasNoUserCreatedBookmarksOrFolders() {
Mikel Astizecaeb702019-12-03 07:11:12561 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastingfc86fec62019-05-21 20:43:47562 return bookmark_bar_node_->children().empty() &&
563 other_node_->children().empty() && mobile_node_->children().empty();
Marti Wongc67da222017-09-01 02:30:01564}
565
[email protected]cf8e8172011-07-23 00:46:24566bool BookmarkModel::IsBookmarked(const GURL& url) {
Mikel Astizecaeb702019-12-03 07:11:12567 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violet82ef0fa2018-05-23 18:23:39568 return url_index_ && url_index_->IsBookmarked(url);
[email protected]cf8e8172011-07-23 00:46:24569}
570
Scott Violet8aa6d57602018-04-25 15:46:21571void BookmarkModel::GetBookmarks(std::vector<UrlAndTitle>* bookmarks) {
Mikel Astizecaeb702019-12-03 07:11:12572 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violet82ef0fa2018-05-23 18:23:39573 if (url_index_)
574 url_index_->GetBookmarks(bookmarks);
[email protected]90ef13132008-08-27 03:27:46575}
576
Pauline Leitao6a341952019-09-13 15:00:43577const BookmarkNode* BookmarkModel::AddFolder(
[email protected]eb59ad12014-04-24 00:05:08578 const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30579 size_t index,
Jan Wilken Dörriefa241ba2021-03-11 17:57:01580 const std::u16string& title,
Pauline Leitao6a341952019-09-13 15:00:43581 const BookmarkNode::MetaInfoMap* meta_info,
Daniel Hosseinian5cb93d82020-11-17 20:08:05582 base::Optional<base::GUID> guid) {
Mikel Astizecaeb702019-12-03 07:11:12583 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastinga71b6c82019-05-31 18:41:33584 DCHECK(loaded_);
Mikel Astiz9f8d40e2020-02-13 17:47:13585 DCHECK(parent);
586 DCHECK(parent->is_folder());
Peter Kastinga71b6c82019-05-31 18:41:33587 DCHECK(!is_root_node(parent));
588 DCHECK(IsValidIndex(parent, index, true));
Daniel Hosseinian5cb93d82020-11-17 20:08:05589 DCHECK(!guid || guid->is_valid());
initial.commit09911bf2008-07-26 23:55:29590
Daniel Hosseinian5cb93d82020-11-17 20:08:05591 auto new_node = std::make_unique<BookmarkNode>(
592 generate_next_node_id(), guid ? *guid : base::GUID::GenerateRandomV4(),
593 GURL());
[email protected]edb63cc2011-03-11 02:00:41594 new_node->set_date_folder_modified(Time::Now());
[email protected]aee236542011-12-01 04:34:03595 // Folders shouldn't have line breaks in their titles.
[email protected]0491ff72011-12-30 00:45:59596 new_node->SetTitle(title);
[email protected]eb59ad12014-04-24 00:05:08597 if (meta_info)
598 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29599
avicee78e4e2016-09-30 17:08:14600 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29601}
602
Pauline Leitao6a341952019-09-13 15:00:43603const BookmarkNode* BookmarkModel::AddURL(
[email protected]e64e9012010-01-11 23:10:55604 const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30605 size_t index,
Jan Wilken Dörriefa241ba2021-03-11 17:57:01606 const std::u16string& title,
[email protected]e64e9012010-01-11 23:10:55607 const GURL& url,
Pauline Leitao6a341952019-09-13 15:00:43608 const BookmarkNode::MetaInfoMap* meta_info,
609 base::Optional<base::Time> creation_time,
Daniel Hosseiniancfcebaa2020-11-17 20:38:03610 base::Optional<base::GUID> guid) {
Mikel Astizecaeb702019-12-03 07:11:12611 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastinga71b6c82019-05-31 18:41:33612 DCHECK(loaded_);
613 DCHECK(url.is_valid());
Mikel Astiz9f8d40e2020-02-13 17:47:13614 DCHECK(parent);
615 DCHECK(parent->is_folder());
Peter Kastinga71b6c82019-05-31 18:41:33616 DCHECK(!is_root_node(parent));
617 DCHECK(IsValidIndex(parent, index, true));
Daniel Hosseiniancfcebaa2020-11-17 20:38:03618 DCHECK(!guid || guid->is_valid());
initial.commit09911bf2008-07-26 23:55:29619
Pauline Leitao6a341952019-09-13 15:00:43620 if (!creation_time)
621 creation_time = Time::Now();
622
623 // Syncing may result in dates newer than the last modified date.
624 if (*creation_time > parent->date_folder_modified())
625 SetDateFolderModified(parent, *creation_time);
626
Daniel Hosseiniancfcebaa2020-11-17 20:38:03627 auto new_node = std::make_unique<BookmarkNode>(
628 generate_next_node_id(), guid ? *guid : base::GUID::GenerateRandomV4(),
629 url);
[email protected]0491ff72011-12-30 00:45:59630 new_node->SetTitle(title);
Pauline Leitao6a341952019-09-13 15:00:43631 new_node->set_date_added(*creation_time);
[email protected]eb59ad12014-04-24 00:05:08632 if (meta_info)
633 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29634
avicee78e4e2016-09-30 17:08:14635 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29636}
637
[email protected]b3c33d462009-06-26 22:29:20638void BookmarkModel::SortChildren(const BookmarkNode* parent) {
Mikel Astizecaeb702019-12-03 07:11:12639 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]23e39692014-06-06 21:10:13640 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24641
[email protected]6b4d64c2011-07-29 21:33:24642 if (!parent || !parent->is_folder() || is_root_node(parent) ||
Peter Kastingb0d21f22019-06-25 00:26:16643 parent->children().size() <= 1) {
[email protected]e2f86d92009-02-25 00:22:01644 return;
645 }
646
tfarina2fa1d2fb2016-10-19 01:44:31647 for (BookmarkModelObserver& observer : observers_)
648 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18649
[email protected]ef762642009-03-05 16:30:25650 UErrorCode error = U_ZERO_ERROR;
dchengacd3f522016-04-21 22:30:41651 std::unique_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
[email protected]ef762642009-03-05 16:30:25652 if (U_FAILURE(error))
Ivan Kotenkov75b1c3a2017-10-24 14:47:24653 collator.reset(nullptr);
[email protected]b3c33d462009-06-26 22:29:20654 BookmarkNode* mutable_parent = AsMutable(parent);
Peter Kastingfc86fec62019-05-21 20:43:47655 std::sort(mutable_parent->children_.begin(), mutable_parent->children_.end(),
[email protected]ef762642009-03-05 16:30:25656 SortComparator(collator.get()));
[email protected]e2f86d92009-02-25 00:22:01657
Zinovy Nisaa5aee392018-05-08 16:18:41658 if (store_)
[email protected]997a0362009-03-12 03:10:51659 store_->ScheduleSave();
660
tfarina2fa1d2fb2016-10-19 01:44:31661 for (BookmarkModelObserver& observer : observers_)
662 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]e2f86d92009-02-25 00:22:01663}
664
[email protected]472f95e2013-06-10 16:49:18665void BookmarkModel::ReorderChildren(
666 const BookmarkNode* parent,
[email protected]257d5082013-08-06 07:46:43667 const std::vector<const BookmarkNode*>& ordered_nodes) {
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]472f95e2013-06-10 16:49:18671 // Ensure that all children in |parent| are in |ordered_nodes|.
Peter Kastingb0d21f22019-06-25 00:26:16672 DCHECK_EQ(parent->children().size(), ordered_nodes.size());
avicee78e4e2016-09-30 17:08:14673 for (const BookmarkNode* node : ordered_nodes)
674 DCHECK_EQ(parent, node->parent());
[email protected]472f95e2013-06-10 16:49:18675
tfarina2fa1d2fb2016-10-19 01:44:31676 for (BookmarkModelObserver& observer : observers_)
677 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18678
avicee78e4e2016-09-30 17:08:14679 if (ordered_nodes.size() > 1) {
680 std::map<const BookmarkNode*, int> order;
681 for (size_t i = 0; i < ordered_nodes.size(); ++i)
682 order[ordered_nodes[i]] = i;
[email protected]472f95e2013-06-10 16:49:18683
avicee78e4e2016-09-30 17:08:14684 std::vector<std::unique_ptr<BookmarkNode>> new_children(
685 ordered_nodes.size());
686 BookmarkNode* mutable_parent = AsMutable(parent);
Peter Kastingfc86fec62019-05-21 20:43:47687 for (auto& child : mutable_parent->children_) {
avicee78e4e2016-09-30 17:08:14688 size_t new_location = order[child.get()];
689 new_children[new_location] = std::move(child);
690 }
Peter Kastingfc86fec62019-05-21 20:43:47691 mutable_parent->children_.swap(new_children);
avicee78e4e2016-09-30 17:08:14692
Zinovy Nisaa5aee392018-05-08 16:18:41693 if (store_)
avicee78e4e2016-09-30 17:08:14694 store_->ScheduleSave();
695 }
[email protected]472f95e2013-06-10 16:49:18696
tfarina2fa1d2fb2016-10-19 01:44:31697 for (BookmarkModelObserver& observer : observers_)
698 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]472f95e2013-06-10 16:49:18699}
700
[email protected]c6a7a3d2011-03-12 01:04:30701void BookmarkModel::SetDateFolderModified(const BookmarkNode* parent,
702 const Time time) {
Mikel Astizecaeb702019-12-03 07:11:12703 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]eea8fd5532009-12-16 00:08:10704 DCHECK(parent);
[email protected]edb63cc2011-03-11 02:00:41705 AsMutable(parent)->set_date_folder_modified(time);
[email protected]eea8fd5532009-12-16 00:08:10706
Zinovy Nisaa5aee392018-05-08 16:18:41707 if (store_)
[email protected]eea8fd5532009-12-16 00:08:10708 store_->ScheduleSave();
709}
710
[email protected]c6a7a3d2011-03-12 01:04:30711void BookmarkModel::ResetDateFolderModified(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12712 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]c6a7a3d2011-03-12 01:04:30713 SetDateFolderModified(node, Time());
initial.commit09911bf2008-07-26 23:55:29714}
715
manukhb9a9062b2020-10-16 22:51:17716std::vector<TitledUrlMatch> BookmarkModel::GetBookmarksMatching(
Jan Wilken Dörriefa241ba2021-03-11 17:57:01717 const std::u16string& query,
[email protected]e64e9012010-01-11 23:10:55718 size_t max_count,
manukh92134fdb2020-11-05 20:33:01719 query_parser::MatchingAlgorithm matching_algorithm,
720 bool match_ancestor_titles) {
Mikel Astizecaeb702019-12-03 07:11:12721 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
722
[email protected]01eec882009-05-22 18:13:28723 if (!loaded_)
manukhb9a9062b2020-10-16 22:51:17724 return {};
[email protected]01eec882009-05-22 18:13:28725
manukh92134fdb2020-11-05 20:33:01726 return titled_url_index_->GetResultsMatching(
727 query, max_count, matching_algorithm, match_ancestor_titles);
[email protected]85d911c2009-05-19 03:59:42728}
729
[email protected]9876bb1c2008-12-16 20:42:25730void BookmarkModel::ClearStore() {
Mikel Astizecaeb702019-12-03 07:11:12731 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]265e88e2014-07-07 20:45:19732 store_.reset();
[email protected]9876bb1c2008-12-16 20:42:25733}
734
avicee78e4e2016-09-30 17:08:14735void BookmarkModel::RestoreRemovedNode(const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30736 size_t index,
avicee78e4e2016-09-30 17:08:14737 std::unique_ptr<BookmarkNode> node) {
Mikel Astizecaeb702019-12-03 07:11:12738 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
739
avicee78e4e2016-09-30 17:08:14740 BookmarkNode* node_ptr = node.get();
741 AddNode(AsMutable(parent), index, std::move(node));
jianli14436d52015-10-09 22:47:35742
743 // We might be restoring a folder node that have already contained a set of
744 // child nodes. We need to notify all of them.
manukhb9a9062b2020-10-16 22:51:17745 NotifyNodeAddedForAllDescendants(node_ptr);
jianli14436d52015-10-09 22:47:35746}
747
manukhb9a9062b2020-10-16 22:51:17748void BookmarkModel::NotifyNodeAddedForAllDescendants(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12749 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
750
Peter Kasting8cf4c23e2019-06-06 00:38:30751 for (size_t i = 0; i < node->children().size(); ++i) {
tfarina2fa1d2fb2016-10-19 01:44:31752 for (BookmarkModelObserver& observer : observers_)
753 observer.BookmarkNodeAdded(this, node, i);
manukhb9a9062b2020-10-16 22:51:17754 NotifyNodeAddedForAllDescendants(node->children()[i].get());
jianli14436d52015-10-09 22:47:35755 }
756}
757
Mikel Astizb810f7ac2019-11-06 16:57:00758void BookmarkModel::RemoveNodeFromIndexRecursive(BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12759 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violete349e962018-05-03 20:45:23760 DCHECK(loaded_);
761 DCHECK(!is_permanent_node(node));
[email protected]f25387b2008-08-21 15:20:33762
Scott Violet82ef0fa2018-05-23 18:23:39763 if (node->is_url())
Mikel Astizc69bf852020-01-30 21:48:53764 titled_url_index_->Remove(node);
initial.commit09911bf2008-07-26 23:55:29765
[email protected]abc2f262011-03-15 21:15:44766 CancelPendingFaviconLoadRequests(node);
initial.commit09911bf2008-07-26 23:55:29767
768 // Recurse through children.
Peter Kastingb0d21f22019-06-25 00:26:16769 for (size_t i = node->children().size(); i > 0; --i)
Mikel Astizb810f7ac2019-11-06 16:57:00770 RemoveNodeFromIndexRecursive(node->children()[i - 1].get());
initial.commit09911bf2008-07-26 23:55:29771}
772
dchengacd3f522016-04-21 22:30:41773void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
Mikel Astizecaeb702019-12-03 07:11:12774 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]6a848b52014-04-26 22:06:54775 DCHECK(details);
Scott Violete349e962018-05-03 20:45:23776 DCHECK(!loaded_);
[email protected]01eec882009-05-22 18:13:28777
[email protected]01eec882009-05-22 18:13:28778 next_node_id_ = details->max_id();
[email protected]367d7072009-07-13 23:27:13779 if (details->computed_checksum() != details->stored_checksum() ||
Pauline Leitao44f5a812019-07-30 10:49:51780 details->ids_reassigned() || details->guids_reassigned()) {
[email protected]367d7072009-07-13 23:27:13781 // If bookmarks file changed externally, the IDs may have changed
782 // externally. In that case, the decoder may have reassigned IDs to make
783 // them unique. So when the file has changed externally, we should save the
Pauline Leitao44f5a812019-07-30 10:49:51784 // bookmarks file to persist such changes. The same applies if new GUIDs
785 // have been assigned to bookmarks.
Scott Violete349e962018-05-03 20:45:23786 if (store_)
[email protected]367d7072009-07-13 23:27:13787 store_->ScheduleSave();
788 }
Scott Violete349e962018-05-03 20:45:23789
Mikel Astizc69bf852020-01-30 21:48:53790 titled_url_index_ = details->owned_index();
Scott Violeta772b27d2018-05-31 23:23:21791 url_index_ = details->url_index();
Scott Violet82ef0fa2018-05-23 18:23:39792 root_ = details->root_node();
793 // See declaration for details on why |owned_root_| is reset.
794 owned_root_.reset();
Scott Violete349e962018-05-03 20:45:23795 bookmark_bar_node_ = details->bb_node();
796 other_node_ = details->other_folder_node();
797 mobile_node_ = details->mobile_folder_node();
798
Mikel Astizc69bf852020-01-30 21:48:53799 titled_url_index_->SetNodeSorter(
800 std::make_unique<TypedCountSorter>(client_.get()));
Scott Violete349e962018-05-03 20:45:23801 // Sorting the permanent nodes has to happen on the main thread, so we do it
802 // here, after loading completes.
Peter Kastingfc86fec62019-05-21 20:43:47803 std::stable_sort(root_->children_.begin(), root_->children_.end(),
sdefresne070a5102016-02-01 13:42:14804 VisibilityComparator(client_.get()));
[email protected]6c1164042009-05-08 14:41:08805
Scott Violete349e962018-05-03 20:45:23806 root_->SetMetaInfoMap(details->model_meta_info_map());
[email protected]1858410f2012-10-26 05:06:45807
initial.commit09911bf2008-07-26 23:55:29808 loaded_ = true;
Mohamed Amir Yosefd19506182018-06-19 13:02:14809 client_->DecodeBookmarkSyncMetadata(
810 details->sync_metadata_str(),
811 store_ ? base::BindRepeating(&BookmarkStorage::ScheduleSave,
812 base::Unretained(store_.get()))
813 : base::DoNothing());
initial.commit09911bf2008-07-26 23:55:29814
[email protected]f25387b2008-08-21 15:20:33815 // Notify our direct observers.
tfarina2fa1d2fb2016-10-19 01:44:31816 for (BookmarkModelObserver& observer : observers_)
817 observer.BookmarkModelLoaded(this, details->ids_reassigned());
initial.commit09911bf2008-07-26 23:55:29818}
819
[email protected]d8e41ed2008-09-11 15:22:32820BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30821 size_t index,
avicee78e4e2016-09-30 17:08:14822 std::unique_ptr<BookmarkNode> node) {
Mikel Astizecaeb702019-12-03 07:11:12823 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
824
avicee78e4e2016-09-30 17:08:14825 BookmarkNode* node_ptr = node.get();
Scott Violet82ef0fa2018-05-23 18:23:39826 url_index_->Add(parent, index, std::move(node));
initial.commit09911bf2008-07-26 23:55:29827
Zinovy Nisaa5aee392018-05-08 16:18:41828 if (store_)
[email protected]f25387b2008-08-21 15:20:33829 store_->ScheduleSave();
830
Scott Violet82ef0fa2018-05-23 18:23:39831 AddNodeToIndexRecursive(node_ptr);
danduongf4fde322014-11-04 18:56:56832
tfarina2fa1d2fb2016-10-19 01:44:31833 for (BookmarkModelObserver& observer : observers_)
834 observer.BookmarkNodeAdded(this, parent, index);
[email protected]f25387b2008-08-21 15:20:33835
avicee78e4e2016-09-30 17:08:14836 return node_ptr;
initial.commit09911bf2008-07-26 23:55:29837}
838
manukhb9a9062b2020-10-16 22:51:17839void BookmarkModel::AddNodeToIndexRecursive(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12840 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
841
Rushan Suleymanov551c70b2020-10-28 18:54:26842 // TODO(crbug.com/1143246): add a DCHECK to validate that all nodes have
843 // unique GUID when it is guaranteed.
844
Scott Violet82ef0fa2018-05-23 18:23:39845 if (node->is_url())
Mikel Astizc69bf852020-01-30 21:48:53846 titled_url_index_->Add(node);
Mikel Astize1634392020-02-25 17:12:40847
Peter Kastingb0d21f22019-06-25 00:26:16848 for (const auto& child : node->children())
849 AddNodeToIndexRecursive(child.get());
danduongf4fde322014-11-04 18:56:56850}
851
[email protected]b3c33d462009-06-26 22:29:20852bool BookmarkModel::IsValidIndex(const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30853 size_t index,
[email protected]d8e41ed2008-09-11 15:22:32854 bool allow_end) {
Mikel Astizecaeb702019-12-03 07:11:12855 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kasting8cf4c23e2019-06-06 00:38:30856 return parent && parent->is_folder() &&
857 (index < parent->children().size() ||
858 (allow_end && index == parent->children().size()));
[email protected]bd1b96702009-07-08 21:54:14859}
[email protected]f25387b2008-08-21 15:20:33860
[email protected]abc2f262011-03-15 21:15:44861void BookmarkModel::OnFaviconDataAvailable(
[email protected]0ea3db52012-12-07 01:32:01862 BookmarkNode* node,
[email protected]7627e0b42014-04-17 17:20:53863 const favicon_base::FaviconImageResult& image_result) {
Mikel Astizecaeb702019-12-03 07:11:12864 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]4167c3a2008-08-21 18:12:20865 DCHECK(node);
Mikel Astizecaeb702019-12-03 07:11:12866
[email protected]e95b717f2014-02-06 13:47:13867 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
[email protected]bcc38612012-10-23 01:10:27868 node->set_favicon_state(BookmarkNode::LOADED_FAVICON);
[email protected]65baa222012-08-30 15:43:51869 if (!image_result.image.IsEmpty()) {
870 node->set_favicon(image_result.image);
[email protected]2ad0e872012-11-30 01:24:46871 node->set_icon_url(image_result.icon_url);
[email protected]65baa222012-08-30 15:43:51872 FaviconLoaded(node);
Mikel Astiz55b3fe202017-11-08 20:54:50873 } else {
874 // No favicon available, but we still notify observers.
875 FaviconLoaded(node);
initial.commit09911bf2008-07-26 23:55:29876 }
877}
878
Mikel Astizbf0fc33a2020-08-03 11:19:03879void BookmarkModel::LoadFavicon(BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12880 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
881
[email protected]0890e60e2011-06-27 14:55:21882 if (node->is_folder())
initial.commit09911bf2008-07-26 23:55:29883 return;
884
[email protected]5d4077542011-07-21 20:24:07885 DCHECK(node->url().is_valid());
[email protected]504fca82014-05-07 22:48:08886 node->set_favicon_state(BookmarkNode::LOADING_FAVICON);
[email protected]25244a932014-07-12 23:00:24887 base::CancelableTaskTracker::TaskId taskId =
888 client_->GetFaviconImageForPageURL(
Mikel Astizbf0fc33a2020-08-03 11:19:03889 node->url(),
danakje8f4a2022019-12-13 20:37:39890 base::BindOnce(&BookmarkModel::OnFaviconDataAvailable,
Mikel Astizbf0fc33a2020-08-03 11:19:03891 base::Unretained(this), node),
[email protected]25244a932014-07-12 23:00:24892 &cancelable_task_tracker_);
[email protected]6a848b52014-04-26 22:06:54893 if (taskId != base::CancelableTaskTracker::kBadTaskId)
894 node->set_favicon_load_task_id(taskId);
initial.commit09911bf2008-07-26 23:55:29895}
896
[email protected]5b5c9b7f32011-07-21 01:07:18897void BookmarkModel::FaviconLoaded(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12898 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina2fa1d2fb2016-10-19 01:44:31899 for (BookmarkModelObserver& observer : observers_)
900 observer.BookmarkNodeFaviconChanged(this, node);
[email protected]5b5c9b7f32011-07-21 01:07:18901}
902
[email protected]abc2f262011-03-15 21:15:44903void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12904 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]e95b717f2014-02-06 13:47:13905 if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) {
[email protected]0ea3db52012-12-07 01:32:01906 cancelable_task_tracker_.TryCancel(node->favicon_load_task_id());
[email protected]e95b717f2014-02-06 13:47:13907 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
initial.commit09911bf2008-07-26 23:55:29908 }
909}
910
avibc5337b2015-12-25 23:16:33911int64_t BookmarkModel::generate_next_node_id() {
Mikel Astizecaeb702019-12-03 07:11:12912 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violete349e962018-05-03 20:45:23913 DCHECK(loaded_);
[email protected]4d89f382009-05-12 06:56:49914 return next_node_id_++;
915}
[email protected]01eec882009-05-22 18:13:28916
jianli14436d52015-10-09 22:47:35917void BookmarkModel::SetUndoDelegate(BookmarkUndoDelegate* undo_delegate) {
Mikel Astizecaeb702019-12-03 07:11:12918 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
jianli14436d52015-10-09 22:47:35919 undo_delegate_ = undo_delegate;
920 if (undo_delegate_)
921 undo_delegate_->SetUndoProvider(this);
922}
923
924BookmarkUndoDelegate* BookmarkModel::undo_delegate() const {
Mikel Astizecaeb702019-12-03 07:11:12925 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
jianli14436d52015-10-09 22:47:35926 return undo_delegate_ ? undo_delegate_ : empty_undo_delegate_.get();
927}
928
tfarinaa0ec34e2015-01-12 18:46:48929} // namespace bookmarks