blob: 267563cd54150d081753f7ec4f228ebb09644e5d [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"
Pauline Leitao44f5a812019-07-30 10:49:5115#include "base/guid.h"
[email protected]9a08fe82013-04-23 05:06:0516#include "base/i18n/string_compare.h"
[email protected]6a848b52014-04-26 22:06:5417#include "base/logging.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"
[email protected]6a848b52014-04-26 22:06:5420#include "base/strings/string_util.h"
[email protected]a90c8ca2014-05-20 17:16:0421#include "components/bookmarks/browser/bookmark_expanded_state_tracker.h"
[email protected]a90c8ca2014-05-20 17:16:0422#include "components/bookmarks/browser/bookmark_model_observer.h"
23#include "components/bookmarks/browser/bookmark_node_data.h"
24#include "components/bookmarks/browser/bookmark_storage.h"
jianli14436d52015-10-09 22:47:3525#include "components/bookmarks/browser/bookmark_undo_delegate.h"
[email protected]a90c8ca2014-05-20 17:16:0426#include "components/bookmarks/browser/bookmark_utils.h"
Scott Violeta772b27d2018-05-31 23:23:2127#include "components/bookmarks/browser/model_loader.h"
mattreynolds25e9a312016-12-14 21:52:1328#include "components/bookmarks/browser/titled_url_index.h"
29#include "components/bookmarks/browser/titled_url_match.h"
mattreynolds191b88722016-12-13 19:25:3230#include "components/bookmarks/browser/typed_count_sorter.h"
Scott Violet8aa6d57602018-04-25 15:46:2131#include "components/bookmarks/browser/url_and_title.h"
Scott Violet82ef0fa2018-05-23 18:23:3932#include "components/bookmarks/browser/url_index.h"
Scott Violete349e962018-05-03 20:45:2333#include "components/bookmarks/common/bookmark_constants.h"
[email protected]7627e0b42014-04-17 17:20:5334#include "components/favicon_base/favicon_types.h"
thakisfe8fa0a2017-02-23 19:46:3635#include "components/strings/grit/components_strings.h"
[email protected]c051a1b2011-01-21 23:30:1736#include "ui/base/l10n/l10n_util.h"
[email protected]65baa222012-08-30 15:43:5137#include "ui/gfx/favicon_size.h"
initial.commit09911bf2008-07-26 23:55:2938
[email protected]e1acf6f2008-10-27 20:43:3339using base::Time;
tfarinaa0ec34e2015-01-12 18:46:4840
41namespace bookmarks {
[email protected]e1acf6f2008-10-27 20:43:3342
[email protected]b3c33d462009-06-26 22:29:2043namespace {
44
45// Helper to get a mutable bookmark node.
[email protected]7b084b02011-07-08 16:06:4846BookmarkNode* AsMutable(const BookmarkNode* node) {
[email protected]b3c33d462009-06-26 22:29:2047 return const_cast<BookmarkNode*>(node);
48}
49
[email protected]996dbe82014-05-12 12:32:1850// Helper to get a mutable permanent bookmark node.
51BookmarkPermanentNode* AsMutable(const BookmarkPermanentNode* node) {
52 return const_cast<BookmarkPermanentNode*>(node);
53}
54
55// Comparator used when sorting permanent nodes. Nodes that are initially
56// visible are sorted before nodes that are initially hidden.
vmpstr3abe3302016-03-09 19:38:1957class VisibilityComparator {
[email protected]996dbe82014-05-12 12:32:1858 public:
59 explicit VisibilityComparator(BookmarkClient* client) : client_(client) {}
60
avicee78e4e2016-09-30 17:08:1461 // Returns true if |n1| precedes |n2|.
Scott Violete349e962018-05-03 20:45:2362 bool operator()(const std::unique_ptr<BookmarkNode>& n1,
63 const std::unique_ptr<BookmarkNode>& n2) {
64 DCHECK(n1->is_permanent_node());
65 DCHECK(n2->is_permanent_node());
66 bool n1_visible = client_->IsPermanentNodeVisible(
67 static_cast<BookmarkPermanentNode*>(n1.get()));
68 bool n2_visible = client_->IsPermanentNodeVisible(
69 static_cast<BookmarkPermanentNode*>(n2.get()));
[email protected]996dbe82014-05-12 12:32:1870 return n1_visible != n2_visible && n1_visible;
71 }
72
73 private:
74 BookmarkClient* client_;
75};
76
[email protected]ef762642009-03-05 16:30:2577// Comparator used when sorting bookmarks. Folders are sorted first, then
[email protected]2c685cc22009-08-28 00:17:4478// bookmarks.
vmpstr3abe3302016-03-09 19:38:1979class SortComparator {
[email protected]ef762642009-03-05 16:30:2580 public:
[email protected]a48f87d2012-10-09 18:06:3381 explicit SortComparator(icu::Collator* collator) : collator_(collator) {}
[email protected]ef762642009-03-05 16:30:2582
avicee78e4e2016-09-30 17:08:1483 // Returns true if |n1| precedes |n2|.
84 bool operator()(const std::unique_ptr<BookmarkNode>& n1,
85 const std::unique_ptr<BookmarkNode>& n2) {
[email protected]037db002009-10-19 20:06:0886 if (n1->type() == n2->type()) {
[email protected]ef762642009-03-05 16:30:2587 // Types are the same, compare the names.
88 if (!collator_)
[email protected]440b37b22010-08-30 05:31:4089 return n1->GetTitle() < n2->GetTitle();
[email protected]9a08fe82013-04-23 05:06:0590 return base::i18n::CompareString16WithCollator(
estade1274f882015-04-11 05:13:3591 *collator_, n1->GetTitle(), n2->GetTitle()) == UCOL_LESS;
[email protected]ef762642009-03-05 16:30:2592 }
93 // Types differ, sort such that folders come first.
94 return n1->is_folder();
95 }
96
97 private:
[email protected]b5b2385a2009-08-18 05:12:2998 icu::Collator* collator_;
[email protected]ef762642009-03-05 16:30:2599};
100
jianli14436d52015-10-09 22:47:35101// Delegate that does nothing.
102class EmptyUndoDelegate : public BookmarkUndoDelegate {
103 public:
104 EmptyUndoDelegate() {}
105 ~EmptyUndoDelegate() override {}
106
107 private:
108 // BookmarkUndoDelegate:
109 void SetUndoProvider(BookmarkUndoProvider* provider) override {}
110 void OnBookmarkNodeRemoved(BookmarkModel* model,
111 const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30112 size_t index,
dchengacd3f522016-04-21 22:30:41113 std::unique_ptr<BookmarkNode> node) override {}
jianli14436d52015-10-09 22:47:35114
115 DISALLOW_COPY_AND_ASSIGN(EmptyUndoDelegate);
116};
117
[email protected]bc770a032011-12-12 17:35:30118} // namespace
[email protected]97fdd162011-12-03 20:50:12119
[email protected]97fdd162011-12-03 20:50:12120// BookmarkModel --------------------------------------------------------------
121
dchengacd3f522016-04-21 22:30:41122BookmarkModel::BookmarkModel(std::unique_ptr<BookmarkClient> client)
sdefresne070a5102016-02-01 13:42:14123 : client_(std::move(client)),
Pauline Leitao44f5a812019-07-30 10:49:51124 owned_root_(std::make_unique<BookmarkNode>(/*id=*/0,
125 BookmarkNode::RootNodeGuid(),
126 GURL())),
Scott Violet82ef0fa2018-05-23 18:23:39127 root_(owned_root_.get()),
François Degrosd6e2d7dd2017-11-22 05:37:02128 observers_(base::ObserverListPolicy::EXISTING_ONLY),
Scott Violete349e962018-05-03 20:45:23129 empty_undo_delegate_(std::make_unique<EmptyUndoDelegate>()) {
[email protected]6a848b52014-04-26 22:06:54130 DCHECK(client_);
sdefresne070a5102016-02-01 13:42:14131 client_->Init(this);
initial.commit09911bf2008-07-26 23:55:29132}
133
[email protected]d8e41ed2008-09-11 15:22:32134BookmarkModel::~BookmarkModel() {
Mikel Astizecaeb702019-12-03 07:11:12135 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
136
tfarina2fa1d2fb2016-10-19 01:44:31137 for (BookmarkModelObserver& observer : observers_)
138 observer.BookmarkModelBeingDeleted(this);
[email protected]3de6fd342008-09-05 02:44:51139
Zinovy Nisaa5aee392018-05-08 16:18:41140 if (store_) {
[email protected]f25387b2008-08-21 15:20:33141 // The store maintains a reference back to us. We need to tell it we're gone
142 // so that it doesn't try and invoke a method back on us again.
143 store_->BookmarkModelDeleted();
initial.commit09911bf2008-07-26 23:55:29144 }
145}
146
[email protected]afecfb72013-04-18 17:17:33147void BookmarkModel::Load(
[email protected]6a848b52014-04-26 22:06:54148 PrefService* pref_service,
[email protected]6a848b52014-04-26 22:06:54149 const base::FilePath& profile_path,
150 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
151 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) {
Mikel Astizecaeb702019-12-03 07:11:12152 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violete349e962018-05-03 20:45:23153 // If the store is non-null, it means Load was already invoked. Load should
154 // only be invoked once.
155 DCHECK(!store_);
[email protected]90ef13132008-08-27 03:27:46156
Scott Violete349e962018-05-03 20:45:23157 expanded_state_tracker_ =
158 std::make_unique<BookmarkExpandedStateTracker>(this, pref_service);
[email protected]90ef13132008-08-27 03:27:46159
Scott Violete349e962018-05-03 20:45:23160 store_ = std::make_unique<BookmarkStorage>(this, profile_path,
161 io_task_runner.get());
Scott Violeta772b27d2018-05-31 23:23:21162 // Creating ModelLoader schedules the load on |io_task_runner|.
tzik1d5d38a72018-07-27 04:40:10163 model_loader_ = ModelLoader::Create(
Scott Violeta772b27d2018-05-31 23:23:21164 profile_path.Append(kBookmarksFileName), io_task_runner.get(),
165 std::make_unique<BookmarkLoadDetails>(client_.get()),
Mikel Astizecaeb702019-12-03 07:11:12166 base::BindOnce(&BookmarkModel::DoneLoading, AsWeakPtr()));
167}
168
169scoped_refptr<ModelLoader> BookmarkModel::model_loader() {
170 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
171 return model_loader_;
[email protected]90ef13132008-08-27 03:27:46172}
173
[email protected]125b234182011-07-08 19:54:41174void BookmarkModel::AddObserver(BookmarkModelObserver* observer) {
Mikel Astizecaeb702019-12-03 07:11:12175 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]125b234182011-07-08 19:54:41176 observers_.AddObserver(observer);
177}
178
179void BookmarkModel::RemoveObserver(BookmarkModelObserver* observer) {
Mikel Astizecaeb702019-12-03 07:11:12180 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]125b234182011-07-08 19:54:41181 observers_.RemoveObserver(observer);
182}
183
[email protected]b68a8172012-02-17 00:25:18184void BookmarkModel::BeginExtensiveChanges() {
Mikel Astizecaeb702019-12-03 07:11:12185 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]b68a8172012-02-17 00:25:18186 if (++extensive_changes_ == 1) {
tfarina2fa1d2fb2016-10-19 01:44:31187 for (BookmarkModelObserver& observer : observers_)
188 observer.ExtensiveBookmarkChangesBeginning(this);
[email protected]b68a8172012-02-17 00:25:18189 }
[email protected]125b234182011-07-08 19:54:41190}
191
[email protected]b68a8172012-02-17 00:25:18192void BookmarkModel::EndExtensiveChanges() {
Mikel Astizecaeb702019-12-03 07:11:12193 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]b68a8172012-02-17 00:25:18194 --extensive_changes_;
195 DCHECK_GE(extensive_changes_, 0);
196 if (extensive_changes_ == 0) {
tfarina2fa1d2fb2016-10-19 01:44:31197 for (BookmarkModelObserver& observer : observers_)
198 observer.ExtensiveBookmarkChangesEnded(this);
[email protected]b68a8172012-02-17 00:25:18199 }
[email protected]125b234182011-07-08 19:54:41200}
201
[email protected]346453a2014-03-12 10:14:37202void BookmarkModel::BeginGroupedChanges() {
Mikel Astizecaeb702019-12-03 07:11:12203 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina2fa1d2fb2016-10-19 01:44:31204 for (BookmarkModelObserver& observer : observers_)
205 observer.GroupedBookmarkChangesBeginning(this);
[email protected]346453a2014-03-12 10:14:37206}
207
208void BookmarkModel::EndGroupedChanges() {
Mikel Astizecaeb702019-12-03 07:11:12209 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina2fa1d2fb2016-10-19 01:44:31210 for (BookmarkModelObserver& observer : observers_)
211 observer.GroupedBookmarkChangesEnded(this);
[email protected]346453a2014-03-12 10:14:37212}
213
deepak.m139312672015-05-04 16:29:43214void BookmarkModel::Remove(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12215 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina16f92ed42015-06-12 13:54:36216 DCHECK(loaded_);
deepak.m139312672015-05-04 16:29:43217 DCHECK(node);
tfarina16f92ed42015-06-12 13:54:36218 DCHECK(!is_root_node(node));
Scott Violet82ef0fa2018-05-23 18:23:39219 const BookmarkNode* parent = node->parent();
220 DCHECK(parent);
Peter Kasting8cf4c23e2019-06-06 00:38:30221 size_t index = size_t{parent->GetIndexOf(node)};
222 DCHECK_NE(size_t{-1}, index);
Mikel Astiz32dcf91d2019-11-12 19:20:36223
224 // Removing a permanent node is problematic and can cause crashes elsewhere
225 // that are difficult to trace back.
226 CHECK(!is_permanent_node(node)) << "for type " << node->type();
Scott Violet82ef0fa2018-05-23 18:23:39227
228 for (BookmarkModelObserver& observer : observers_)
229 observer.OnWillRemoveBookmarks(this, parent, index, node);
230
231 std::set<GURL> removed_urls;
232 std::unique_ptr<BookmarkNode> owned_node =
233 url_index_->Remove(AsMutable(node), &removed_urls);
Mikel Astizb810f7ac2019-11-06 16:57:00234 RemoveNodeFromIndexRecursive(owned_node.get());
Scott Violet82ef0fa2018-05-23 18:23:39235
236 if (store_)
237 store_->ScheduleSave();
238
239 for (BookmarkModelObserver& observer : observers_)
240 observer.BookmarkNodeRemoved(this, parent, index, node, removed_urls);
241
242 undo_delegate()->OnBookmarkNodeRemoved(this, parent, index,
243 std::move(owned_node));
[email protected]f25387b2008-08-21 15:20:33244}
245
[email protected]5cd942208a2014-06-11 06:16:46246void BookmarkModel::RemoveAllUserBookmarks() {
Mikel Astizecaeb702019-12-03 07:11:12247 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]9109f8a12013-06-12 18:07:48248 std::set<GURL> removed_urls;
jianli14436d52015-10-09 22:47:35249 struct RemoveNodeData {
jianli14436d52015-10-09 22:47:35250 const BookmarkNode* parent;
251 int index;
avicee78e4e2016-09-30 17:08:14252 std::unique_ptr<BookmarkNode> node;
jianli14436d52015-10-09 22:47:35253 };
254 std::vector<RemoveNodeData> removed_node_data_list;
[email protected]472f95e2013-06-10 16:49:18255
tfarina2fa1d2fb2016-10-19 01:44:31256 for (BookmarkModelObserver& observer : observers_)
257 observer.OnWillRemoveAllUserBookmarks(this);
[email protected]472f95e2013-06-10 16:49:18258
[email protected]323dbf72013-03-30 17:08:33259 BeginExtensiveChanges();
260 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and
261 // its immediate children. For removing all non permanent nodes just remove
262 // all children of non-root permanent nodes.
263 {
Peter Kastingb0d21f22019-06-25 00:26:16264 for (const auto& permanent_node : root_->children()) {
265 if (!client_->CanBeEditedByUser(permanent_node.get()))
[email protected]043a76d2014-06-05 16:36:24266 continue;
267
Peter Kastingb0d21f22019-06-25 00:26:16268 for (size_t j = permanent_node->children().size(); j > 0; --j) {
Scott Violet82ef0fa2018-05-23 18:23:39269 std::unique_ptr<BookmarkNode> node = url_index_->Remove(
Peter Kastingb0d21f22019-06-25 00:26:16270 permanent_node->children()[j - 1].get(), &removed_urls);
Mikel Astizb810f7ac2019-11-06 16:57:00271 RemoveNodeFromIndexRecursive(node.get());
Peter Kastingb0d21f22019-06-25 00:26:16272 removed_node_data_list.push_back(
273 {permanent_node.get(), j - 1, std::move(node)});
[email protected]323dbf72013-03-30 17:08:33274 }
275 }
276 }
277 EndExtensiveChanges();
Zinovy Nisaa5aee392018-05-08 16:18:41278 if (store_)
[email protected]323dbf72013-03-30 17:08:33279 store_->ScheduleSave();
280
tfarina2fa1d2fb2016-10-19 01:44:31281 for (BookmarkModelObserver& observer : observers_)
282 observer.BookmarkAllUserNodesRemoved(this, removed_urls);
jianli14436d52015-10-09 22:47:35283
284 BeginGroupedChanges();
avicee78e4e2016-09-30 17:08:14285 for (auto& removed_node_data : removed_node_data_list) {
286 undo_delegate()->OnBookmarkNodeRemoved(this, removed_node_data.parent,
287 removed_node_data.index,
288 std::move(removed_node_data.node));
jianli14436d52015-10-09 22:47:35289 }
290 EndGroupedChanges();
[email protected]5cd942208a2014-06-11 06:16:46291}
292
[email protected]b3c33d462009-06-26 22:29:20293void BookmarkModel::Move(const BookmarkNode* node,
294 const BookmarkNode* new_parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30295 size_t index) {
Mikel Astizecaeb702019-12-03 07:11:12296 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastinga71b6c82019-05-31 18:41:33297 DCHECK(loaded_);
298 DCHECK(node);
299 DCHECK(IsValidIndex(new_parent, index, true));
300 DCHECK(!is_root_node(new_parent));
301 DCHECK(!is_permanent_node(node));
302 DCHECK(!new_parent->HasAncestor(node));
initial.commit09911bf2008-07-26 23:55:29303
[email protected]2d48ee842011-03-08 23:27:29304 const BookmarkNode* old_parent = node->parent();
Peter Kasting8cf4c23e2019-06-06 00:38:30305 size_t old_index = old_parent->GetIndexOf(node);
initial.commit09911bf2008-07-26 23:55:29306
307 if (old_parent == new_parent &&
308 (index == old_index || index == old_index + 1)) {
309 // Node is already in this position, nothing to do.
310 return;
311 }
312
[email protected]9e583642012-12-05 02:48:32313 SetDateFolderModified(new_parent, Time::Now());
314
initial.commit09911bf2008-07-26 23:55:29315 if (old_parent == new_parent && index > old_index)
316 index--;
avicee78e4e2016-09-30 17:08:14317
318 BookmarkNode* mutable_old_parent = AsMutable(old_parent);
319 std::unique_ptr<BookmarkNode> owned_node =
Peter Kasting04fd72422019-06-03 19:21:03320 mutable_old_parent->Remove(old_index);
[email protected]b3c33d462009-06-26 22:29:20321 BookmarkNode* mutable_new_parent = AsMutable(new_parent);
avicee78e4e2016-09-30 17:08:14322 mutable_new_parent->Add(std::move(owned_node), index);
initial.commit09911bf2008-07-26 23:55:29323
Zinovy Nisaa5aee392018-05-08 16:18:41324 if (store_)
[email protected]f25387b2008-08-21 15:20:33325 store_->ScheduleSave();
326
tfarina2fa1d2fb2016-10-19 01:44:31327 for (BookmarkModelObserver& observer : observers_)
328 observer.BookmarkNodeMoved(this, old_parent, old_index, new_parent, index);
initial.commit09911bf2008-07-26 23:55:29329}
330
[email protected]4e187ef652010-03-11 05:21:35331void BookmarkModel::Copy(const BookmarkNode* node,
332 const BookmarkNode* new_parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30333 size_t index) {
Mikel Astizecaeb702019-12-03 07:11:12334 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastinga71b6c82019-05-31 18:41:33335 DCHECK(loaded_);
336 DCHECK(node);
337 DCHECK(IsValidIndex(new_parent, index, true));
338 DCHECK(!is_root_node(new_parent));
339 DCHECK(!is_permanent_node(node));
340 DCHECK(!new_parent->HasAncestor(node));
[email protected]4e187ef652010-03-11 05:21:35341
[email protected]c6a7a3d2011-03-12 01:04:30342 SetDateFolderModified(new_parent, Time::Now());
[email protected]67a8ae42013-05-20 09:42:39343 BookmarkNodeData drag_data(node);
[email protected]b1864502010-11-13 00:55:51344 // CloneBookmarkNode will use BookmarkModel methods to do the job, so we
[email protected]1a566fae2010-04-16 01:05:06345 // don't need to send notifications here.
tfarina8f3c40cc2015-01-20 21:22:50346 CloneBookmarkNode(this, drag_data.elements, new_parent, index, true);
[email protected]4e187ef652010-03-11 05:21:35347
Zinovy Nisaa5aee392018-05-08 16:18:41348 if (store_)
[email protected]4e187ef652010-03-11 05:21:35349 store_->ScheduleSave();
[email protected]4e187ef652010-03-11 05:21:35350}
351
[email protected]6a4e5a02012-06-26 19:47:48352const gfx::Image& BookmarkModel::GetFavicon(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12353 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]ea2e5aa52009-05-20 18:01:28354 DCHECK(node);
[email protected]bcc38612012-10-23 01:10:27355 if (node->favicon_state() == BookmarkNode::INVALID_FAVICON) {
[email protected]b3c33d462009-06-26 22:29:20356 BookmarkNode* mutable_node = AsMutable(node);
Mikel Astiza5ea255f2017-11-06 22:50:15357 LoadFavicon(mutable_node, client_->PreferTouchIcon()
358 ? favicon_base::IconType::kTouchIcon
359 : favicon_base::IconType::kFavicon);
[email protected]ea2e5aa52009-05-20 18:01:28360 }
361 return node->favicon();
362}
363
[email protected]504fca82014-05-07 22:48:08364favicon_base::IconType BookmarkModel::GetFaviconType(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12365 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]504fca82014-05-07 22:48:08366 DCHECK(node);
367 return node->favicon_type();
368}
369
[email protected]6a848b52014-04-26 22:06:54370void BookmarkModel::SetTitle(const BookmarkNode* node,
371 const base::string16& title) {
Mikel Astizecaeb702019-12-03 07:11:12372 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina5ebd5362015-05-12 21:50:10373 DCHECK(node);
374
[email protected]0491ff72011-12-30 00:45:59375 if (node->GetTitle() == title)
initial.commit09911bf2008-07-26 23:55:29376 return;
[email protected]f25387b2008-08-21 15:20:33377
[email protected]043a76d2014-06-05 16:36:24378 if (is_permanent_node(node) && !client_->CanSetPermanentNodeTitle(node)) {
[email protected]baf4f922009-10-19 16:44:07379 NOTREACHED();
380 return;
381 }
382
tfarina2fa1d2fb2016-10-19 01:44:31383 for (BookmarkModelObserver& observer : observers_)
384 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18385
[email protected]85d911c2009-05-19 03:59:42386 // The title index doesn't support changing the title, instead we remove then
Matt Reynoldse33ab142017-11-09 03:06:48387 // add it back. Only do this for URL nodes. A directory node can have its
388 // title changed but should be excluded from the index.
389 if (node->is_url())
Mikel Astizc69bf852020-01-30 21:48:53390 titled_url_index_->Remove(node);
[email protected]0491ff72011-12-30 00:45:59391 AsMutable(node)->SetTitle(title);
Matt Reynoldse33ab142017-11-09 03:06:48392 if (node->is_url())
Mikel Astizc69bf852020-01-30 21:48:53393 titled_url_index_->Add(node);
[email protected]85d911c2009-05-19 03:59:42394
Zinovy Nisaa5aee392018-05-08 16:18:41395 if (store_)
[email protected]f25387b2008-08-21 15:20:33396 store_->ScheduleSave();
397
tfarina2fa1d2fb2016-10-19 01:44:31398 for (BookmarkModelObserver& observer : observers_)
399 observer.BookmarkNodeChanged(this, node);
initial.commit09911bf2008-07-26 23:55:29400}
401
[email protected]e5486602010-02-09 21:27:55402void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) {
Mikel Astizecaeb702019-12-03 07:11:12403 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
404 DCHECK(node);
405 DCHECK(!node->is_folder());
[email protected]e5486602010-02-09 21:27:55406
[email protected]5d4077542011-07-21 20:24:07407 if (node->url() == url)
[email protected]e5486602010-02-09 21:27:55408 return;
409
[email protected]5b5c9b7f32011-07-21 01:07:18410 BookmarkNode* mutable_node = AsMutable(node);
411 mutable_node->InvalidateFavicon();
412 CancelPendingFaviconLoadRequests(mutable_node);
[email protected]e5486602010-02-09 21:27:55413
tfarina2fa1d2fb2016-10-19 01:44:31414 for (BookmarkModelObserver& observer : observers_)
415 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18416
Mikel Astizc69bf852020-01-30 21:48:53417 titled_url_index_->Remove(mutable_node);
Scott Violet82ef0fa2018-05-23 18:23:39418 url_index_->SetUrl(mutable_node, url);
419 AddNodeToIndexRecursive(mutable_node);
[email protected]e5486602010-02-09 21:27:55420
Zinovy Nisaa5aee392018-05-08 16:18:41421 if (store_)
[email protected]e5486602010-02-09 21:27:55422 store_->ScheduleSave();
423
tfarina2fa1d2fb2016-10-19 01:44:31424 for (BookmarkModelObserver& observer : observers_)
425 observer.BookmarkNodeChanged(this, node);
[email protected]e5486602010-02-09 21:27:55426}
427
[email protected]1858410f2012-10-26 05:06:45428void BookmarkModel::SetNodeMetaInfo(const BookmarkNode* node,
429 const std::string& key,
430 const std::string& value) {
Mikel Astizecaeb702019-12-03 07:11:12431 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
432
[email protected]39e113452013-11-26 00:43:06433 std::string old_value;
434 if (node->GetMetaInfo(key, &old_value) && old_value == value)
435 return;
436
tfarina2fa1d2fb2016-10-19 01:44:31437 for (BookmarkModelObserver& observer : observers_)
438 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40439
[email protected]1858410f2012-10-26 05:06:45440 if (AsMutable(node)->SetMetaInfo(key, value) && store_.get())
441 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40442
tfarina2fa1d2fb2016-10-19 01:44:31443 for (BookmarkModelObserver& observer : observers_)
444 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45445}
446
[email protected]e38a87d2013-12-05 01:35:18447void BookmarkModel::SetNodeMetaInfoMap(
448 const BookmarkNode* node,
449 const BookmarkNode::MetaInfoMap& meta_info_map) {
Mikel Astizecaeb702019-12-03 07:11:12450 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
451
[email protected]e38a87d2013-12-05 01:35:18452 const BookmarkNode::MetaInfoMap* old_meta_info_map = node->GetMetaInfoMap();
453 if ((!old_meta_info_map && meta_info_map.empty()) ||
454 (old_meta_info_map && meta_info_map == *old_meta_info_map))
455 return;
456
tfarina2fa1d2fb2016-10-19 01:44:31457 for (BookmarkModelObserver& observer : observers_)
458 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]e38a87d2013-12-05 01:35:18459
460 AsMutable(node)->SetMetaInfoMap(meta_info_map);
Zinovy Nisaa5aee392018-05-08 16:18:41461 if (store_)
[email protected]e38a87d2013-12-05 01:35:18462 store_->ScheduleSave();
463
tfarina2fa1d2fb2016-10-19 01:44:31464 for (BookmarkModelObserver& observer : observers_)
465 observer.BookmarkMetaInfoChanged(this, node);
[email protected]e38a87d2013-12-05 01:35:18466}
467
[email protected]1858410f2012-10-26 05:06:45468void BookmarkModel::DeleteNodeMetaInfo(const BookmarkNode* node,
469 const std::string& key) {
Mikel Astizecaeb702019-12-03 07:11:12470 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
471
[email protected]39e113452013-11-26 00:43:06472 const BookmarkNode::MetaInfoMap* meta_info_map = node->GetMetaInfoMap();
473 if (!meta_info_map || meta_info_map->find(key) == meta_info_map->end())
474 return;
475
tfarina2fa1d2fb2016-10-19 01:44:31476 for (BookmarkModelObserver& observer : observers_)
477 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40478
[email protected]1858410f2012-10-26 05:06:45479 if (AsMutable(node)->DeleteMetaInfo(key) && store_.get())
480 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40481
tfarina2fa1d2fb2016-10-19 01:44:31482 for (BookmarkModelObserver& observer : observers_)
483 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45484}
485
rfevangd75d32212014-12-06 01:27:22486void BookmarkModel::AddNonClonedKey(const std::string& key) {
Mikel Astizecaeb702019-12-03 07:11:12487 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
rfevangd75d32212014-12-06 01:27:22488 non_cloned_keys_.insert(key);
489}
490
[email protected]39e113452013-11-26 00:43:06491void BookmarkModel::SetNodeSyncTransactionVersion(
492 const BookmarkNode* node,
avibc5337b2015-12-25 23:16:33493 int64_t sync_transaction_version) {
Mikel Astizecaeb702019-12-03 07:11:12494 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]043a76d2014-06-05 16:36:24495 DCHECK(client_->CanSyncNode(node));
496
[email protected]39e113452013-11-26 00:43:06497 if (sync_transaction_version == node->sync_transaction_version())
498 return;
499
500 AsMutable(node)->set_sync_transaction_version(sync_transaction_version);
Zinovy Nisaa5aee392018-05-08 16:18:41501 if (store_)
[email protected]39e113452013-11-26 00:43:06502 store_->ScheduleSave();
503}
504
pkotwiczca240dd2015-07-09 16:15:32505void BookmarkModel::OnFaviconsChanged(const std::set<GURL>& page_urls,
506 const GURL& icon_url) {
Mikel Astizecaeb702019-12-03 07:11:12507 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
508
Scott Violet82ef0fa2018-05-23 18:23:39509 if (!loaded_)
510 return;
511
pkotwiczca240dd2015-07-09 16:15:32512 std::set<const BookmarkNode*> to_update;
513 for (const GURL& page_url : page_urls) {
[email protected]6a848b52014-04-26 22:06:54514 std::vector<const BookmarkNode*> nodes;
pkotwiczca240dd2015-07-09 16:15:32515 GetNodesByURL(page_url, &nodes);
516 to_update.insert(nodes.begin(), nodes.end());
517 }
518
519 if (!icon_url.is_empty()) {
520 // Log Histogram to determine how often |icon_url| is non empty in
521 // practice.
522 // TODO(pkotwicz): Do something more efficient if |icon_url| is non-empty
523 // many times a day for each user.
524 UMA_HISTOGRAM_BOOLEAN("Bookmarks.OnFaviconsChangedIconURL", true);
525
Scott Violet82ef0fa2018-05-23 18:23:39526 url_index_->GetNodesWithIconUrl(icon_url, &to_update);
[email protected]6a848b52014-04-26 22:06:54527 }
pkotwiczca240dd2015-07-09 16:15:32528
529 for (const BookmarkNode* node : to_update) {
530 // Rerequest the favicon.
531 BookmarkNode* mutable_node = AsMutable(node);
532 mutable_node->InvalidateFavicon();
533 CancelPendingFaviconLoadRequests(mutable_node);
tfarina2fa1d2fb2016-10-19 01:44:31534 for (BookmarkModelObserver& observer : observers_)
535 observer.BookmarkNodeFaviconChanged(this, node);
pkotwiczca240dd2015-07-09 16:15:32536 }
[email protected]6a848b52014-04-26 22:06:54537}
538
tfarina5ebd5362015-05-12 21:50:10539void BookmarkModel::SetDateAdded(const BookmarkNode* node, Time date_added) {
Mikel Astizecaeb702019-12-03 07:11:12540 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
541 DCHECK(node);
542 DCHECK(!is_permanent_node(node));
[email protected]b61445c2012-10-27 00:11:42543
544 if (node->date_added() == date_added)
545 return;
546
[email protected]b61445c2012-10-27 00:11:42547 AsMutable(node)->set_date_added(date_added);
548
549 // Syncing might result in dates newer than the folder's last modified date.
550 if (date_added > node->parent()->date_folder_modified()) {
551 // Will trigger store_->ScheduleSave().
552 SetDateFolderModified(node->parent(), date_added);
Zinovy Nisaa5aee392018-05-08 16:18:41553 } else if (store_) {
[email protected]b61445c2012-10-27 00:11:42554 store_->ScheduleSave();
555 }
556}
557
[email protected]848cd05e2008-09-19 18:33:48558void BookmarkModel::GetNodesByURL(const GURL& url,
[email protected]b3c33d462009-06-26 22:29:20559 std::vector<const BookmarkNode*>* nodes) {
Mikel Astizecaeb702019-12-03 07:11:12560 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
561
Scott Violet82ef0fa2018-05-23 18:23:39562 if (url_index_)
563 url_index_->GetNodesByUrl(url, nodes);
[email protected]848cd05e2008-09-19 18:33:48564}
565
[email protected]23e39692014-06-06 21:10:13566const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL(
[email protected]b3c33d462009-06-26 22:29:20567 const GURL& url) {
Mikel Astizecaeb702019-12-03 07:11:12568 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
569
[email protected]b3c33d462009-06-26 22:29:20570 std::vector<const BookmarkNode*> nodes;
[email protected]848cd05e2008-09-19 18:33:48571 GetNodesByURL(url, &nodes);
tfarinaa0ec34e2015-01-12 18:46:48572 std::sort(nodes.begin(), nodes.end(), &MoreRecentlyAdded);
[email protected]23e39692014-06-06 21:10:13573
574 // Look for the first node that the user can edit.
575 for (size_t i = 0; i < nodes.size(); ++i) {
576 if (client_->CanBeEditedByUser(nodes[i]))
577 return nodes[i];
578 }
579
Ivan Kotenkov75b1c3a2017-10-24 14:47:24580 return nullptr;
initial.commit09911bf2008-07-26 23:55:29581}
582
[email protected]cf8e8172011-07-23 00:46:24583bool BookmarkModel::HasBookmarks() {
Mikel Astizecaeb702019-12-03 07:11:12584 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violet82ef0fa2018-05-23 18:23:39585 return url_index_ && url_index_->HasBookmarks();
[email protected]cf8e8172011-07-23 00:46:24586}
587
Marti Wongc67da222017-09-01 02:30:01588bool BookmarkModel::HasNoUserCreatedBookmarksOrFolders() {
Mikel Astizecaeb702019-12-03 07:11:12589 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastingfc86fec62019-05-21 20:43:47590 return bookmark_bar_node_->children().empty() &&
591 other_node_->children().empty() && mobile_node_->children().empty();
Marti Wongc67da222017-09-01 02:30:01592}
593
[email protected]cf8e8172011-07-23 00:46:24594bool BookmarkModel::IsBookmarked(const GURL& url) {
Mikel Astizecaeb702019-12-03 07:11:12595 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violet82ef0fa2018-05-23 18:23:39596 return url_index_ && url_index_->IsBookmarked(url);
[email protected]cf8e8172011-07-23 00:46:24597}
598
Scott Violet8aa6d57602018-04-25 15:46:21599void BookmarkModel::GetBookmarks(std::vector<UrlAndTitle>* bookmarks) {
Mikel Astizecaeb702019-12-03 07:11:12600 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violet82ef0fa2018-05-23 18:23:39601 if (url_index_)
602 url_index_->GetBookmarks(bookmarks);
[email protected]90ef13132008-08-27 03:27:46603}
604
Pauline Leitao6a341952019-09-13 15:00:43605const BookmarkNode* BookmarkModel::AddFolder(
[email protected]eb59ad12014-04-24 00:05:08606 const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30607 size_t index,
[email protected]eb59ad12014-04-24 00:05:08608 const base::string16& title,
Pauline Leitao6a341952019-09-13 15:00:43609 const BookmarkNode::MetaInfoMap* meta_info,
610 base::Optional<std::string> 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(!is_root_node(parent));
614 DCHECK(IsValidIndex(parent, index, true));
initial.commit09911bf2008-07-26 23:55:29615
Pauline Leitao6a341952019-09-13 15:00:43616 if (guid)
617 DCHECK(base::IsValidGUID(*guid));
618 else
619 guid = base::GenerateGUID();
620
621 auto new_node =
622 std::make_unique<BookmarkNode>(generate_next_node_id(), *guid, GURL());
[email protected]edb63cc2011-03-11 02:00:41623 new_node->set_date_folder_modified(Time::Now());
[email protected]aee236542011-12-01 04:34:03624 // Folders shouldn't have line breaks in their titles.
[email protected]0491ff72011-12-30 00:45:59625 new_node->SetTitle(title);
[email protected]eb59ad12014-04-24 00:05:08626 if (meta_info)
627 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29628
avicee78e4e2016-09-30 17:08:14629 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29630}
631
Pauline Leitao6a341952019-09-13 15:00:43632const BookmarkNode* BookmarkModel::AddURL(
[email protected]e64e9012010-01-11 23:10:55633 const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30634 size_t index,
[email protected]96920152013-12-04 21:00:16635 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55636 const GURL& url,
Pauline Leitao6a341952019-09-13 15:00:43637 const BookmarkNode::MetaInfoMap* meta_info,
638 base::Optional<base::Time> creation_time,
639 base::Optional<std::string> guid) {
Mikel Astizecaeb702019-12-03 07:11:12640 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kastinga71b6c82019-05-31 18:41:33641 DCHECK(loaded_);
642 DCHECK(url.is_valid());
643 DCHECK(!is_root_node(parent));
644 DCHECK(IsValidIndex(parent, index, true));
initial.commit09911bf2008-07-26 23:55:29645
Pauline Leitao6a341952019-09-13 15:00:43646 if (guid)
647 DCHECK(base::IsValidGUID(*guid));
648 else
649 guid = base::GenerateGUID();
initial.commit09911bf2008-07-26 23:55:29650
Pauline Leitao6a341952019-09-13 15:00:43651 if (!creation_time)
652 creation_time = Time::Now();
653
654 // Syncing may result in dates newer than the last modified date.
655 if (*creation_time > parent->date_folder_modified())
656 SetDateFolderModified(parent, *creation_time);
657
658 auto new_node =
659 std::make_unique<BookmarkNode>(generate_next_node_id(), *guid, url);
[email protected]0491ff72011-12-30 00:45:59660 new_node->SetTitle(title);
Pauline Leitao6a341952019-09-13 15:00:43661 new_node->set_date_added(*creation_time);
[email protected]eb59ad12014-04-24 00:05:08662 if (meta_info)
663 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29664
avicee78e4e2016-09-30 17:08:14665 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29666}
667
[email protected]b3c33d462009-06-26 22:29:20668void BookmarkModel::SortChildren(const BookmarkNode* parent) {
Mikel Astizecaeb702019-12-03 07:11:12669 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]23e39692014-06-06 21:10:13670 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24671
[email protected]6b4d64c2011-07-29 21:33:24672 if (!parent || !parent->is_folder() || is_root_node(parent) ||
Peter Kastingb0d21f22019-06-25 00:26:16673 parent->children().size() <= 1) {
[email protected]e2f86d92009-02-25 00:22:01674 return;
675 }
676
tfarina2fa1d2fb2016-10-19 01:44:31677 for (BookmarkModelObserver& observer : observers_)
678 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18679
[email protected]ef762642009-03-05 16:30:25680 UErrorCode error = U_ZERO_ERROR;
dchengacd3f522016-04-21 22:30:41681 std::unique_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
[email protected]ef762642009-03-05 16:30:25682 if (U_FAILURE(error))
Ivan Kotenkov75b1c3a2017-10-24 14:47:24683 collator.reset(nullptr);
[email protected]b3c33d462009-06-26 22:29:20684 BookmarkNode* mutable_parent = AsMutable(parent);
Peter Kastingfc86fec62019-05-21 20:43:47685 std::sort(mutable_parent->children_.begin(), mutable_parent->children_.end(),
[email protected]ef762642009-03-05 16:30:25686 SortComparator(collator.get()));
[email protected]e2f86d92009-02-25 00:22:01687
Zinovy Nisaa5aee392018-05-08 16:18:41688 if (store_)
[email protected]997a0362009-03-12 03:10:51689 store_->ScheduleSave();
690
tfarina2fa1d2fb2016-10-19 01:44:31691 for (BookmarkModelObserver& observer : observers_)
692 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]e2f86d92009-02-25 00:22:01693}
694
[email protected]472f95e2013-06-10 16:49:18695void BookmarkModel::ReorderChildren(
696 const BookmarkNode* parent,
[email protected]257d5082013-08-06 07:46:43697 const std::vector<const BookmarkNode*>& ordered_nodes) {
Mikel Astizecaeb702019-12-03 07:11:12698 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]23e39692014-06-06 21:10:13699 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24700
[email protected]472f95e2013-06-10 16:49:18701 // Ensure that all children in |parent| are in |ordered_nodes|.
Peter Kastingb0d21f22019-06-25 00:26:16702 DCHECK_EQ(parent->children().size(), ordered_nodes.size());
avicee78e4e2016-09-30 17:08:14703 for (const BookmarkNode* node : ordered_nodes)
704 DCHECK_EQ(parent, node->parent());
[email protected]472f95e2013-06-10 16:49:18705
tfarina2fa1d2fb2016-10-19 01:44:31706 for (BookmarkModelObserver& observer : observers_)
707 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18708
avicee78e4e2016-09-30 17:08:14709 if (ordered_nodes.size() > 1) {
710 std::map<const BookmarkNode*, int> order;
711 for (size_t i = 0; i < ordered_nodes.size(); ++i)
712 order[ordered_nodes[i]] = i;
[email protected]472f95e2013-06-10 16:49:18713
avicee78e4e2016-09-30 17:08:14714 std::vector<std::unique_ptr<BookmarkNode>> new_children(
715 ordered_nodes.size());
716 BookmarkNode* mutable_parent = AsMutable(parent);
Peter Kastingfc86fec62019-05-21 20:43:47717 for (auto& child : mutable_parent->children_) {
avicee78e4e2016-09-30 17:08:14718 size_t new_location = order[child.get()];
719 new_children[new_location] = std::move(child);
720 }
Peter Kastingfc86fec62019-05-21 20:43:47721 mutable_parent->children_.swap(new_children);
avicee78e4e2016-09-30 17:08:14722
Zinovy Nisaa5aee392018-05-08 16:18:41723 if (store_)
avicee78e4e2016-09-30 17:08:14724 store_->ScheduleSave();
725 }
[email protected]472f95e2013-06-10 16:49:18726
tfarina2fa1d2fb2016-10-19 01:44:31727 for (BookmarkModelObserver& observer : observers_)
728 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]472f95e2013-06-10 16:49:18729}
730
[email protected]c6a7a3d2011-03-12 01:04:30731void BookmarkModel::SetDateFolderModified(const BookmarkNode* parent,
732 const Time time) {
Mikel Astizecaeb702019-12-03 07:11:12733 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]eea8fd5532009-12-16 00:08:10734 DCHECK(parent);
[email protected]edb63cc2011-03-11 02:00:41735 AsMutable(parent)->set_date_folder_modified(time);
[email protected]eea8fd5532009-12-16 00:08:10736
Zinovy Nisaa5aee392018-05-08 16:18:41737 if (store_)
[email protected]eea8fd5532009-12-16 00:08:10738 store_->ScheduleSave();
739}
740
[email protected]c6a7a3d2011-03-12 01:04:30741void BookmarkModel::ResetDateFolderModified(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12742 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]c6a7a3d2011-03-12 01:04:30743 SetDateFolderModified(node, Time());
initial.commit09911bf2008-07-26 23:55:29744}
745
kkimlabsf1a7a3732014-11-04 10:30:46746void BookmarkModel::GetBookmarksMatching(const base::string16& text,
747 size_t max_count,
mattreynolds25e9a312016-12-14 21:52:13748 std::vector<TitledUrlMatch>* matches) {
Mikel Astizecaeb702019-12-03 07:11:12749 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
kkimlabsf1a7a3732014-11-04 10:30:46750 GetBookmarksMatching(text, max_count,
751 query_parser::MatchingAlgorithm::DEFAULT, matches);
752}
753
[email protected]b3a84892014-04-23 04:28:07754void BookmarkModel::GetBookmarksMatching(
[email protected]96920152013-12-04 21:00:16755 const base::string16& text,
[email protected]e64e9012010-01-11 23:10:55756 size_t max_count,
kkimlabsf1a7a3732014-11-04 10:30:46757 query_parser::MatchingAlgorithm matching_algorithm,
mattreynolds25e9a312016-12-14 21:52:13758 std::vector<TitledUrlMatch>* matches) {
Mikel Astizecaeb702019-12-03 07:11:12759 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
760
[email protected]01eec882009-05-22 18:13:28761 if (!loaded_)
762 return;
763
Mikel Astizc69bf852020-01-30 21:48:53764 titled_url_index_->GetResultsMatching(text, max_count, matching_algorithm,
765 matches);
[email protected]85d911c2009-05-19 03:59:42766}
767
[email protected]9876bb1c2008-12-16 20:42:25768void BookmarkModel::ClearStore() {
Mikel Astizecaeb702019-12-03 07:11:12769 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]265e88e2014-07-07 20:45:19770 store_.reset();
[email protected]9876bb1c2008-12-16 20:42:25771}
772
[email protected]bc770a032011-12-12 17:35:30773void BookmarkModel::SetPermanentNodeVisible(BookmarkNode::Type type,
774 bool value) {
Mikel Astizecaeb702019-12-03 07:11:12775 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]043a76d2014-06-05 16:36:24776 BookmarkPermanentNode* node = AsMutable(PermanentNode(type));
777 node->set_visible(value || client_->IsPermanentNodeVisible(node));
[email protected]996dbe82014-05-12 12:32:18778}
779
780const BookmarkPermanentNode* BookmarkModel::PermanentNode(
781 BookmarkNode::Type type) {
Mikel Astizecaeb702019-12-03 07:11:12782 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]1da5f712011-12-06 05:52:26783 DCHECK(loaded_);
Mikel Astizecaeb702019-12-03 07:11:12784
[email protected]bc770a032011-12-12 17:35:30785 switch (type) {
786 case BookmarkNode::BOOKMARK_BAR:
[email protected]996dbe82014-05-12 12:32:18787 return bookmark_bar_node_;
[email protected]bc770a032011-12-12 17:35:30788 case BookmarkNode::OTHER_NODE:
[email protected]996dbe82014-05-12 12:32:18789 return other_node_;
[email protected]bc770a032011-12-12 17:35:30790 case BookmarkNode::MOBILE:
[email protected]996dbe82014-05-12 12:32:18791 return mobile_node_;
[email protected]bc770a032011-12-12 17:35:30792 default:
793 NOTREACHED();
Ivan Kotenkov75b1c3a2017-10-24 14:47:24794 return nullptr;
[email protected]bc770a032011-12-12 17:35:30795 }
[email protected]1da5f712011-12-06 05:52:26796}
797
avicee78e4e2016-09-30 17:08:14798void BookmarkModel::RestoreRemovedNode(const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30799 size_t index,
avicee78e4e2016-09-30 17:08:14800 std::unique_ptr<BookmarkNode> node) {
Mikel Astizecaeb702019-12-03 07:11:12801 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
802
avicee78e4e2016-09-30 17:08:14803 BookmarkNode* node_ptr = node.get();
804 AddNode(AsMutable(parent), index, std::move(node));
jianli14436d52015-10-09 22:47:35805
806 // We might be restoring a folder node that have already contained a set of
807 // child nodes. We need to notify all of them.
avicee78e4e2016-09-30 17:08:14808 NotifyNodeAddedForAllDescendents(node_ptr);
jianli14436d52015-10-09 22:47:35809}
810
811void BookmarkModel::NotifyNodeAddedForAllDescendents(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12812 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
813
Peter Kasting8cf4c23e2019-06-06 00:38:30814 for (size_t i = 0; i < node->children().size(); ++i) {
tfarina2fa1d2fb2016-10-19 01:44:31815 for (BookmarkModelObserver& observer : observers_)
816 observer.BookmarkNodeAdded(this, node, i);
Peter Kasting51745902019-06-28 21:54:55817 NotifyNodeAddedForAllDescendents(node->children()[i].get());
jianli14436d52015-10-09 22:47:35818 }
819}
820
Mikel Astizb810f7ac2019-11-06 16:57:00821void BookmarkModel::RemoveNodeFromIndexRecursive(BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12822 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violete349e962018-05-03 20:45:23823 DCHECK(loaded_);
824 DCHECK(!is_permanent_node(node));
[email protected]f25387b2008-08-21 15:20:33825
Scott Violet82ef0fa2018-05-23 18:23:39826 if (node->is_url())
Mikel Astizc69bf852020-01-30 21:48:53827 titled_url_index_->Remove(node);
initial.commit09911bf2008-07-26 23:55:29828
[email protected]abc2f262011-03-15 21:15:44829 CancelPendingFaviconLoadRequests(node);
initial.commit09911bf2008-07-26 23:55:29830
831 // Recurse through children.
Peter Kastingb0d21f22019-06-25 00:26:16832 for (size_t i = node->children().size(); i > 0; --i)
Mikel Astizb810f7ac2019-11-06 16:57:00833 RemoveNodeFromIndexRecursive(node->children()[i - 1].get());
initial.commit09911bf2008-07-26 23:55:29834}
835
dchengacd3f522016-04-21 22:30:41836void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
Mikel Astizecaeb702019-12-03 07:11:12837 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]6a848b52014-04-26 22:06:54838 DCHECK(details);
Scott Violete349e962018-05-03 20:45:23839 DCHECK(!loaded_);
[email protected]01eec882009-05-22 18:13:28840
[email protected]01eec882009-05-22 18:13:28841 next_node_id_ = details->max_id();
[email protected]367d7072009-07-13 23:27:13842 if (details->computed_checksum() != details->stored_checksum() ||
Pauline Leitao44f5a812019-07-30 10:49:51843 details->ids_reassigned() || details->guids_reassigned()) {
[email protected]367d7072009-07-13 23:27:13844 // If bookmarks file changed externally, the IDs may have changed
845 // externally. In that case, the decoder may have reassigned IDs to make
846 // them unique. So when the file has changed externally, we should save the
Pauline Leitao44f5a812019-07-30 10:49:51847 // bookmarks file to persist such changes. The same applies if new GUIDs
848 // have been assigned to bookmarks.
Scott Violete349e962018-05-03 20:45:23849 if (store_)
[email protected]367d7072009-07-13 23:27:13850 store_->ScheduleSave();
851 }
Scott Violete349e962018-05-03 20:45:23852
Mikel Astizc69bf852020-01-30 21:48:53853 titled_url_index_ = details->owned_index();
Scott Violeta772b27d2018-05-31 23:23:21854 url_index_ = details->url_index();
Scott Violet82ef0fa2018-05-23 18:23:39855 root_ = details->root_node();
856 // See declaration for details on why |owned_root_| is reset.
857 owned_root_.reset();
Scott Violete349e962018-05-03 20:45:23858 bookmark_bar_node_ = details->bb_node();
859 other_node_ = details->other_folder_node();
860 mobile_node_ = details->mobile_folder_node();
861
Mikel Astizc69bf852020-01-30 21:48:53862 titled_url_index_->SetNodeSorter(
863 std::make_unique<TypedCountSorter>(client_.get()));
Scott Violete349e962018-05-03 20:45:23864 // Sorting the permanent nodes has to happen on the main thread, so we do it
865 // here, after loading completes.
Peter Kastingfc86fec62019-05-21 20:43:47866 std::stable_sort(root_->children_.begin(), root_->children_.end(),
sdefresne070a5102016-02-01 13:42:14867 VisibilityComparator(client_.get()));
[email protected]6c1164042009-05-08 14:41:08868
Scott Violete349e962018-05-03 20:45:23869 root_->SetMetaInfoMap(details->model_meta_info_map());
870 root_->set_sync_transaction_version(
871 details->model_sync_transaction_version());
[email protected]1858410f2012-10-26 05:06:45872
initial.commit09911bf2008-07-26 23:55:29873 loaded_ = true;
Mohamed Amir Yosefd19506182018-06-19 13:02:14874 client_->DecodeBookmarkSyncMetadata(
875 details->sync_metadata_str(),
876 store_ ? base::BindRepeating(&BookmarkStorage::ScheduleSave,
877 base::Unretained(store_.get()))
878 : base::DoNothing());
initial.commit09911bf2008-07-26 23:55:29879
[email protected]f25387b2008-08-21 15:20:33880 // Notify our direct observers.
tfarina2fa1d2fb2016-10-19 01:44:31881 for (BookmarkModelObserver& observer : observers_)
882 observer.BookmarkModelLoaded(this, details->ids_reassigned());
initial.commit09911bf2008-07-26 23:55:29883}
884
[email protected]d8e41ed2008-09-11 15:22:32885BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30886 size_t index,
avicee78e4e2016-09-30 17:08:14887 std::unique_ptr<BookmarkNode> node) {
Mikel Astizecaeb702019-12-03 07:11:12888 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
889
avicee78e4e2016-09-30 17:08:14890 BookmarkNode* node_ptr = node.get();
Scott Violet82ef0fa2018-05-23 18:23:39891 url_index_->Add(parent, index, std::move(node));
initial.commit09911bf2008-07-26 23:55:29892
Zinovy Nisaa5aee392018-05-08 16:18:41893 if (store_)
[email protected]f25387b2008-08-21 15:20:33894 store_->ScheduleSave();
895
Scott Violet82ef0fa2018-05-23 18:23:39896 AddNodeToIndexRecursive(node_ptr);
danduongf4fde322014-11-04 18:56:56897
tfarina2fa1d2fb2016-10-19 01:44:31898 for (BookmarkModelObserver& observer : observers_)
899 observer.BookmarkNodeAdded(this, parent, index);
[email protected]f25387b2008-08-21 15:20:33900
avicee78e4e2016-09-30 17:08:14901 return node_ptr;
initial.commit09911bf2008-07-26 23:55:29902}
903
Scott Violet82ef0fa2018-05-23 18:23:39904void BookmarkModel::AddNodeToIndexRecursive(BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12905 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
906
Scott Violet82ef0fa2018-05-23 18:23:39907 if (node->is_url())
Mikel Astizc69bf852020-01-30 21:48:53908 titled_url_index_->Add(node);
Peter Kastingb0d21f22019-06-25 00:26:16909 for (const auto& child : node->children())
910 AddNodeToIndexRecursive(child.get());
danduongf4fde322014-11-04 18:56:56911}
912
[email protected]b3c33d462009-06-26 22:29:20913bool BookmarkModel::IsValidIndex(const BookmarkNode* parent,
Peter Kasting8cf4c23e2019-06-06 00:38:30914 size_t index,
[email protected]d8e41ed2008-09-11 15:22:32915 bool allow_end) {
Mikel Astizecaeb702019-12-03 07:11:12916 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Peter Kasting8cf4c23e2019-06-06 00:38:30917 return parent && parent->is_folder() &&
918 (index < parent->children().size() ||
919 (allow_end && index == parent->children().size()));
[email protected]bd1b96702009-07-08 21:54:14920}
[email protected]f25387b2008-08-21 15:20:33921
[email protected]abc2f262011-03-15 21:15:44922void BookmarkModel::OnFaviconDataAvailable(
[email protected]0ea3db52012-12-07 01:32:01923 BookmarkNode* node,
[email protected]504fca82014-05-07 22:48:08924 favicon_base::IconType icon_type,
[email protected]7627e0b42014-04-17 17:20:53925 const favicon_base::FaviconImageResult& image_result) {
Mikel Astizecaeb702019-12-03 07:11:12926 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]4167c3a2008-08-21 18:12:20927 DCHECK(node);
Mikel Astizecaeb702019-12-03 07:11:12928
[email protected]e95b717f2014-02-06 13:47:13929 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
[email protected]bcc38612012-10-23 01:10:27930 node->set_favicon_state(BookmarkNode::LOADED_FAVICON);
[email protected]65baa222012-08-30 15:43:51931 if (!image_result.image.IsEmpty()) {
[email protected]504fca82014-05-07 22:48:08932 node->set_favicon_type(icon_type);
[email protected]65baa222012-08-30 15:43:51933 node->set_favicon(image_result.image);
[email protected]2ad0e872012-11-30 01:24:46934 node->set_icon_url(image_result.icon_url);
[email protected]65baa222012-08-30 15:43:51935 FaviconLoaded(node);
Mikel Astiza5ea255f2017-11-06 22:50:15936 } else if (icon_type == favicon_base::IconType::kTouchIcon) {
[email protected]504fca82014-05-07 22:48:08937 // Couldn't load the touch icon, fallback to the regular favicon.
938 DCHECK(client_->PreferTouchIcon());
Mikel Astiza5ea255f2017-11-06 22:50:15939 LoadFavicon(node, favicon_base::IconType::kFavicon);
Mikel Astiz55b3fe202017-11-08 20:54:50940 } else {
941 // No favicon available, but we still notify observers.
942 FaviconLoaded(node);
initial.commit09911bf2008-07-26 23:55:29943 }
944}
945
tfarinac0baf0b2014-12-08 18:01:21946void BookmarkModel::LoadFavicon(BookmarkNode* node,
947 favicon_base::IconType icon_type) {
Mikel Astizecaeb702019-12-03 07:11:12948 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
949
[email protected]0890e60e2011-06-27 14:55:21950 if (node->is_folder())
initial.commit09911bf2008-07-26 23:55:29951 return;
952
[email protected]5d4077542011-07-21 20:24:07953 DCHECK(node->url().is_valid());
[email protected]504fca82014-05-07 22:48:08954 node->set_favicon_state(BookmarkNode::LOADING_FAVICON);
[email protected]25244a932014-07-12 23:00:24955 base::CancelableTaskTracker::TaskId taskId =
956 client_->GetFaviconImageForPageURL(
danakje8f4a2022019-12-13 20:37:39957 node->url(), icon_type,
958 base::BindOnce(&BookmarkModel::OnFaviconDataAvailable,
959 base::Unretained(this), node, icon_type),
[email protected]25244a932014-07-12 23:00:24960 &cancelable_task_tracker_);
[email protected]6a848b52014-04-26 22:06:54961 if (taskId != base::CancelableTaskTracker::kBadTaskId)
962 node->set_favicon_load_task_id(taskId);
initial.commit09911bf2008-07-26 23:55:29963}
964
[email protected]5b5c9b7f32011-07-21 01:07:18965void BookmarkModel::FaviconLoaded(const BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12966 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tfarina2fa1d2fb2016-10-19 01:44:31967 for (BookmarkModelObserver& observer : observers_)
968 observer.BookmarkNodeFaviconChanged(this, node);
[email protected]5b5c9b7f32011-07-21 01:07:18969}
970
[email protected]abc2f262011-03-15 21:15:44971void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) {
Mikel Astizecaeb702019-12-03 07:11:12972 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
[email protected]e95b717f2014-02-06 13:47:13973 if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) {
[email protected]0ea3db52012-12-07 01:32:01974 cancelable_task_tracker_.TryCancel(node->favicon_load_task_id());
[email protected]e95b717f2014-02-06 13:47:13975 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
initial.commit09911bf2008-07-26 23:55:29976 }
977}
978
avibc5337b2015-12-25 23:16:33979int64_t BookmarkModel::generate_next_node_id() {
Mikel Astizecaeb702019-12-03 07:11:12980 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Scott Violete349e962018-05-03 20:45:23981 DCHECK(loaded_);
[email protected]4d89f382009-05-12 06:56:49982 return next_node_id_++;
983}
[email protected]01eec882009-05-22 18:13:28984
jianli14436d52015-10-09 22:47:35985void BookmarkModel::SetUndoDelegate(BookmarkUndoDelegate* undo_delegate) {
Mikel Astizecaeb702019-12-03 07:11:12986 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
jianli14436d52015-10-09 22:47:35987 undo_delegate_ = undo_delegate;
988 if (undo_delegate_)
989 undo_delegate_->SetUndoProvider(this);
990}
991
992BookmarkUndoDelegate* BookmarkModel::undo_delegate() const {
Mikel Astizecaeb702019-12-03 07:11:12993 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
jianli14436d52015-10-09 22:47:35994 return undo_delegate_ ? undo_delegate_ : empty_undo_delegate_.get();
995}
996
tfarinaa0ec34e2015-01-12 18:46:48997} // namespace bookmarks