blob: 9d316114bfbcb49abbbc441d04eda2834275cba8 [file] [log] [blame]
[email protected]c47f86fa2014-04-30 02:20:181// Copyright 2014 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]a90c8ca2014-05-20 17:16:045#include "components/bookmarks/browser/bookmark_model.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]4e425be42011-01-15 06:56:097#include <algorithm>
8#include <functional>
Gyuyoung Kim6afb5082018-01-19 13:35:579#include <memory>
Mikel Astiz55b3fe202017-11-08 20:54:5010#include <string>
dcheng51606352015-12-26 21:16:2311#include <utility>
[email protected]4e425be42011-01-15 06:56:0912
[email protected]bbdd2982011-10-08 18:14:2413#include "base/bind.h"
14#include "base/bind_helpers.h"
[email protected]9a08fe82013-04-23 05:06:0515#include "base/i18n/string_compare.h"
[email protected]6a848b52014-04-26 22:06:5416#include "base/logging.h"
[email protected]996dbe82014-05-12 12:32:1817#include "base/macros.h"
pkotwiczca240dd2015-07-09 16:15:3218#include "base/metrics/histogram_macros.h"
[email protected]6a848b52014-04-26 22:06:5419#include "base/strings/string_util.h"
[email protected]a90c8ca2014-05-20 17:16:0420#include "components/bookmarks/browser/bookmark_expanded_state_tracker.h"
[email protected]a90c8ca2014-05-20 17:16:0421#include "components/bookmarks/browser/bookmark_model_observer.h"
22#include "components/bookmarks/browser/bookmark_node_data.h"
23#include "components/bookmarks/browser/bookmark_storage.h"
jianli14436d52015-10-09 22:47:3524#include "components/bookmarks/browser/bookmark_undo_delegate.h"
[email protected]a90c8ca2014-05-20 17:16:0425#include "components/bookmarks/browser/bookmark_utils.h"
mattreynolds25e9a312016-12-14 21:52:1326#include "components/bookmarks/browser/titled_url_index.h"
27#include "components/bookmarks/browser/titled_url_match.h"
mattreynolds191b88722016-12-13 19:25:3228#include "components/bookmarks/browser/typed_count_sorter.h"
Scott Violet8aa6d57602018-04-25 15:46:2129#include "components/bookmarks/browser/url_and_title.h"
Scott Violet82ef0fa2018-05-23 18:23:3930#include "components/bookmarks/browser/url_index.h"
Scott Violete349e962018-05-03 20:45:2331#include "components/bookmarks/common/bookmark_constants.h"
[email protected]7627e0b42014-04-17 17:20:5332#include "components/favicon_base/favicon_types.h"
thakisfe8fa0a2017-02-23 19:46:3633#include "components/strings/grit/components_strings.h"
[email protected]c051a1b2011-01-21 23:30:1734#include "ui/base/l10n/l10n_util.h"
[email protected]65baa222012-08-30 15:43:5135#include "ui/gfx/favicon_size.h"
initial.commit09911bf2008-07-26 23:55:2936
[email protected]e1acf6f2008-10-27 20:43:3337using base::Time;
tfarinaa0ec34e2015-01-12 18:46:4838
39namespace bookmarks {
[email protected]e1acf6f2008-10-27 20:43:3340
[email protected]b3c33d462009-06-26 22:29:2041namespace {
42
43// Helper to get a mutable bookmark node.
[email protected]7b084b02011-07-08 16:06:4844BookmarkNode* AsMutable(const BookmarkNode* node) {
[email protected]b3c33d462009-06-26 22:29:2045 return const_cast<BookmarkNode*>(node);
46}
47
[email protected]996dbe82014-05-12 12:32:1848// Helper to get a mutable permanent bookmark node.
49BookmarkPermanentNode* AsMutable(const BookmarkPermanentNode* node) {
50 return const_cast<BookmarkPermanentNode*>(node);
51}
52
53// Comparator used when sorting permanent nodes. Nodes that are initially
54// visible are sorted before nodes that are initially hidden.
vmpstr3abe3302016-03-09 19:38:1955class VisibilityComparator {
[email protected]996dbe82014-05-12 12:32:1856 public:
57 explicit VisibilityComparator(BookmarkClient* client) : client_(client) {}
58
avicee78e4e2016-09-30 17:08:1459 // Returns true if |n1| precedes |n2|.
Scott Violete349e962018-05-03 20:45:2360 bool operator()(const std::unique_ptr<BookmarkNode>& n1,
61 const std::unique_ptr<BookmarkNode>& n2) {
62 DCHECK(n1->is_permanent_node());
63 DCHECK(n2->is_permanent_node());
64 bool n1_visible = client_->IsPermanentNodeVisible(
65 static_cast<BookmarkPermanentNode*>(n1.get()));
66 bool n2_visible = client_->IsPermanentNodeVisible(
67 static_cast<BookmarkPermanentNode*>(n2.get()));
[email protected]996dbe82014-05-12 12:32:1868 return n1_visible != n2_visible && n1_visible;
69 }
70
71 private:
72 BookmarkClient* client_;
73};
74
[email protected]ef762642009-03-05 16:30:2575// Comparator used when sorting bookmarks. Folders are sorted first, then
[email protected]2c685cc22009-08-28 00:17:4476// bookmarks.
vmpstr3abe3302016-03-09 19:38:1977class SortComparator {
[email protected]ef762642009-03-05 16:30:2578 public:
[email protected]a48f87d2012-10-09 18:06:3379 explicit SortComparator(icu::Collator* collator) : collator_(collator) {}
[email protected]ef762642009-03-05 16:30:2580
avicee78e4e2016-09-30 17:08:1481 // Returns true if |n1| precedes |n2|.
82 bool operator()(const std::unique_ptr<BookmarkNode>& n1,
83 const std::unique_ptr<BookmarkNode>& n2) {
[email protected]037db002009-10-19 20:06:0884 if (n1->type() == n2->type()) {
[email protected]ef762642009-03-05 16:30:2585 // Types are the same, compare the names.
86 if (!collator_)
[email protected]440b37b22010-08-30 05:31:4087 return n1->GetTitle() < n2->GetTitle();
[email protected]9a08fe82013-04-23 05:06:0588 return base::i18n::CompareString16WithCollator(
estade1274f882015-04-11 05:13:3589 *collator_, n1->GetTitle(), n2->GetTitle()) == UCOL_LESS;
[email protected]ef762642009-03-05 16:30:2590 }
91 // Types differ, sort such that folders come first.
92 return n1->is_folder();
93 }
94
95 private:
[email protected]b5b2385a2009-08-18 05:12:2996 icu::Collator* collator_;
[email protected]ef762642009-03-05 16:30:2597};
98
jianli14436d52015-10-09 22:47:3599// Delegate that does nothing.
100class EmptyUndoDelegate : public BookmarkUndoDelegate {
101 public:
102 EmptyUndoDelegate() {}
103 ~EmptyUndoDelegate() override {}
104
105 private:
106 // BookmarkUndoDelegate:
107 void SetUndoProvider(BookmarkUndoProvider* provider) override {}
108 void OnBookmarkNodeRemoved(BookmarkModel* model,
109 const BookmarkNode* parent,
110 int index,
dchengacd3f522016-04-21 22:30:41111 std::unique_ptr<BookmarkNode> node) override {}
jianli14436d52015-10-09 22:47:35112
113 DISALLOW_COPY_AND_ASSIGN(EmptyUndoDelegate);
114};
115
Scott Violete349e962018-05-03 20:45:23116void FinishedLoadOnMainThread(
117 base::OnceCallback<void(std::unique_ptr<BookmarkLoadDetails>)> callback,
118 std::unique_ptr<BookmarkLoadDetails> details) {
119 std::move(callback).Run(std::move(details));
120}
121
122void DoLoadOnBackgroundThread(
123 const base::FilePath& profile_path,
124 scoped_refptr<base::SequencedTaskRunner> result_task_runner,
125 base::OnceCallback<void(std::unique_ptr<BookmarkLoadDetails>)> callback,
126 std::unique_ptr<BookmarkLoadDetails> details) {
127 LoadBookmarks(profile_path, details.get());
128 result_task_runner->PostTask(
129 FROM_HERE, base::BindOnce(&FinishedLoadOnMainThread, std::move(callback),
130 std::move(details)));
131}
132
[email protected]bc770a032011-12-12 17:35:30133} // namespace
[email protected]97fdd162011-12-03 20:50:12134
[email protected]97fdd162011-12-03 20:50:12135// BookmarkModel --------------------------------------------------------------
136
dchengacd3f522016-04-21 22:30:41137BookmarkModel::BookmarkModel(std::unique_ptr<BookmarkClient> client)
sdefresne070a5102016-02-01 13:42:14138 : client_(std::move(client)),
Scott Violet82ef0fa2018-05-23 18:23:39139 owned_root_(std::make_unique<BookmarkNode>(GURL())),
140 root_(owned_root_.get()),
François Degrosd6e2d7dd2017-11-22 05:37:02141 observers_(base::ObserverListPolicy::EXISTING_ONLY),
Scott Violete349e962018-05-03 20:45:23142 empty_undo_delegate_(std::make_unique<EmptyUndoDelegate>()) {
[email protected]6a848b52014-04-26 22:06:54143 DCHECK(client_);
sdefresne070a5102016-02-01 13:42:14144 client_->Init(this);
initial.commit09911bf2008-07-26 23:55:29145}
146
[email protected]d8e41ed2008-09-11 15:22:32147BookmarkModel::~BookmarkModel() {
tfarina2fa1d2fb2016-10-19 01:44:31148 for (BookmarkModelObserver& observer : observers_)
149 observer.BookmarkModelBeingDeleted(this);
[email protected]3de6fd342008-09-05 02:44:51150
Zinovy Nisaa5aee392018-05-08 16:18:41151 if (store_) {
[email protected]f25387b2008-08-21 15:20:33152 // The store maintains a reference back to us. We need to tell it we're gone
153 // so that it doesn't try and invoke a method back on us again.
154 store_->BookmarkModelDeleted();
initial.commit09911bf2008-07-26 23:55:29155 }
156}
157
[email protected]f61f4782012-06-08 21:54:21158void BookmarkModel::Shutdown() {
[email protected]88e6a232011-09-14 14:53:20159 if (loaded_)
160 return;
161
[email protected]f61f4782012-06-08 21:54:21162 // See comment in HistoryService::ShutdownOnUIThread where this is invoked for
163 // details. It is also called when the BookmarkModel is deleted.
[email protected]88e6a232011-09-14 14:53:20164 loaded_signal_.Signal();
165}
166
[email protected]afecfb72013-04-18 17:17:33167void BookmarkModel::Load(
[email protected]6a848b52014-04-26 22:06:54168 PrefService* pref_service,
[email protected]6a848b52014-04-26 22:06:54169 const base::FilePath& profile_path,
170 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
171 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) {
Scott Violete349e962018-05-03 20:45:23172 // If the store is non-null, it means Load was already invoked. Load should
173 // only be invoked once.
174 DCHECK(!store_);
[email protected]90ef13132008-08-27 03:27:46175
Scott Violete349e962018-05-03 20:45:23176 expanded_state_tracker_ =
177 std::make_unique<BookmarkExpandedStateTracker>(this, pref_service);
[email protected]90ef13132008-08-27 03:27:46178
Scott Violete349e962018-05-03 20:45:23179 store_ = std::make_unique<BookmarkStorage>(this, profile_path,
180 io_task_runner.get());
181 auto done_loading_callback =
182 base::BindOnce(&BookmarkModel::DoneLoading, weak_factory_.GetWeakPtr());
183 io_task_runner->PostTask(
184 FROM_HERE,
185 base::BindOnce(&DoLoadOnBackgroundThread,
186 profile_path.Append(kBookmarksFileName), ui_task_runner,
187 std::move(done_loading_callback),
188 std::make_unique<BookmarkLoadDetails>(client_.get())));
[email protected]90ef13132008-08-27 03:27:46189}
190
[email protected]125b234182011-07-08 19:54:41191void BookmarkModel::AddObserver(BookmarkModelObserver* observer) {
192 observers_.AddObserver(observer);
193}
194
195void BookmarkModel::RemoveObserver(BookmarkModelObserver* observer) {
196 observers_.RemoveObserver(observer);
197}
198
[email protected]b68a8172012-02-17 00:25:18199void BookmarkModel::BeginExtensiveChanges() {
200 if (++extensive_changes_ == 1) {
tfarina2fa1d2fb2016-10-19 01:44:31201 for (BookmarkModelObserver& observer : observers_)
202 observer.ExtensiveBookmarkChangesBeginning(this);
[email protected]b68a8172012-02-17 00:25:18203 }
[email protected]125b234182011-07-08 19:54:41204}
205
[email protected]b68a8172012-02-17 00:25:18206void BookmarkModel::EndExtensiveChanges() {
207 --extensive_changes_;
208 DCHECK_GE(extensive_changes_, 0);
209 if (extensive_changes_ == 0) {
tfarina2fa1d2fb2016-10-19 01:44:31210 for (BookmarkModelObserver& observer : observers_)
211 observer.ExtensiveBookmarkChangesEnded(this);
[email protected]b68a8172012-02-17 00:25:18212 }
[email protected]125b234182011-07-08 19:54:41213}
214
[email protected]346453a2014-03-12 10:14:37215void BookmarkModel::BeginGroupedChanges() {
tfarina2fa1d2fb2016-10-19 01:44:31216 for (BookmarkModelObserver& observer : observers_)
217 observer.GroupedBookmarkChangesBeginning(this);
[email protected]346453a2014-03-12 10:14:37218}
219
220void BookmarkModel::EndGroupedChanges() {
tfarina2fa1d2fb2016-10-19 01:44:31221 for (BookmarkModelObserver& observer : observers_)
222 observer.GroupedBookmarkChangesEnded(this);
[email protected]346453a2014-03-12 10:14:37223}
224
deepak.m139312672015-05-04 16:29:43225void BookmarkModel::Remove(const BookmarkNode* node) {
tfarina16f92ed42015-06-12 13:54:36226 DCHECK(loaded_);
deepak.m139312672015-05-04 16:29:43227 DCHECK(node);
tfarina16f92ed42015-06-12 13:54:36228 DCHECK(!is_root_node(node));
Scott Violet82ef0fa2018-05-23 18:23:39229 const BookmarkNode* parent = node->parent();
230 DCHECK(parent);
231 int index = parent->GetIndexOf(node);
232 DCHECK_NE(-1, index);
233
234 for (BookmarkModelObserver& observer : observers_)
235 observer.OnWillRemoveBookmarks(this, parent, index, node);
236
237 std::set<GURL> removed_urls;
238 std::unique_ptr<BookmarkNode> owned_node =
239 url_index_->Remove(AsMutable(node), &removed_urls);
240 RemoveNode(owned_node.get());
241
242 if (store_)
243 store_->ScheduleSave();
244
245 for (BookmarkModelObserver& observer : observers_)
246 observer.BookmarkNodeRemoved(this, parent, index, node, removed_urls);
247
248 undo_delegate()->OnBookmarkNodeRemoved(this, parent, index,
249 std::move(owned_node));
[email protected]f25387b2008-08-21 15:20:33250}
251
[email protected]5cd942208a2014-06-11 06:16:46252void BookmarkModel::RemoveAllUserBookmarks() {
[email protected]9109f8a12013-06-12 18:07:48253 std::set<GURL> removed_urls;
jianli14436d52015-10-09 22:47:35254 struct RemoveNodeData {
jianli14436d52015-10-09 22:47:35255 const BookmarkNode* parent;
256 int index;
avicee78e4e2016-09-30 17:08:14257 std::unique_ptr<BookmarkNode> node;
jianli14436d52015-10-09 22:47:35258 };
259 std::vector<RemoveNodeData> removed_node_data_list;
[email protected]472f95e2013-06-10 16:49:18260
tfarina2fa1d2fb2016-10-19 01:44:31261 for (BookmarkModelObserver& observer : observers_)
262 observer.OnWillRemoveAllUserBookmarks(this);
[email protected]472f95e2013-06-10 16:49:18263
[email protected]323dbf72013-03-30 17:08:33264 BeginExtensiveChanges();
265 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and
266 // its immediate children. For removing all non permanent nodes just remove
267 // all children of non-root permanent nodes.
268 {
Scott Violete349e962018-05-03 20:45:23269 for (int i = 0; i < root_->child_count(); ++i) {
270 const BookmarkNode* permanent_node = root_->GetChild(i);
[email protected]043a76d2014-06-05 16:36:24271
[email protected]23e39692014-06-06 21:10:13272 if (!client_->CanBeEditedByUser(permanent_node))
[email protected]043a76d2014-06-05 16:36:24273 continue;
274
[email protected]323dbf72013-03-30 17:08:33275 for (int j = permanent_node->child_count() - 1; j >= 0; --j) {
Scott Violet82ef0fa2018-05-23 18:23:39276 std::unique_ptr<BookmarkNode> node = url_index_->Remove(
avicee78e4e2016-09-30 17:08:14277 AsMutable(permanent_node->GetChild(j)), &removed_urls);
Scott Violet82ef0fa2018-05-23 18:23:39278 RemoveNode(node.get());
avicee78e4e2016-09-30 17:08:14279 removed_node_data_list.push_back({permanent_node, j, std::move(node)});
[email protected]323dbf72013-03-30 17:08:33280 }
281 }
282 }
283 EndExtensiveChanges();
Zinovy Nisaa5aee392018-05-08 16:18:41284 if (store_)
[email protected]323dbf72013-03-30 17:08:33285 store_->ScheduleSave();
286
tfarina2fa1d2fb2016-10-19 01:44:31287 for (BookmarkModelObserver& observer : observers_)
288 observer.BookmarkAllUserNodesRemoved(this, removed_urls);
jianli14436d52015-10-09 22:47:35289
290 BeginGroupedChanges();
avicee78e4e2016-09-30 17:08:14291 for (auto& removed_node_data : removed_node_data_list) {
292 undo_delegate()->OnBookmarkNodeRemoved(this, removed_node_data.parent,
293 removed_node_data.index,
294 std::move(removed_node_data.node));
jianli14436d52015-10-09 22:47:35295 }
296 EndGroupedChanges();
[email protected]5cd942208a2014-06-11 06:16:46297}
298
[email protected]b3c33d462009-06-26 22:29:20299void BookmarkModel::Move(const BookmarkNode* node,
300 const BookmarkNode* new_parent,
[email protected]d8e41ed2008-09-11 15:22:32301 int index) {
[email protected]f25387b2008-08-21 15:20:33302 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
[email protected]6b4d64c2011-07-29 21:33:24303 is_root_node(new_parent) || is_permanent_node(node)) {
initial.commit09911bf2008-07-26 23:55:29304 NOTREACHED();
305 return;
306 }
307
308 if (new_parent->HasAncestor(node)) {
309 // Can't make an ancestor of the node be a child of the node.
310 NOTREACHED();
311 return;
312 }
313
[email protected]2d48ee842011-03-08 23:27:29314 const BookmarkNode* old_parent = node->parent();
[email protected]368f3a72011-03-08 17:17:48315 int old_index = old_parent->GetIndexOf(node);
initial.commit09911bf2008-07-26 23:55:29316
317 if (old_parent == new_parent &&
318 (index == old_index || index == old_index + 1)) {
319 // Node is already in this position, nothing to do.
320 return;
321 }
322
[email protected]9e583642012-12-05 02:48:32323 SetDateFolderModified(new_parent, Time::Now());
324
initial.commit09911bf2008-07-26 23:55:29325 if (old_parent == new_parent && index > old_index)
326 index--;
avicee78e4e2016-09-30 17:08:14327
328 BookmarkNode* mutable_old_parent = AsMutable(old_parent);
329 std::unique_ptr<BookmarkNode> owned_node =
330 mutable_old_parent->Remove(AsMutable(node));
[email protected]b3c33d462009-06-26 22:29:20331 BookmarkNode* mutable_new_parent = AsMutable(new_parent);
avicee78e4e2016-09-30 17:08:14332 mutable_new_parent->Add(std::move(owned_node), index);
initial.commit09911bf2008-07-26 23:55:29333
Zinovy Nisaa5aee392018-05-08 16:18:41334 if (store_)
[email protected]f25387b2008-08-21 15:20:33335 store_->ScheduleSave();
336
tfarina2fa1d2fb2016-10-19 01:44:31337 for (BookmarkModelObserver& observer : observers_)
338 observer.BookmarkNodeMoved(this, old_parent, old_index, new_parent, index);
initial.commit09911bf2008-07-26 23:55:29339}
340
[email protected]4e187ef652010-03-11 05:21:35341void BookmarkModel::Copy(const BookmarkNode* node,
342 const BookmarkNode* new_parent,
343 int index) {
344 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
[email protected]6b4d64c2011-07-29 21:33:24345 is_root_node(new_parent) || is_permanent_node(node)) {
[email protected]4e187ef652010-03-11 05:21:35346 NOTREACHED();
347 return;
348 }
349
350 if (new_parent->HasAncestor(node)) {
351 // Can't make an ancestor of the node be a child of the node.
352 NOTREACHED();
353 return;
354 }
355
[email protected]c6a7a3d2011-03-12 01:04:30356 SetDateFolderModified(new_parent, Time::Now());
[email protected]67a8ae42013-05-20 09:42:39357 BookmarkNodeData drag_data(node);
[email protected]b1864502010-11-13 00:55:51358 // CloneBookmarkNode will use BookmarkModel methods to do the job, so we
[email protected]1a566fae2010-04-16 01:05:06359 // don't need to send notifications here.
tfarina8f3c40cc2015-01-20 21:22:50360 CloneBookmarkNode(this, drag_data.elements, new_parent, index, true);
[email protected]4e187ef652010-03-11 05:21:35361
Zinovy Nisaa5aee392018-05-08 16:18:41362 if (store_)
[email protected]4e187ef652010-03-11 05:21:35363 store_->ScheduleSave();
[email protected]4e187ef652010-03-11 05:21:35364}
365
[email protected]6a4e5a02012-06-26 19:47:48366const gfx::Image& BookmarkModel::GetFavicon(const BookmarkNode* node) {
[email protected]ea2e5aa52009-05-20 18:01:28367 DCHECK(node);
[email protected]bcc38612012-10-23 01:10:27368 if (node->favicon_state() == BookmarkNode::INVALID_FAVICON) {
[email protected]b3c33d462009-06-26 22:29:20369 BookmarkNode* mutable_node = AsMutable(node);
Mikel Astiza5ea2552017-11-06 22:50:15370 LoadFavicon(mutable_node, client_->PreferTouchIcon()
371 ? favicon_base::IconType::kTouchIcon
372 : favicon_base::IconType::kFavicon);
[email protected]ea2e5aa52009-05-20 18:01:28373 }
374 return node->favicon();
375}
376
[email protected]504fca82014-05-07 22:48:08377favicon_base::IconType BookmarkModel::GetFaviconType(const BookmarkNode* node) {
378 DCHECK(node);
379 return node->favicon_type();
380}
381
[email protected]6a848b52014-04-26 22:06:54382void BookmarkModel::SetTitle(const BookmarkNode* node,
383 const base::string16& title) {
tfarina5ebd5362015-05-12 21:50:10384 DCHECK(node);
385
[email protected]0491ff72011-12-30 00:45:59386 if (node->GetTitle() == title)
initial.commit09911bf2008-07-26 23:55:29387 return;
[email protected]f25387b2008-08-21 15:20:33388
[email protected]043a76d2014-06-05 16:36:24389 if (is_permanent_node(node) && !client_->CanSetPermanentNodeTitle(node)) {
[email protected]baf4f922009-10-19 16:44:07390 NOTREACHED();
391 return;
392 }
393
tfarina2fa1d2fb2016-10-19 01:44:31394 for (BookmarkModelObserver& observer : observers_)
395 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18396
[email protected]85d911c2009-05-19 03:59:42397 // The title index doesn't support changing the title, instead we remove then
Matt Reynoldse33ab142017-11-09 03:06:48398 // add it back. Only do this for URL nodes. A directory node can have its
399 // title changed but should be excluded from the index.
400 if (node->is_url())
401 index_->Remove(node);
[email protected]0491ff72011-12-30 00:45:59402 AsMutable(node)->SetTitle(title);
Matt Reynoldse33ab142017-11-09 03:06:48403 if (node->is_url())
404 index_->Add(node);
[email protected]85d911c2009-05-19 03:59:42405
Zinovy Nisaa5aee392018-05-08 16:18:41406 if (store_)
[email protected]f25387b2008-08-21 15:20:33407 store_->ScheduleSave();
408
tfarina2fa1d2fb2016-10-19 01:44:31409 for (BookmarkModelObserver& observer : observers_)
410 observer.BookmarkNodeChanged(this, node);
initial.commit09911bf2008-07-26 23:55:29411}
412
[email protected]e5486602010-02-09 21:27:55413void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) {
tfarina5ebd5362015-05-12 21:50:10414 DCHECK(node && !node->is_folder());
[email protected]e5486602010-02-09 21:27:55415
[email protected]5d4077542011-07-21 20:24:07416 if (node->url() == url)
[email protected]e5486602010-02-09 21:27:55417 return;
418
[email protected]5b5c9b7f32011-07-21 01:07:18419 BookmarkNode* mutable_node = AsMutable(node);
420 mutable_node->InvalidateFavicon();
421 CancelPendingFaviconLoadRequests(mutable_node);
[email protected]e5486602010-02-09 21:27:55422
tfarina2fa1d2fb2016-10-19 01:44:31423 for (BookmarkModelObserver& observer : observers_)
424 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18425
Scott Violet82ef0fa2018-05-23 18:23:39426 index_->Remove(mutable_node);
427 url_index_->SetUrl(mutable_node, url);
428 AddNodeToIndexRecursive(mutable_node);
[email protected]e5486602010-02-09 21:27:55429
Zinovy Nisaa5aee392018-05-08 16:18:41430 if (store_)
[email protected]e5486602010-02-09 21:27:55431 store_->ScheduleSave();
432
tfarina2fa1d2fb2016-10-19 01:44:31433 for (BookmarkModelObserver& observer : observers_)
434 observer.BookmarkNodeChanged(this, node);
[email protected]e5486602010-02-09 21:27:55435}
436
[email protected]1858410f2012-10-26 05:06:45437void BookmarkModel::SetNodeMetaInfo(const BookmarkNode* node,
438 const std::string& key,
439 const std::string& value) {
[email protected]39e113452013-11-26 00:43:06440 std::string old_value;
441 if (node->GetMetaInfo(key, &old_value) && old_value == value)
442 return;
443
tfarina2fa1d2fb2016-10-19 01:44:31444 for (BookmarkModelObserver& observer : observers_)
445 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40446
[email protected]1858410f2012-10-26 05:06:45447 if (AsMutable(node)->SetMetaInfo(key, value) && store_.get())
448 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40449
tfarina2fa1d2fb2016-10-19 01:44:31450 for (BookmarkModelObserver& observer : observers_)
451 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45452}
453
[email protected]e38a87d2013-12-05 01:35:18454void BookmarkModel::SetNodeMetaInfoMap(
455 const BookmarkNode* node,
456 const BookmarkNode::MetaInfoMap& meta_info_map) {
457 const BookmarkNode::MetaInfoMap* old_meta_info_map = node->GetMetaInfoMap();
458 if ((!old_meta_info_map && meta_info_map.empty()) ||
459 (old_meta_info_map && meta_info_map == *old_meta_info_map))
460 return;
461
tfarina2fa1d2fb2016-10-19 01:44:31462 for (BookmarkModelObserver& observer : observers_)
463 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]e38a87d2013-12-05 01:35:18464
465 AsMutable(node)->SetMetaInfoMap(meta_info_map);
Zinovy Nisaa5aee392018-05-08 16:18:41466 if (store_)
[email protected]e38a87d2013-12-05 01:35:18467 store_->ScheduleSave();
468
tfarina2fa1d2fb2016-10-19 01:44:31469 for (BookmarkModelObserver& observer : observers_)
470 observer.BookmarkMetaInfoChanged(this, node);
[email protected]e38a87d2013-12-05 01:35:18471}
472
[email protected]1858410f2012-10-26 05:06:45473void BookmarkModel::DeleteNodeMetaInfo(const BookmarkNode* node,
474 const std::string& key) {
[email protected]39e113452013-11-26 00:43:06475 const BookmarkNode::MetaInfoMap* meta_info_map = node->GetMetaInfoMap();
476 if (!meta_info_map || meta_info_map->find(key) == meta_info_map->end())
477 return;
478
tfarina2fa1d2fb2016-10-19 01:44:31479 for (BookmarkModelObserver& observer : observers_)
480 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40481
[email protected]1858410f2012-10-26 05:06:45482 if (AsMutable(node)->DeleteMetaInfo(key) && store_.get())
483 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40484
tfarina2fa1d2fb2016-10-19 01:44:31485 for (BookmarkModelObserver& observer : observers_)
486 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45487}
488
rfevangd75d32212014-12-06 01:27:22489void BookmarkModel::AddNonClonedKey(const std::string& key) {
490 non_cloned_keys_.insert(key);
491}
492
[email protected]39e113452013-11-26 00:43:06493void BookmarkModel::SetNodeSyncTransactionVersion(
494 const BookmarkNode* node,
avibc5337b2015-12-25 23:16:33495 int64_t sync_transaction_version) {
[email protected]043a76d2014-06-05 16:36:24496 DCHECK(client_->CanSyncNode(node));
497
[email protected]39e113452013-11-26 00:43:06498 if (sync_transaction_version == node->sync_transaction_version())
499 return;
500
501 AsMutable(node)->set_sync_transaction_version(sync_transaction_version);
Zinovy Nisaa5aee392018-05-08 16:18:41502 if (store_)
[email protected]39e113452013-11-26 00:43:06503 store_->ScheduleSave();
504}
505
pkotwiczca240dd2015-07-09 16:15:32506void BookmarkModel::OnFaviconsChanged(const std::set<GURL>& page_urls,
507 const GURL& icon_url) {
Scott Violet82ef0fa2018-05-23 18:23:39508 if (!loaded_)
509 return;
510
pkotwiczca240dd2015-07-09 16:15:32511 std::set<const BookmarkNode*> to_update;
512 for (const GURL& page_url : page_urls) {
[email protected]6a848b52014-04-26 22:06:54513 std::vector<const BookmarkNode*> nodes;
pkotwiczca240dd2015-07-09 16:15:32514 GetNodesByURL(page_url, &nodes);
515 to_update.insert(nodes.begin(), nodes.end());
516 }
517
518 if (!icon_url.is_empty()) {
519 // Log Histogram to determine how often |icon_url| is non empty in
520 // practice.
521 // TODO(pkotwicz): Do something more efficient if |icon_url| is non-empty
522 // many times a day for each user.
523 UMA_HISTOGRAM_BOOLEAN("Bookmarks.OnFaviconsChangedIconURL", true);
524
Scott Violet82ef0fa2018-05-23 18:23:39525 url_index_->GetNodesWithIconUrl(icon_url, &to_update);
[email protected]6a848b52014-04-26 22:06:54526 }
pkotwiczca240dd2015-07-09 16:15:32527
528 for (const BookmarkNode* node : to_update) {
529 // Rerequest the favicon.
530 BookmarkNode* mutable_node = AsMutable(node);
531 mutable_node->InvalidateFavicon();
532 CancelPendingFaviconLoadRequests(mutable_node);
tfarina2fa1d2fb2016-10-19 01:44:31533 for (BookmarkModelObserver& observer : observers_)
534 observer.BookmarkNodeFaviconChanged(this, node);
pkotwiczca240dd2015-07-09 16:15:32535 }
[email protected]6a848b52014-04-26 22:06:54536}
537
tfarina5ebd5362015-05-12 21:50:10538void BookmarkModel::SetDateAdded(const BookmarkNode* node, Time date_added) {
539 DCHECK(node && !is_permanent_node(node));
[email protected]b61445c2012-10-27 00:11:42540
541 if (node->date_added() == date_added)
542 return;
543
[email protected]b61445c2012-10-27 00:11:42544 AsMutable(node)->set_date_added(date_added);
545
546 // Syncing might result in dates newer than the folder's last modified date.
547 if (date_added > node->parent()->date_folder_modified()) {
548 // Will trigger store_->ScheduleSave().
549 SetDateFolderModified(node->parent(), date_added);
Zinovy Nisaa5aee392018-05-08 16:18:41550 } else if (store_) {
[email protected]b61445c2012-10-27 00:11:42551 store_->ScheduleSave();
552 }
553}
554
[email protected]848cd05e2008-09-19 18:33:48555void BookmarkModel::GetNodesByURL(const GURL& url,
[email protected]b3c33d462009-06-26 22:29:20556 std::vector<const BookmarkNode*>* nodes) {
Scott Violet82ef0fa2018-05-23 18:23:39557 if (url_index_)
558 url_index_->GetNodesByUrl(url, nodes);
[email protected]848cd05e2008-09-19 18:33:48559}
560
[email protected]23e39692014-06-06 21:10:13561const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL(
[email protected]b3c33d462009-06-26 22:29:20562 const GURL& url) {
563 std::vector<const BookmarkNode*> nodes;
[email protected]848cd05e2008-09-19 18:33:48564 GetNodesByURL(url, &nodes);
tfarinaa0ec34e2015-01-12 18:46:48565 std::sort(nodes.begin(), nodes.end(), &MoreRecentlyAdded);
[email protected]23e39692014-06-06 21:10:13566
567 // Look for the first node that the user can edit.
568 for (size_t i = 0; i < nodes.size(); ++i) {
569 if (client_->CanBeEditedByUser(nodes[i]))
570 return nodes[i];
571 }
572
Ivan Kotenkov75b1c3a2017-10-24 14:47:24573 return nullptr;
initial.commit09911bf2008-07-26 23:55:29574}
575
[email protected]cf8e8172011-07-23 00:46:24576bool BookmarkModel::HasBookmarks() {
Scott Violet82ef0fa2018-05-23 18:23:39577 return url_index_ && url_index_->HasBookmarks();
[email protected]cf8e8172011-07-23 00:46:24578}
579
Marti Wongc67da222017-09-01 02:30:01580bool BookmarkModel::HasNoUserCreatedBookmarksOrFolders() {
581 return bookmark_bar_node_->empty() && other_node_->empty() &&
582 mobile_node_->empty();
583}
584
[email protected]cf8e8172011-07-23 00:46:24585bool BookmarkModel::IsBookmarked(const GURL& url) {
Scott Violet82ef0fa2018-05-23 18:23:39586 return url_index_ && url_index_->IsBookmarked(url);
[email protected]cf8e8172011-07-23 00:46:24587}
588
Scott Violet8aa6d57602018-04-25 15:46:21589void BookmarkModel::GetBookmarks(std::vector<UrlAndTitle>* bookmarks) {
Scott Violet82ef0fa2018-05-23 18:23:39590 if (url_index_)
591 url_index_->GetBookmarks(bookmarks);
[email protected]90ef13132008-08-27 03:27:46592}
593
[email protected]cf8e8172011-07-23 00:46:24594void BookmarkModel::BlockTillLoaded() {
595 loaded_signal_.Wait();
[email protected]848cd05e2008-09-19 18:33:48596}
597
[email protected]39703292011-03-18 17:03:40598const BookmarkNode* BookmarkModel::AddFolder(const BookmarkNode* parent,
599 int index,
[email protected]96920152013-12-04 21:00:16600 const base::string16& title) {
Ivan Kotenkov75b1c3a2017-10-24 14:47:24601 return AddFolderWithMetaInfo(parent, index, title, nullptr);
[email protected]eb59ad12014-04-24 00:05:08602}
603const BookmarkNode* BookmarkModel::AddFolderWithMetaInfo(
604 const BookmarkNode* parent,
605 int index,
606 const base::string16& title,
607 const BookmarkNode::MetaInfoMap* meta_info) {
[email protected]6b4d64c2011-07-29 21:33:24608 if (!loaded_ || is_root_node(parent) || !IsValidIndex(parent, index, true)) {
initial.commit09911bf2008-07-26 23:55:29609 // Can't add to the root.
610 NOTREACHED();
Ivan Kotenkov75b1c3a2017-10-24 14:47:24611 return nullptr;
initial.commit09911bf2008-07-26 23:55:29612 }
613
avicee78e4e2016-09-30 17:08:14614 std::unique_ptr<BookmarkNode> new_node =
Jinho Bangbefb1c22018-01-16 18:40:10615 std::make_unique<BookmarkNode>(generate_next_node_id(), GURL());
[email protected]edb63cc2011-03-11 02:00:41616 new_node->set_date_folder_modified(Time::Now());
[email protected]aee236542011-12-01 04:34:03617 // Folders shouldn't have line breaks in their titles.
[email protected]0491ff72011-12-30 00:45:59618 new_node->SetTitle(title);
[email protected]037db002009-10-19 20:06:08619 new_node->set_type(BookmarkNode::FOLDER);
[email protected]eb59ad12014-04-24 00:05:08620 if (meta_info)
621 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29622
avicee78e4e2016-09-30 17:08:14623 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29624}
625
[email protected]e64e9012010-01-11 23:10:55626const BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent,
627 int index,
[email protected]96920152013-12-04 21:00:16628 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55629 const GURL& url) {
Ivan Kotenkov75b1c3a2017-10-24 14:47:24630 return AddURLWithCreationTimeAndMetaInfo(parent, index, title, url,
631 Time::Now(), nullptr);
initial.commit09911bf2008-07-26 23:55:29632}
633
[email protected]eb59ad12014-04-24 00:05:08634const BookmarkNode* BookmarkModel::AddURLWithCreationTimeAndMetaInfo(
[email protected]e64e9012010-01-11 23:10:55635 const BookmarkNode* parent,
636 int index,
[email protected]96920152013-12-04 21:00:16637 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55638 const GURL& url,
[email protected]eb59ad12014-04-24 00:05:08639 const Time& creation_time,
640 const BookmarkNode::MetaInfoMap* meta_info) {
[email protected]6b4d64c2011-07-29 21:33:24641 if (!loaded_ || !url.is_valid() || is_root_node(parent) ||
[email protected]f25387b2008-08-21 15:20:33642 !IsValidIndex(parent, index, true)) {
initial.commit09911bf2008-07-26 23:55:29643 NOTREACHED();
Ivan Kotenkov75b1c3a2017-10-24 14:47:24644 return nullptr;
initial.commit09911bf2008-07-26 23:55:29645 }
initial.commit09911bf2008-07-26 23:55:29646
[email protected]b61445c2012-10-27 00:11:42647 // Syncing may result in dates newer than the last modified date.
[email protected]8ad613b2012-10-12 21:28:45648 if (creation_time > parent->date_folder_modified())
649 SetDateFolderModified(parent, creation_time);
initial.commit09911bf2008-07-26 23:55:29650
avicee78e4e2016-09-30 17:08:14651 std::unique_ptr<BookmarkNode> new_node =
Jinho Bangbefb1c22018-01-16 18:40:10652 std::make_unique<BookmarkNode>(generate_next_node_id(), url);
[email protected]0491ff72011-12-30 00:45:59653 new_node->SetTitle(title);
[email protected]b3c33d462009-06-26 22:29:20654 new_node->set_date_added(creation_time);
[email protected]037db002009-10-19 20:06:08655 new_node->set_type(BookmarkNode::URL);
[email protected]eb59ad12014-04-24 00:05:08656 if (meta_info)
657 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29658
avicee78e4e2016-09-30 17:08:14659 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29660}
661
[email protected]b3c33d462009-06-26 22:29:20662void BookmarkModel::SortChildren(const BookmarkNode* parent) {
[email protected]23e39692014-06-06 21:10:13663 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24664
[email protected]6b4d64c2011-07-29 21:33:24665 if (!parent || !parent->is_folder() || is_root_node(parent) ||
[email protected]9c1a75a2011-03-10 02:38:12666 parent->child_count() <= 1) {
[email protected]e2f86d92009-02-25 00:22:01667 return;
668 }
669
tfarina2fa1d2fb2016-10-19 01:44:31670 for (BookmarkModelObserver& observer : observers_)
671 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18672
[email protected]ef762642009-03-05 16:30:25673 UErrorCode error = U_ZERO_ERROR;
dchengacd3f522016-04-21 22:30:41674 std::unique_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
[email protected]ef762642009-03-05 16:30:25675 if (U_FAILURE(error))
Ivan Kotenkov75b1c3a2017-10-24 14:47:24676 collator.reset(nullptr);
[email protected]b3c33d462009-06-26 22:29:20677 BookmarkNode* mutable_parent = AsMutable(parent);
678 std::sort(mutable_parent->children().begin(),
679 mutable_parent->children().end(),
[email protected]ef762642009-03-05 16:30:25680 SortComparator(collator.get()));
[email protected]e2f86d92009-02-25 00:22:01681
Zinovy Nisaa5aee392018-05-08 16:18:41682 if (store_)
[email protected]997a0362009-03-12 03:10:51683 store_->ScheduleSave();
684
tfarina2fa1d2fb2016-10-19 01:44:31685 for (BookmarkModelObserver& observer : observers_)
686 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]e2f86d92009-02-25 00:22:01687}
688
[email protected]472f95e2013-06-10 16:49:18689void BookmarkModel::ReorderChildren(
690 const BookmarkNode* parent,
[email protected]257d5082013-08-06 07:46:43691 const std::vector<const BookmarkNode*>& ordered_nodes) {
[email protected]23e39692014-06-06 21:10:13692 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24693
[email protected]472f95e2013-06-10 16:49:18694 // Ensure that all children in |parent| are in |ordered_nodes|.
695 DCHECK_EQ(static_cast<size_t>(parent->child_count()), ordered_nodes.size());
avicee78e4e2016-09-30 17:08:14696 for (const BookmarkNode* node : ordered_nodes)
697 DCHECK_EQ(parent, node->parent());
[email protected]472f95e2013-06-10 16:49:18698
tfarina2fa1d2fb2016-10-19 01:44:31699 for (BookmarkModelObserver& observer : observers_)
700 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18701
avicee78e4e2016-09-30 17:08:14702 if (ordered_nodes.size() > 1) {
703 std::map<const BookmarkNode*, int> order;
704 for (size_t i = 0; i < ordered_nodes.size(); ++i)
705 order[ordered_nodes[i]] = i;
[email protected]472f95e2013-06-10 16:49:18706
avicee78e4e2016-09-30 17:08:14707 std::vector<std::unique_ptr<BookmarkNode>> new_children(
708 ordered_nodes.size());
709 BookmarkNode* mutable_parent = AsMutable(parent);
710 for (auto& child : mutable_parent->children()) {
711 size_t new_location = order[child.get()];
712 new_children[new_location] = std::move(child);
713 }
714 mutable_parent->children().swap(new_children);
715
Zinovy Nisaa5aee392018-05-08 16:18:41716 if (store_)
avicee78e4e2016-09-30 17:08:14717 store_->ScheduleSave();
718 }
[email protected]472f95e2013-06-10 16:49:18719
tfarina2fa1d2fb2016-10-19 01:44:31720 for (BookmarkModelObserver& observer : observers_)
721 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]472f95e2013-06-10 16:49:18722}
723
[email protected]c6a7a3d2011-03-12 01:04:30724void BookmarkModel::SetDateFolderModified(const BookmarkNode* parent,
725 const Time time) {
[email protected]eea8fd5532009-12-16 00:08:10726 DCHECK(parent);
[email protected]edb63cc2011-03-11 02:00:41727 AsMutable(parent)->set_date_folder_modified(time);
[email protected]eea8fd5532009-12-16 00:08:10728
Zinovy Nisaa5aee392018-05-08 16:18:41729 if (store_)
[email protected]eea8fd5532009-12-16 00:08:10730 store_->ScheduleSave();
731}
732
[email protected]c6a7a3d2011-03-12 01:04:30733void BookmarkModel::ResetDateFolderModified(const BookmarkNode* node) {
734 SetDateFolderModified(node, Time());
initial.commit09911bf2008-07-26 23:55:29735}
736
kkimlabsf1a7a3732014-11-04 10:30:46737void BookmarkModel::GetBookmarksMatching(const base::string16& text,
738 size_t max_count,
mattreynolds25e9a312016-12-14 21:52:13739 std::vector<TitledUrlMatch>* matches) {
kkimlabsf1a7a3732014-11-04 10:30:46740 GetBookmarksMatching(text, max_count,
741 query_parser::MatchingAlgorithm::DEFAULT, matches);
742}
743
[email protected]b3a84892014-04-23 04:28:07744void BookmarkModel::GetBookmarksMatching(
[email protected]96920152013-12-04 21:00:16745 const base::string16& text,
[email protected]e64e9012010-01-11 23:10:55746 size_t max_count,
kkimlabsf1a7a3732014-11-04 10:30:46747 query_parser::MatchingAlgorithm matching_algorithm,
mattreynolds25e9a312016-12-14 21:52:13748 std::vector<TitledUrlMatch>* matches) {
[email protected]01eec882009-05-22 18:13:28749 if (!loaded_)
750 return;
751
mattreynolds55324d62016-12-09 23:07:29752 index_->GetResultsMatching(text, max_count, matching_algorithm, matches);
[email protected]85d911c2009-05-19 03:59:42753}
754
[email protected]9876bb1c2008-12-16 20:42:25755void BookmarkModel::ClearStore() {
[email protected]265e88e2014-07-07 20:45:19756 store_.reset();
[email protected]9876bb1c2008-12-16 20:42:25757}
758
[email protected]bc770a032011-12-12 17:35:30759void BookmarkModel::SetPermanentNodeVisible(BookmarkNode::Type type,
760 bool value) {
[email protected]043a76d2014-06-05 16:36:24761 BookmarkPermanentNode* node = AsMutable(PermanentNode(type));
762 node->set_visible(value || client_->IsPermanentNodeVisible(node));
[email protected]996dbe82014-05-12 12:32:18763}
764
765const BookmarkPermanentNode* BookmarkModel::PermanentNode(
766 BookmarkNode::Type type) {
[email protected]1da5f712011-12-06 05:52:26767 DCHECK(loaded_);
[email protected]bc770a032011-12-12 17:35:30768 switch (type) {
769 case BookmarkNode::BOOKMARK_BAR:
[email protected]996dbe82014-05-12 12:32:18770 return bookmark_bar_node_;
[email protected]bc770a032011-12-12 17:35:30771 case BookmarkNode::OTHER_NODE:
[email protected]996dbe82014-05-12 12:32:18772 return other_node_;
[email protected]bc770a032011-12-12 17:35:30773 case BookmarkNode::MOBILE:
[email protected]996dbe82014-05-12 12:32:18774 return mobile_node_;
[email protected]bc770a032011-12-12 17:35:30775 default:
776 NOTREACHED();
Ivan Kotenkov75b1c3a2017-10-24 14:47:24777 return nullptr;
[email protected]bc770a032011-12-12 17:35:30778 }
[email protected]1da5f712011-12-06 05:52:26779}
780
avicee78e4e2016-09-30 17:08:14781void BookmarkModel::RestoreRemovedNode(const BookmarkNode* parent,
782 int index,
783 std::unique_ptr<BookmarkNode> node) {
784 BookmarkNode* node_ptr = node.get();
785 AddNode(AsMutable(parent), index, std::move(node));
jianli14436d52015-10-09 22:47:35786
787 // We might be restoring a folder node that have already contained a set of
788 // child nodes. We need to notify all of them.
avicee78e4e2016-09-30 17:08:14789 NotifyNodeAddedForAllDescendents(node_ptr);
jianli14436d52015-10-09 22:47:35790}
791
792void BookmarkModel::NotifyNodeAddedForAllDescendents(const BookmarkNode* node) {
793 for (int i = 0; i < node->child_count(); ++i) {
tfarina2fa1d2fb2016-10-19 01:44:31794 for (BookmarkModelObserver& observer : observers_)
795 observer.BookmarkNodeAdded(this, node, i);
jianli14436d52015-10-09 22:47:35796 NotifyNodeAddedForAllDescendents(node->GetChild(i));
797 }
798}
799
Scott Violet82ef0fa2018-05-23 18:23:39800void BookmarkModel::RemoveNode(BookmarkNode* node) {
Scott Violete349e962018-05-03 20:45:23801 DCHECK(loaded_);
802 DCHECK(!is_permanent_node(node));
[email protected]f25387b2008-08-21 15:20:33803
Scott Violet82ef0fa2018-05-23 18:23:39804 if (node->is_url())
805 index_->Remove(node);
initial.commit09911bf2008-07-26 23:55:29806
[email protected]abc2f262011-03-15 21:15:44807 CancelPendingFaviconLoadRequests(node);
initial.commit09911bf2008-07-26 23:55:29808
809 // Recurse through children.
[email protected]9c1a75a2011-03-10 02:38:12810 for (int i = node->child_count() - 1; i >= 0; --i)
Scott Violet82ef0fa2018-05-23 18:23:39811 RemoveNode(node->GetChild(i));
initial.commit09911bf2008-07-26 23:55:29812}
813
dchengacd3f522016-04-21 22:30:41814void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
[email protected]6a848b52014-04-26 22:06:54815 DCHECK(details);
Scott Violete349e962018-05-03 20:45:23816 DCHECK(!loaded_);
[email protected]01eec882009-05-22 18:13:28817
[email protected]01eec882009-05-22 18:13:28818 next_node_id_ = details->max_id();
[email protected]367d7072009-07-13 23:27:13819 if (details->computed_checksum() != details->stored_checksum() ||
820 details->ids_reassigned()) {
821 // If bookmarks file changed externally, the IDs may have changed
822 // externally. In that case, the decoder may have reassigned IDs to make
823 // them unique. So when the file has changed externally, we should save the
824 // bookmarks file to persist new IDs.
Scott Violete349e962018-05-03 20:45:23825 if (store_)
[email protected]367d7072009-07-13 23:27:13826 store_->ScheduleSave();
827 }
Scott Violete349e962018-05-03 20:45:23828
Scott Violet82ef0fa2018-05-23 18:23:39829 index_ = details->owned_index();
830 url_index_ = details->owned_url_index();
831 root_ = details->root_node();
832 // See declaration for details on why |owned_root_| is reset.
833 owned_root_.reset();
Scott Violete349e962018-05-03 20:45:23834 bookmark_bar_node_ = details->bb_node();
835 other_node_ = details->other_folder_node();
836 mobile_node_ = details->mobile_folder_node();
837
Scott Violet3c914002018-05-03 18:23:05838 index_->SetNodeSorter(std::make_unique<TypedCountSorter>(client_.get()));
Scott Violete349e962018-05-03 20:45:23839 // Sorting the permanent nodes has to happen on the main thread, so we do it
840 // here, after loading completes.
841 std::stable_sort(root_->children().begin(), root_->children().end(),
sdefresne070a5102016-02-01 13:42:14842 VisibilityComparator(client_.get()));
[email protected]6c1164042009-05-08 14:41:08843
Scott Violete349e962018-05-03 20:45:23844 root_->SetMetaInfoMap(details->model_meta_info_map());
845 root_->set_sync_transaction_version(
846 details->model_sync_transaction_version());
[email protected]1858410f2012-10-26 05:06:45847
initial.commit09911bf2008-07-26 23:55:29848 loaded_ = true;
849
[email protected]cbcd6412009-03-09 22:31:39850 loaded_signal_.Signal();
[email protected]90ef13132008-08-27 03:27:46851
[email protected]f25387b2008-08-21 15:20:33852 // Notify our direct observers.
tfarina2fa1d2fb2016-10-19 01:44:31853 for (BookmarkModelObserver& observer : observers_)
854 observer.BookmarkModelLoaded(this, details->ids_reassigned());
initial.commit09911bf2008-07-26 23:55:29855}
856
[email protected]d8e41ed2008-09-11 15:22:32857BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
858 int index,
avicee78e4e2016-09-30 17:08:14859 std::unique_ptr<BookmarkNode> node) {
860 BookmarkNode* node_ptr = node.get();
Scott Violet82ef0fa2018-05-23 18:23:39861 url_index_->Add(parent, index, std::move(node));
initial.commit09911bf2008-07-26 23:55:29862
Zinovy Nisaa5aee392018-05-08 16:18:41863 if (store_)
[email protected]f25387b2008-08-21 15:20:33864 store_->ScheduleSave();
865
Scott Violet82ef0fa2018-05-23 18:23:39866 AddNodeToIndexRecursive(node_ptr);
danduongf4fde322014-11-04 18:56:56867
tfarina2fa1d2fb2016-10-19 01:44:31868 for (BookmarkModelObserver& observer : observers_)
869 observer.BookmarkNodeAdded(this, parent, index);
[email protected]f25387b2008-08-21 15:20:33870
avicee78e4e2016-09-30 17:08:14871 return node_ptr;
initial.commit09911bf2008-07-26 23:55:29872}
873
Scott Violet82ef0fa2018-05-23 18:23:39874void BookmarkModel::AddNodeToIndexRecursive(BookmarkNode* node) {
875 if (node->is_url())
jianli14436d52015-10-09 22:47:35876 index_->Add(node);
jianli14436d52015-10-09 22:47:35877 for (int i = 0; i < node->child_count(); ++i)
Scott Violet82ef0fa2018-05-23 18:23:39878 AddNodeToIndexRecursive(node->GetChild(i));
danduongf4fde322014-11-04 18:56:56879}
880
[email protected]b3c33d462009-06-26 22:29:20881bool BookmarkModel::IsValidIndex(const BookmarkNode* parent,
[email protected]d8e41ed2008-09-11 15:22:32882 int index,
883 bool allow_end) {
[email protected]776e7492008-10-23 16:47:41884 return (parent && parent->is_folder() &&
[email protected]9c1a75a2011-03-10 02:38:12885 (index >= 0 && (index < parent->child_count() ||
886 (allow_end && index == parent->child_count()))));
[email protected]bd1b96702009-07-08 21:54:14887}
[email protected]f25387b2008-08-21 15:20:33888
[email protected]abc2f262011-03-15 21:15:44889void BookmarkModel::OnFaviconDataAvailable(
[email protected]0ea3db52012-12-07 01:32:01890 BookmarkNode* node,
[email protected]504fca82014-05-07 22:48:08891 favicon_base::IconType icon_type,
[email protected]7627e0b42014-04-17 17:20:53892 const favicon_base::FaviconImageResult& image_result) {
[email protected]4167c3a2008-08-21 18:12:20893 DCHECK(node);
[email protected]e95b717f2014-02-06 13:47:13894 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
[email protected]bcc38612012-10-23 01:10:27895 node->set_favicon_state(BookmarkNode::LOADED_FAVICON);
[email protected]65baa222012-08-30 15:43:51896 if (!image_result.image.IsEmpty()) {
[email protected]504fca82014-05-07 22:48:08897 node->set_favicon_type(icon_type);
[email protected]65baa222012-08-30 15:43:51898 node->set_favicon(image_result.image);
[email protected]2ad0e872012-11-30 01:24:46899 node->set_icon_url(image_result.icon_url);
[email protected]65baa222012-08-30 15:43:51900 FaviconLoaded(node);
Mikel Astiza5ea2552017-11-06 22:50:15901 } else if (icon_type == favicon_base::IconType::kTouchIcon) {
[email protected]504fca82014-05-07 22:48:08902 // Couldn't load the touch icon, fallback to the regular favicon.
903 DCHECK(client_->PreferTouchIcon());
Mikel Astiza5ea2552017-11-06 22:50:15904 LoadFavicon(node, favicon_base::IconType::kFavicon);
Mikel Astiz55b3fe202017-11-08 20:54:50905 } else {
906 // No favicon available, but we still notify observers.
907 FaviconLoaded(node);
initial.commit09911bf2008-07-26 23:55:29908 }
909}
910
tfarinac0baf0b2014-12-08 18:01:21911void BookmarkModel::LoadFavicon(BookmarkNode* node,
912 favicon_base::IconType icon_type) {
[email protected]0890e60e2011-06-27 14:55:21913 if (node->is_folder())
initial.commit09911bf2008-07-26 23:55:29914 return;
915
[email protected]5d4077542011-07-21 20:24:07916 DCHECK(node->url().is_valid());
[email protected]504fca82014-05-07 22:48:08917 node->set_favicon_state(BookmarkNode::LOADING_FAVICON);
[email protected]25244a932014-07-12 23:00:24918 base::CancelableTaskTracker::TaskId taskId =
919 client_->GetFaviconImageForPageURL(
920 node->url(),
921 icon_type,
922 base::Bind(
923 &BookmarkModel::OnFaviconDataAvailable,
924 base::Unretained(this),
925 node,
926 icon_type),
927 &cancelable_task_tracker_);
[email protected]6a848b52014-04-26 22:06:54928 if (taskId != base::CancelableTaskTracker::kBadTaskId)
929 node->set_favicon_load_task_id(taskId);
initial.commit09911bf2008-07-26 23:55:29930}
931
[email protected]5b5c9b7f32011-07-21 01:07:18932void BookmarkModel::FaviconLoaded(const BookmarkNode* node) {
tfarina2fa1d2fb2016-10-19 01:44:31933 for (BookmarkModelObserver& observer : observers_)
934 observer.BookmarkNodeFaviconChanged(this, node);
[email protected]5b5c9b7f32011-07-21 01:07:18935}
936
[email protected]abc2f262011-03-15 21:15:44937void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) {
[email protected]e95b717f2014-02-06 13:47:13938 if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) {
[email protected]0ea3db52012-12-07 01:32:01939 cancelable_task_tracker_.TryCancel(node->favicon_load_task_id());
[email protected]e95b717f2014-02-06 13:47:13940 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
initial.commit09911bf2008-07-26 23:55:29941 }
942}
943
avibc5337b2015-12-25 23:16:33944int64_t BookmarkModel::generate_next_node_id() {
Scott Violete349e962018-05-03 20:45:23945 DCHECK(loaded_);
[email protected]4d89f382009-05-12 06:56:49946 return next_node_id_++;
947}
[email protected]01eec882009-05-22 18:13:28948
jianli14436d52015-10-09 22:47:35949void BookmarkModel::SetUndoDelegate(BookmarkUndoDelegate* undo_delegate) {
950 undo_delegate_ = undo_delegate;
951 if (undo_delegate_)
952 undo_delegate_->SetUndoProvider(this);
953}
954
955BookmarkUndoDelegate* BookmarkModel::undo_delegate() const {
956 return undo_delegate_ ? undo_delegate_ : empty_undo_delegate_.get();
957}
958
tfarinaa0ec34e2015-01-12 18:46:48959} // namespace bookmarks