blob: 99effbff74d26421eadd6185c8fdd08202ef8f0c [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>
Mikel Astiz55b3fe202017-11-08 20:54:509#include <string>
dcheng51606352015-12-26 21:16:2310#include <utility>
[email protected]4e425be42011-01-15 06:56:0911
[email protected]bbdd2982011-10-08 18:14:2412#include "base/bind.h"
13#include "base/bind_helpers.h"
[email protected]9a08fe82013-04-23 05:06:0514#include "base/i18n/string_compare.h"
[email protected]6a848b52014-04-26 22:06:5415#include "base/logging.h"
[email protected]996dbe82014-05-12 12:32:1816#include "base/macros.h"
avicee78e4e2016-09-30 17:08:1417#include "base/memory/ptr_util.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"
[email protected]7627e0b42014-04-17 17:20:5329#include "components/favicon_base/favicon_types.h"
thakisfe8fa0a2017-02-23 19:46:3630#include "components/strings/grit/components_strings.h"
[email protected]c051a1b2011-01-21 23:30:1731#include "ui/base/l10n/l10n_util.h"
[email protected]65baa222012-08-30 15:43:5132#include "ui/gfx/favicon_size.h"
initial.commit09911bf2008-07-26 23:55:2933
[email protected]e1acf6f2008-10-27 20:43:3334using base::Time;
tfarinaa0ec34e2015-01-12 18:46:4835
36namespace bookmarks {
[email protected]e1acf6f2008-10-27 20:43:3337
[email protected]b3c33d462009-06-26 22:29:2038namespace {
39
40// Helper to get a mutable bookmark node.
[email protected]7b084b02011-07-08 16:06:4841BookmarkNode* AsMutable(const BookmarkNode* node) {
[email protected]b3c33d462009-06-26 22:29:2042 return const_cast<BookmarkNode*>(node);
43}
44
[email protected]996dbe82014-05-12 12:32:1845// Helper to get a mutable permanent bookmark node.
46BookmarkPermanentNode* AsMutable(const BookmarkPermanentNode* node) {
47 return const_cast<BookmarkPermanentNode*>(node);
48}
49
50// Comparator used when sorting permanent nodes. Nodes that are initially
51// visible are sorted before nodes that are initially hidden.
vmpstr3abe3302016-03-09 19:38:1952class VisibilityComparator {
[email protected]996dbe82014-05-12 12:32:1853 public:
54 explicit VisibilityComparator(BookmarkClient* client) : client_(client) {}
55
avicee78e4e2016-09-30 17:08:1456 // Returns true if |n1| precedes |n2|.
57 bool operator()(const std::unique_ptr<BookmarkPermanentNode>& n1,
58 const std::unique_ptr<BookmarkPermanentNode>& n2) {
59 bool n1_visible = client_->IsPermanentNodeVisible(n1.get());
60 bool n2_visible = client_->IsPermanentNodeVisible(n2.get());
[email protected]996dbe82014-05-12 12:32:1861 return n1_visible != n2_visible && n1_visible;
62 }
63
64 private:
65 BookmarkClient* client_;
66};
67
[email protected]ef762642009-03-05 16:30:2568// Comparator used when sorting bookmarks. Folders are sorted first, then
[email protected]2c685cc22009-08-28 00:17:4469// bookmarks.
vmpstr3abe3302016-03-09 19:38:1970class SortComparator {
[email protected]ef762642009-03-05 16:30:2571 public:
[email protected]a48f87d2012-10-09 18:06:3372 explicit SortComparator(icu::Collator* collator) : collator_(collator) {}
[email protected]ef762642009-03-05 16:30:2573
avicee78e4e2016-09-30 17:08:1474 // Returns true if |n1| precedes |n2|.
75 bool operator()(const std::unique_ptr<BookmarkNode>& n1,
76 const std::unique_ptr<BookmarkNode>& n2) {
[email protected]037db002009-10-19 20:06:0877 if (n1->type() == n2->type()) {
[email protected]ef762642009-03-05 16:30:2578 // Types are the same, compare the names.
79 if (!collator_)
[email protected]440b37b22010-08-30 05:31:4080 return n1->GetTitle() < n2->GetTitle();
[email protected]9a08fe82013-04-23 05:06:0581 return base::i18n::CompareString16WithCollator(
estade1274f882015-04-11 05:13:3582 *collator_, n1->GetTitle(), n2->GetTitle()) == UCOL_LESS;
[email protected]ef762642009-03-05 16:30:2583 }
84 // Types differ, sort such that folders come first.
85 return n1->is_folder();
86 }
87
88 private:
[email protected]b5b2385a2009-08-18 05:12:2989 icu::Collator* collator_;
[email protected]ef762642009-03-05 16:30:2590};
91
jianli14436d52015-10-09 22:47:3592// Delegate that does nothing.
93class EmptyUndoDelegate : public BookmarkUndoDelegate {
94 public:
95 EmptyUndoDelegate() {}
96 ~EmptyUndoDelegate() override {}
97
98 private:
99 // BookmarkUndoDelegate:
100 void SetUndoProvider(BookmarkUndoProvider* provider) override {}
101 void OnBookmarkNodeRemoved(BookmarkModel* model,
102 const BookmarkNode* parent,
103 int index,
dchengacd3f522016-04-21 22:30:41104 std::unique_ptr<BookmarkNode> node) override {}
jianli14436d52015-10-09 22:47:35105
106 DISALLOW_COPY_AND_ASSIGN(EmptyUndoDelegate);
107};
108
[email protected]bc770a032011-12-12 17:35:30109} // namespace
[email protected]97fdd162011-12-03 20:50:12110
[email protected]97fdd162011-12-03 20:50:12111// BookmarkModel --------------------------------------------------------------
112
dchengacd3f522016-04-21 22:30:41113BookmarkModel::BookmarkModel(std::unique_ptr<BookmarkClient> client)
sdefresne070a5102016-02-01 13:42:14114 : client_(std::move(client)),
initial.commit09911bf2008-07-26 23:55:29115 loaded_(false),
[email protected]ea2e5aa52009-05-20 18:01:28116 root_(GURL()),
Ivan Kotenkov75b1c3a2017-10-24 14:47:24117 bookmark_bar_node_(nullptr),
118 other_node_(nullptr),
119 mobile_node_(nullptr),
[email protected]4d89f382009-05-12 06:56:49120 next_node_id_(1),
brettw236d3172015-06-03 16:31:43121 observers_(
122 base::ObserverList<BookmarkModelObserver>::NOTIFY_EXISTING_ONLY),
gab77f88322016-06-02 13:47:03123 loaded_signal_(base::WaitableEvent::ResetPolicy::MANUAL,
124 base::WaitableEvent::InitialState::NOT_SIGNALED),
jianli14436d52015-10-09 22:47:35125 extensive_changes_(0),
126 undo_delegate_(nullptr),
127 empty_undo_delegate_(new EmptyUndoDelegate) {
[email protected]6a848b52014-04-26 22:06:54128 DCHECK(client_);
sdefresne070a5102016-02-01 13:42:14129 client_->Init(this);
initial.commit09911bf2008-07-26 23:55:29130}
131
[email protected]d8e41ed2008-09-11 15:22:32132BookmarkModel::~BookmarkModel() {
tfarina2fa1d2fb2016-10-19 01:44:31133 for (BookmarkModelObserver& observer : observers_)
134 observer.BookmarkModelBeingDeleted(this);
[email protected]3de6fd342008-09-05 02:44:51135
[email protected]dc24976f2013-06-02 21:15:09136 if (store_.get()) {
[email protected]f25387b2008-08-21 15:20:33137 // The store maintains a reference back to us. We need to tell it we're gone
138 // so that it doesn't try and invoke a method back on us again.
139 store_->BookmarkModelDeleted();
initial.commit09911bf2008-07-26 23:55:29140 }
141}
142
[email protected]f61f4782012-06-08 21:54:21143void BookmarkModel::Shutdown() {
[email protected]88e6a232011-09-14 14:53:20144 if (loaded_)
145 return;
146
[email protected]f61f4782012-06-08 21:54:21147 // See comment in HistoryService::ShutdownOnUIThread where this is invoked for
148 // details. It is also called when the BookmarkModel is deleted.
[email protected]88e6a232011-09-14 14:53:20149 loaded_signal_.Signal();
150}
151
[email protected]afecfb72013-04-18 17:17:33152void BookmarkModel::Load(
[email protected]6a848b52014-04-26 22:06:54153 PrefService* pref_service,
[email protected]6a848b52014-04-26 22:06:54154 const base::FilePath& profile_path,
155 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
156 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) {
[email protected]90ef13132008-08-27 03:27:46157 if (store_.get()) {
158 // If the store is non-null, it means Load was already invoked. Load should
159 // only be invoked once.
160 NOTREACHED();
161 return;
162 }
163
[email protected]6df6ec022013-07-16 03:05:22164 expanded_state_tracker_.reset(
[email protected]6a848b52014-04-26 22:06:54165 new BookmarkExpandedStateTracker(this, pref_service));
[email protected]90ef13132008-08-27 03:27:46166
167 // Load the bookmarks. BookmarkStorage notifies us when done.
skyad686a32015-06-25 17:42:28168 store_.reset(new BookmarkStorage(this, profile_path, io_task_runner.get()));
jshin1fb76462016-04-05 22:13:03169 store_->LoadBookmarks(CreateLoadDetails(), ui_task_runner);
[email protected]90ef13132008-08-27 03:27:46170}
171
[email protected]125b234182011-07-08 19:54:41172void BookmarkModel::AddObserver(BookmarkModelObserver* observer) {
173 observers_.AddObserver(observer);
174}
175
176void BookmarkModel::RemoveObserver(BookmarkModelObserver* observer) {
177 observers_.RemoveObserver(observer);
178}
179
[email protected]b68a8172012-02-17 00:25:18180void BookmarkModel::BeginExtensiveChanges() {
181 if (++extensive_changes_ == 1) {
tfarina2fa1d2fb2016-10-19 01:44:31182 for (BookmarkModelObserver& observer : observers_)
183 observer.ExtensiveBookmarkChangesBeginning(this);
[email protected]b68a8172012-02-17 00:25:18184 }
[email protected]125b234182011-07-08 19:54:41185}
186
[email protected]b68a8172012-02-17 00:25:18187void BookmarkModel::EndExtensiveChanges() {
188 --extensive_changes_;
189 DCHECK_GE(extensive_changes_, 0);
190 if (extensive_changes_ == 0) {
tfarina2fa1d2fb2016-10-19 01:44:31191 for (BookmarkModelObserver& observer : observers_)
192 observer.ExtensiveBookmarkChangesEnded(this);
[email protected]b68a8172012-02-17 00:25:18193 }
[email protected]125b234182011-07-08 19:54:41194}
195
[email protected]346453a2014-03-12 10:14:37196void BookmarkModel::BeginGroupedChanges() {
tfarina2fa1d2fb2016-10-19 01:44:31197 for (BookmarkModelObserver& observer : observers_)
198 observer.GroupedBookmarkChangesBeginning(this);
[email protected]346453a2014-03-12 10:14:37199}
200
201void BookmarkModel::EndGroupedChanges() {
tfarina2fa1d2fb2016-10-19 01:44:31202 for (BookmarkModelObserver& observer : observers_)
203 observer.GroupedBookmarkChangesEnded(this);
[email protected]346453a2014-03-12 10:14:37204}
205
deepak.m139312672015-05-04 16:29:43206void BookmarkModel::Remove(const BookmarkNode* node) {
tfarina16f92ed42015-06-12 13:54:36207 DCHECK(loaded_);
deepak.m139312672015-05-04 16:29:43208 DCHECK(node);
tfarina16f92ed42015-06-12 13:54:36209 DCHECK(!is_root_node(node));
deepak.m139312672015-05-04 16:29:43210 RemoveAndDeleteNode(AsMutable(node));
[email protected]f25387b2008-08-21 15:20:33211}
212
[email protected]5cd942208a2014-06-11 06:16:46213void BookmarkModel::RemoveAllUserBookmarks() {
[email protected]9109f8a12013-06-12 18:07:48214 std::set<GURL> removed_urls;
jianli14436d52015-10-09 22:47:35215 struct RemoveNodeData {
jianli14436d52015-10-09 22:47:35216 const BookmarkNode* parent;
217 int index;
avicee78e4e2016-09-30 17:08:14218 std::unique_ptr<BookmarkNode> node;
jianli14436d52015-10-09 22:47:35219 };
220 std::vector<RemoveNodeData> removed_node_data_list;
[email protected]472f95e2013-06-10 16:49:18221
tfarina2fa1d2fb2016-10-19 01:44:31222 for (BookmarkModelObserver& observer : observers_)
223 observer.OnWillRemoveAllUserBookmarks(this);
[email protected]472f95e2013-06-10 16:49:18224
[email protected]323dbf72013-03-30 17:08:33225 BeginExtensiveChanges();
226 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and
227 // its immediate children. For removing all non permanent nodes just remove
228 // all children of non-root permanent nodes.
229 {
230 base::AutoLock url_lock(url_lock_);
231 for (int i = 0; i < root_.child_count(); ++i) {
jianli14436d52015-10-09 22:47:35232 const BookmarkNode* permanent_node = root_.GetChild(i);
[email protected]043a76d2014-06-05 16:36:24233
[email protected]23e39692014-06-06 21:10:13234 if (!client_->CanBeEditedByUser(permanent_node))
[email protected]043a76d2014-06-05 16:36:24235 continue;
236
[email protected]323dbf72013-03-30 17:08:33237 for (int j = permanent_node->child_count() - 1; j >= 0; --j) {
avicee78e4e2016-09-30 17:08:14238 std::unique_ptr<BookmarkNode> node = RemoveNodeAndGetRemovedUrls(
239 AsMutable(permanent_node->GetChild(j)), &removed_urls);
240 removed_node_data_list.push_back({permanent_node, j, std::move(node)});
[email protected]323dbf72013-03-30 17:08:33241 }
242 }
243 }
244 EndExtensiveChanges();
245 if (store_.get())
246 store_->ScheduleSave();
247
tfarina2fa1d2fb2016-10-19 01:44:31248 for (BookmarkModelObserver& observer : observers_)
249 observer.BookmarkAllUserNodesRemoved(this, removed_urls);
jianli14436d52015-10-09 22:47:35250
251 BeginGroupedChanges();
avicee78e4e2016-09-30 17:08:14252 for (auto& removed_node_data : removed_node_data_list) {
253 undo_delegate()->OnBookmarkNodeRemoved(this, removed_node_data.parent,
254 removed_node_data.index,
255 std::move(removed_node_data.node));
jianli14436d52015-10-09 22:47:35256 }
257 EndGroupedChanges();
[email protected]5cd942208a2014-06-11 06:16:46258}
259
[email protected]b3c33d462009-06-26 22:29:20260void BookmarkModel::Move(const BookmarkNode* node,
261 const BookmarkNode* new_parent,
[email protected]d8e41ed2008-09-11 15:22:32262 int index) {
[email protected]f25387b2008-08-21 15:20:33263 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
[email protected]6b4d64c2011-07-29 21:33:24264 is_root_node(new_parent) || is_permanent_node(node)) {
initial.commit09911bf2008-07-26 23:55:29265 NOTREACHED();
266 return;
267 }
268
269 if (new_parent->HasAncestor(node)) {
270 // Can't make an ancestor of the node be a child of the node.
271 NOTREACHED();
272 return;
273 }
274
[email protected]2d48ee842011-03-08 23:27:29275 const BookmarkNode* old_parent = node->parent();
[email protected]368f3a72011-03-08 17:17:48276 int old_index = old_parent->GetIndexOf(node);
initial.commit09911bf2008-07-26 23:55:29277
278 if (old_parent == new_parent &&
279 (index == old_index || index == old_index + 1)) {
280 // Node is already in this position, nothing to do.
281 return;
282 }
283
[email protected]9e583642012-12-05 02:48:32284 SetDateFolderModified(new_parent, Time::Now());
285
initial.commit09911bf2008-07-26 23:55:29286 if (old_parent == new_parent && index > old_index)
287 index--;
avicee78e4e2016-09-30 17:08:14288
289 BookmarkNode* mutable_old_parent = AsMutable(old_parent);
290 std::unique_ptr<BookmarkNode> owned_node =
291 mutable_old_parent->Remove(AsMutable(node));
[email protected]b3c33d462009-06-26 22:29:20292 BookmarkNode* mutable_new_parent = AsMutable(new_parent);
avicee78e4e2016-09-30 17:08:14293 mutable_new_parent->Add(std::move(owned_node), index);
initial.commit09911bf2008-07-26 23:55:29294
[email protected]f25387b2008-08-21 15:20:33295 if (store_.get())
296 store_->ScheduleSave();
297
tfarina2fa1d2fb2016-10-19 01:44:31298 for (BookmarkModelObserver& observer : observers_)
299 observer.BookmarkNodeMoved(this, old_parent, old_index, new_parent, index);
initial.commit09911bf2008-07-26 23:55:29300}
301
[email protected]4e187ef652010-03-11 05:21:35302void BookmarkModel::Copy(const BookmarkNode* node,
303 const BookmarkNode* new_parent,
304 int index) {
305 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
[email protected]6b4d64c2011-07-29 21:33:24306 is_root_node(new_parent) || is_permanent_node(node)) {
[email protected]4e187ef652010-03-11 05:21:35307 NOTREACHED();
308 return;
309 }
310
311 if (new_parent->HasAncestor(node)) {
312 // Can't make an ancestor of the node be a child of the node.
313 NOTREACHED();
314 return;
315 }
316
[email protected]c6a7a3d2011-03-12 01:04:30317 SetDateFolderModified(new_parent, Time::Now());
[email protected]67a8ae42013-05-20 09:42:39318 BookmarkNodeData drag_data(node);
[email protected]b1864502010-11-13 00:55:51319 // CloneBookmarkNode will use BookmarkModel methods to do the job, so we
[email protected]1a566fae2010-04-16 01:05:06320 // don't need to send notifications here.
tfarina8f3c40cc2015-01-20 21:22:50321 CloneBookmarkNode(this, drag_data.elements, new_parent, index, true);
[email protected]4e187ef652010-03-11 05:21:35322
323 if (store_.get())
324 store_->ScheduleSave();
[email protected]4e187ef652010-03-11 05:21:35325}
326
[email protected]6a4e5a02012-06-26 19:47:48327const gfx::Image& BookmarkModel::GetFavicon(const BookmarkNode* node) {
[email protected]ea2e5aa52009-05-20 18:01:28328 DCHECK(node);
[email protected]bcc38612012-10-23 01:10:27329 if (node->favicon_state() == BookmarkNode::INVALID_FAVICON) {
[email protected]b3c33d462009-06-26 22:29:20330 BookmarkNode* mutable_node = AsMutable(node);
Mikel Astiza5ea255f2017-11-06 22:50:15331 LoadFavicon(mutable_node, client_->PreferTouchIcon()
332 ? favicon_base::IconType::kTouchIcon
333 : favicon_base::IconType::kFavicon);
[email protected]ea2e5aa52009-05-20 18:01:28334 }
335 return node->favicon();
336}
337
[email protected]504fca82014-05-07 22:48:08338favicon_base::IconType BookmarkModel::GetFaviconType(const BookmarkNode* node) {
339 DCHECK(node);
340 return node->favicon_type();
341}
342
[email protected]6a848b52014-04-26 22:06:54343void BookmarkModel::SetTitle(const BookmarkNode* node,
344 const base::string16& title) {
tfarina5ebd5362015-05-12 21:50:10345 DCHECK(node);
346
[email protected]0491ff72011-12-30 00:45:59347 if (node->GetTitle() == title)
initial.commit09911bf2008-07-26 23:55:29348 return;
[email protected]f25387b2008-08-21 15:20:33349
[email protected]043a76d2014-06-05 16:36:24350 if (is_permanent_node(node) && !client_->CanSetPermanentNodeTitle(node)) {
[email protected]baf4f922009-10-19 16:44:07351 NOTREACHED();
352 return;
353 }
354
tfarina2fa1d2fb2016-10-19 01:44:31355 for (BookmarkModelObserver& observer : observers_)
356 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18357
[email protected]85d911c2009-05-19 03:59:42358 // The title index doesn't support changing the title, instead we remove then
359 // add it back.
[email protected]01eec882009-05-22 18:13:28360 index_->Remove(node);
[email protected]0491ff72011-12-30 00:45:59361 AsMutable(node)->SetTitle(title);
[email protected]01eec882009-05-22 18:13:28362 index_->Add(node);
[email protected]85d911c2009-05-19 03:59:42363
[email protected]f25387b2008-08-21 15:20:33364 if (store_.get())
365 store_->ScheduleSave();
366
tfarina2fa1d2fb2016-10-19 01:44:31367 for (BookmarkModelObserver& observer : observers_)
368 observer.BookmarkNodeChanged(this, node);
initial.commit09911bf2008-07-26 23:55:29369}
370
[email protected]e5486602010-02-09 21:27:55371void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) {
tfarina5ebd5362015-05-12 21:50:10372 DCHECK(node && !node->is_folder());
[email protected]e5486602010-02-09 21:27:55373
[email protected]5d4077542011-07-21 20:24:07374 if (node->url() == url)
[email protected]e5486602010-02-09 21:27:55375 return;
376
[email protected]5b5c9b7f32011-07-21 01:07:18377 BookmarkNode* mutable_node = AsMutable(node);
378 mutable_node->InvalidateFavicon();
379 CancelPendingFaviconLoadRequests(mutable_node);
[email protected]e5486602010-02-09 21:27:55380
tfarina2fa1d2fb2016-10-19 01:44:31381 for (BookmarkModelObserver& observer : observers_)
382 observer.OnWillChangeBookmarkNode(this, node);
[email protected]472f95e2013-06-10 16:49:18383
[email protected]e5486602010-02-09 21:27:55384 {
[email protected]20305ec2011-01-21 04:55:52385 base::AutoLock url_lock(url_lock_);
danduongf4fde322014-11-04 18:56:56386 RemoveNodeFromInternalMaps(mutable_node);
[email protected]5d4077542011-07-21 20:24:07387 mutable_node->set_url(url);
danduongf4fde322014-11-04 18:56:56388 AddNodeToInternalMaps(mutable_node);
[email protected]e5486602010-02-09 21:27:55389 }
390
391 if (store_.get())
392 store_->ScheduleSave();
393
tfarina2fa1d2fb2016-10-19 01:44:31394 for (BookmarkModelObserver& observer : observers_)
395 observer.BookmarkNodeChanged(this, node);
[email protected]e5486602010-02-09 21:27:55396}
397
[email protected]1858410f2012-10-26 05:06:45398void BookmarkModel::SetNodeMetaInfo(const BookmarkNode* node,
399 const std::string& key,
400 const std::string& value) {
[email protected]39e113452013-11-26 00:43:06401 std::string old_value;
402 if (node->GetMetaInfo(key, &old_value) && old_value == value)
403 return;
404
tfarina2fa1d2fb2016-10-19 01:44:31405 for (BookmarkModelObserver& observer : observers_)
406 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40407
[email protected]1858410f2012-10-26 05:06:45408 if (AsMutable(node)->SetMetaInfo(key, value) && store_.get())
409 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40410
tfarina2fa1d2fb2016-10-19 01:44:31411 for (BookmarkModelObserver& observer : observers_)
412 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45413}
414
[email protected]e38a87d2013-12-05 01:35:18415void BookmarkModel::SetNodeMetaInfoMap(
416 const BookmarkNode* node,
417 const BookmarkNode::MetaInfoMap& meta_info_map) {
418 const BookmarkNode::MetaInfoMap* old_meta_info_map = node->GetMetaInfoMap();
419 if ((!old_meta_info_map && meta_info_map.empty()) ||
420 (old_meta_info_map && meta_info_map == *old_meta_info_map))
421 return;
422
tfarina2fa1d2fb2016-10-19 01:44:31423 for (BookmarkModelObserver& observer : observers_)
424 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]e38a87d2013-12-05 01:35:18425
426 AsMutable(node)->SetMetaInfoMap(meta_info_map);
427 if (store_.get())
428 store_->ScheduleSave();
429
tfarina2fa1d2fb2016-10-19 01:44:31430 for (BookmarkModelObserver& observer : observers_)
431 observer.BookmarkMetaInfoChanged(this, node);
[email protected]e38a87d2013-12-05 01:35:18432}
433
[email protected]1858410f2012-10-26 05:06:45434void BookmarkModel::DeleteNodeMetaInfo(const BookmarkNode* node,
435 const std::string& key) {
[email protected]39e113452013-11-26 00:43:06436 const BookmarkNode::MetaInfoMap* meta_info_map = node->GetMetaInfoMap();
437 if (!meta_info_map || meta_info_map->find(key) == meta_info_map->end())
438 return;
439
tfarina2fa1d2fb2016-10-19 01:44:31440 for (BookmarkModelObserver& observer : observers_)
441 observer.OnWillChangeBookmarkMetaInfo(this, node);
[email protected]cd869ede2013-10-17 12:29:40442
[email protected]1858410f2012-10-26 05:06:45443 if (AsMutable(node)->DeleteMetaInfo(key) && store_.get())
444 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40445
tfarina2fa1d2fb2016-10-19 01:44:31446 for (BookmarkModelObserver& observer : observers_)
447 observer.BookmarkMetaInfoChanged(this, node);
[email protected]1858410f2012-10-26 05:06:45448}
449
rfevangd75d32212014-12-06 01:27:22450void BookmarkModel::AddNonClonedKey(const std::string& key) {
451 non_cloned_keys_.insert(key);
452}
453
[email protected]39e113452013-11-26 00:43:06454void BookmarkModel::SetNodeSyncTransactionVersion(
455 const BookmarkNode* node,
avibc5337b2015-12-25 23:16:33456 int64_t sync_transaction_version) {
[email protected]043a76d2014-06-05 16:36:24457 DCHECK(client_->CanSyncNode(node));
458
[email protected]39e113452013-11-26 00:43:06459 if (sync_transaction_version == node->sync_transaction_version())
460 return;
461
462 AsMutable(node)->set_sync_transaction_version(sync_transaction_version);
463 if (store_.get())
464 store_->ScheduleSave();
465}
466
pkotwiczca240dd2015-07-09 16:15:32467void BookmarkModel::OnFaviconsChanged(const std::set<GURL>& page_urls,
468 const GURL& icon_url) {
469 std::set<const BookmarkNode*> to_update;
470 for (const GURL& page_url : page_urls) {
[email protected]6a848b52014-04-26 22:06:54471 std::vector<const BookmarkNode*> nodes;
pkotwiczca240dd2015-07-09 16:15:32472 GetNodesByURL(page_url, &nodes);
473 to_update.insert(nodes.begin(), nodes.end());
474 }
475
476 if (!icon_url.is_empty()) {
477 // Log Histogram to determine how often |icon_url| is non empty in
478 // practice.
479 // TODO(pkotwicz): Do something more efficient if |icon_url| is non-empty
480 // many times a day for each user.
481 UMA_HISTOGRAM_BOOLEAN("Bookmarks.OnFaviconsChangedIconURL", true);
482
483 base::AutoLock url_lock(url_lock_);
484 for (const BookmarkNode* node : nodes_ordered_by_url_set_) {
ssid144fb7b82017-06-01 02:32:26485 if (node->icon_url() && icon_url == *node->icon_url())
pkotwiczca240dd2015-07-09 16:15:32486 to_update.insert(node);
[email protected]6a848b52014-04-26 22:06:54487 }
488 }
pkotwiczca240dd2015-07-09 16:15:32489
490 for (const BookmarkNode* node : to_update) {
491 // Rerequest the favicon.
492 BookmarkNode* mutable_node = AsMutable(node);
493 mutable_node->InvalidateFavicon();
494 CancelPendingFaviconLoadRequests(mutable_node);
tfarina2fa1d2fb2016-10-19 01:44:31495 for (BookmarkModelObserver& observer : observers_)
496 observer.BookmarkNodeFaviconChanged(this, node);
pkotwiczca240dd2015-07-09 16:15:32497 }
[email protected]6a848b52014-04-26 22:06:54498}
499
tfarina5ebd5362015-05-12 21:50:10500void BookmarkModel::SetDateAdded(const BookmarkNode* node, Time date_added) {
501 DCHECK(node && !is_permanent_node(node));
[email protected]b61445c2012-10-27 00:11:42502
503 if (node->date_added() == date_added)
504 return;
505
[email protected]b61445c2012-10-27 00:11:42506 AsMutable(node)->set_date_added(date_added);
507
508 // Syncing might result in dates newer than the folder's last modified date.
509 if (date_added > node->parent()->date_folder_modified()) {
510 // Will trigger store_->ScheduleSave().
511 SetDateFolderModified(node->parent(), date_added);
512 } else if (store_.get()) {
513 store_->ScheduleSave();
514 }
515}
516
[email protected]848cd05e2008-09-19 18:33:48517void BookmarkModel::GetNodesByURL(const GURL& url,
[email protected]b3c33d462009-06-26 22:29:20518 std::vector<const BookmarkNode*>* nodes) {
[email protected]20305ec2011-01-21 04:55:52519 base::AutoLock url_lock(url_lock_);
[email protected]ea2e5aa52009-05-20 18:01:28520 BookmarkNode tmp_node(url);
initial.commit09911bf2008-07-26 23:55:29521 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node);
[email protected]5d4077542011-07-21 20:24:07522 while (i != nodes_ordered_by_url_set_.end() && (*i)->url() == url) {
[email protected]848cd05e2008-09-19 18:33:48523 nodes->push_back(*i);
524 ++i;
525 }
526}
527
[email protected]23e39692014-06-06 21:10:13528const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL(
[email protected]b3c33d462009-06-26 22:29:20529 const GURL& url) {
530 std::vector<const BookmarkNode*> nodes;
[email protected]848cd05e2008-09-19 18:33:48531 GetNodesByURL(url, &nodes);
tfarinaa0ec34e2015-01-12 18:46:48532 std::sort(nodes.begin(), nodes.end(), &MoreRecentlyAdded);
[email protected]23e39692014-06-06 21:10:13533
534 // Look for the first node that the user can edit.
535 for (size_t i = 0; i < nodes.size(); ++i) {
536 if (client_->CanBeEditedByUser(nodes[i]))
537 return nodes[i];
538 }
539
Ivan Kotenkov75b1c3a2017-10-24 14:47:24540 return nullptr;
initial.commit09911bf2008-07-26 23:55:29541}
542
[email protected]cf8e8172011-07-23 00:46:24543bool BookmarkModel::HasBookmarks() {
544 base::AutoLock url_lock(url_lock_);
545 return !nodes_ordered_by_url_set_.empty();
546}
547
Marti Wongc67da222017-09-01 02:30:01548bool BookmarkModel::HasNoUserCreatedBookmarksOrFolders() {
549 return bookmark_bar_node_->empty() && other_node_->empty() &&
550 mobile_node_->empty();
551}
552
[email protected]cf8e8172011-07-23 00:46:24553bool BookmarkModel::IsBookmarked(const GURL& url) {
554 base::AutoLock url_lock(url_lock_);
555 return IsBookmarkedNoLock(url);
556}
557
[email protected]0f7bee52012-08-06 20:04:17558void BookmarkModel::GetBookmarks(
[email protected]cef7931c2014-06-06 09:56:09559 std::vector<BookmarkModel::URLAndTitle>* bookmarks) {
[email protected]20305ec2011-01-21 04:55:52560 base::AutoLock url_lock(url_lock_);
Ivan Kotenkov75b1c3a2017-10-24 14:47:24561 const GURL* last_url = nullptr;
[email protected]90ef13132008-08-27 03:27:46562 for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin();
563 i != nodes_ordered_by_url_set_.end(); ++i) {
[email protected]5d4077542011-07-21 20:24:07564 const GURL* url = &((*i)->url());
[email protected]848cd05e2008-09-19 18:33:48565 // Only add unique URLs.
[email protected]0f7bee52012-08-06 20:04:17566 if (!last_url || *url != *last_url) {
[email protected]cef7931c2014-06-06 09:56:09567 BookmarkModel::URLAndTitle bookmark;
[email protected]0f7bee52012-08-06 20:04:17568 bookmark.url = *url;
569 bookmark.title = (*i)->GetTitle();
570 bookmarks->push_back(bookmark);
571 }
[email protected]848cd05e2008-09-19 18:33:48572 last_url = url;
[email protected]90ef13132008-08-27 03:27:46573 }
574}
575
[email protected]cf8e8172011-07-23 00:46:24576void BookmarkModel::BlockTillLoaded() {
577 loaded_signal_.Wait();
[email protected]848cd05e2008-09-19 18:33:48578}
579
[email protected]39703292011-03-18 17:03:40580const BookmarkNode* BookmarkModel::AddFolder(const BookmarkNode* parent,
581 int index,
[email protected]96920152013-12-04 21:00:16582 const base::string16& title) {
Ivan Kotenkov75b1c3a2017-10-24 14:47:24583 return AddFolderWithMetaInfo(parent, index, title, nullptr);
[email protected]eb59ad12014-04-24 00:05:08584}
585const BookmarkNode* BookmarkModel::AddFolderWithMetaInfo(
586 const BookmarkNode* parent,
587 int index,
588 const base::string16& title,
589 const BookmarkNode::MetaInfoMap* meta_info) {
[email protected]6b4d64c2011-07-29 21:33:24590 if (!loaded_ || is_root_node(parent) || !IsValidIndex(parent, index, true)) {
initial.commit09911bf2008-07-26 23:55:29591 // Can't add to the root.
592 NOTREACHED();
Ivan Kotenkov75b1c3a2017-10-24 14:47:24593 return nullptr;
initial.commit09911bf2008-07-26 23:55:29594 }
595
avicee78e4e2016-09-30 17:08:14596 std::unique_ptr<BookmarkNode> new_node =
597 base::MakeUnique<BookmarkNode>(generate_next_node_id(), GURL());
[email protected]edb63cc2011-03-11 02:00:41598 new_node->set_date_folder_modified(Time::Now());
[email protected]aee236542011-12-01 04:34:03599 // Folders shouldn't have line breaks in their titles.
[email protected]0491ff72011-12-30 00:45:59600 new_node->SetTitle(title);
[email protected]037db002009-10-19 20:06:08601 new_node->set_type(BookmarkNode::FOLDER);
[email protected]eb59ad12014-04-24 00:05:08602 if (meta_info)
603 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29604
avicee78e4e2016-09-30 17:08:14605 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29606}
607
[email protected]e64e9012010-01-11 23:10:55608const BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent,
609 int index,
[email protected]96920152013-12-04 21:00:16610 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55611 const GURL& url) {
Ivan Kotenkov75b1c3a2017-10-24 14:47:24612 return AddURLWithCreationTimeAndMetaInfo(parent, index, title, url,
613 Time::Now(), nullptr);
initial.commit09911bf2008-07-26 23:55:29614}
615
[email protected]eb59ad12014-04-24 00:05:08616const BookmarkNode* BookmarkModel::AddURLWithCreationTimeAndMetaInfo(
[email protected]e64e9012010-01-11 23:10:55617 const BookmarkNode* parent,
618 int index,
[email protected]96920152013-12-04 21:00:16619 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55620 const GURL& url,
[email protected]eb59ad12014-04-24 00:05:08621 const Time& creation_time,
622 const BookmarkNode::MetaInfoMap* meta_info) {
[email protected]6b4d64c2011-07-29 21:33:24623 if (!loaded_ || !url.is_valid() || is_root_node(parent) ||
[email protected]f25387b2008-08-21 15:20:33624 !IsValidIndex(parent, index, true)) {
initial.commit09911bf2008-07-26 23:55:29625 NOTREACHED();
Ivan Kotenkov75b1c3a2017-10-24 14:47:24626 return nullptr;
initial.commit09911bf2008-07-26 23:55:29627 }
initial.commit09911bf2008-07-26 23:55:29628
[email protected]b61445c2012-10-27 00:11:42629 // Syncing may result in dates newer than the last modified date.
[email protected]8ad613b2012-10-12 21:28:45630 if (creation_time > parent->date_folder_modified())
631 SetDateFolderModified(parent, creation_time);
initial.commit09911bf2008-07-26 23:55:29632
avicee78e4e2016-09-30 17:08:14633 std::unique_ptr<BookmarkNode> new_node =
634 base::MakeUnique<BookmarkNode>(generate_next_node_id(), url);
[email protected]0491ff72011-12-30 00:45:59635 new_node->SetTitle(title);
[email protected]b3c33d462009-06-26 22:29:20636 new_node->set_date_added(creation_time);
[email protected]037db002009-10-19 20:06:08637 new_node->set_type(BookmarkNode::URL);
[email protected]eb59ad12014-04-24 00:05:08638 if (meta_info)
639 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29640
avicee78e4e2016-09-30 17:08:14641 return AddNode(AsMutable(parent), index, std::move(new_node));
initial.commit09911bf2008-07-26 23:55:29642}
643
[email protected]b3c33d462009-06-26 22:29:20644void BookmarkModel::SortChildren(const BookmarkNode* parent) {
[email protected]23e39692014-06-06 21:10:13645 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24646
[email protected]6b4d64c2011-07-29 21:33:24647 if (!parent || !parent->is_folder() || is_root_node(parent) ||
[email protected]9c1a75a2011-03-10 02:38:12648 parent->child_count() <= 1) {
[email protected]e2f86d92009-02-25 00:22:01649 return;
650 }
651
tfarina2fa1d2fb2016-10-19 01:44:31652 for (BookmarkModelObserver& observer : observers_)
653 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18654
[email protected]ef762642009-03-05 16:30:25655 UErrorCode error = U_ZERO_ERROR;
dchengacd3f522016-04-21 22:30:41656 std::unique_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
[email protected]ef762642009-03-05 16:30:25657 if (U_FAILURE(error))
Ivan Kotenkov75b1c3a2017-10-24 14:47:24658 collator.reset(nullptr);
[email protected]b3c33d462009-06-26 22:29:20659 BookmarkNode* mutable_parent = AsMutable(parent);
660 std::sort(mutable_parent->children().begin(),
661 mutable_parent->children().end(),
[email protected]ef762642009-03-05 16:30:25662 SortComparator(collator.get()));
[email protected]e2f86d92009-02-25 00:22:01663
[email protected]997a0362009-03-12 03:10:51664 if (store_.get())
665 store_->ScheduleSave();
666
tfarina2fa1d2fb2016-10-19 01:44:31667 for (BookmarkModelObserver& observer : observers_)
668 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]e2f86d92009-02-25 00:22:01669}
670
[email protected]472f95e2013-06-10 16:49:18671void BookmarkModel::ReorderChildren(
672 const BookmarkNode* parent,
[email protected]257d5082013-08-06 07:46:43673 const std::vector<const BookmarkNode*>& ordered_nodes) {
[email protected]23e39692014-06-06 21:10:13674 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24675
[email protected]472f95e2013-06-10 16:49:18676 // Ensure that all children in |parent| are in |ordered_nodes|.
677 DCHECK_EQ(static_cast<size_t>(parent->child_count()), ordered_nodes.size());
avicee78e4e2016-09-30 17:08:14678 for (const BookmarkNode* node : ordered_nodes)
679 DCHECK_EQ(parent, node->parent());
[email protected]472f95e2013-06-10 16:49:18680
tfarina2fa1d2fb2016-10-19 01:44:31681 for (BookmarkModelObserver& observer : observers_)
682 observer.OnWillReorderBookmarkNode(this, parent);
[email protected]472f95e2013-06-10 16:49:18683
avicee78e4e2016-09-30 17:08:14684 if (ordered_nodes.size() > 1) {
685 std::map<const BookmarkNode*, int> order;
686 for (size_t i = 0; i < ordered_nodes.size(); ++i)
687 order[ordered_nodes[i]] = i;
[email protected]472f95e2013-06-10 16:49:18688
avicee78e4e2016-09-30 17:08:14689 std::vector<std::unique_ptr<BookmarkNode>> new_children(
690 ordered_nodes.size());
691 BookmarkNode* mutable_parent = AsMutable(parent);
692 for (auto& child : mutable_parent->children()) {
693 size_t new_location = order[child.get()];
694 new_children[new_location] = std::move(child);
695 }
696 mutable_parent->children().swap(new_children);
697
698 if (store_.get())
699 store_->ScheduleSave();
700 }
[email protected]472f95e2013-06-10 16:49:18701
tfarina2fa1d2fb2016-10-19 01:44:31702 for (BookmarkModelObserver& observer : observers_)
703 observer.BookmarkNodeChildrenReordered(this, parent);
[email protected]472f95e2013-06-10 16:49:18704}
705
[email protected]c6a7a3d2011-03-12 01:04:30706void BookmarkModel::SetDateFolderModified(const BookmarkNode* parent,
707 const Time time) {
[email protected]eea8fd5532009-12-16 00:08:10708 DCHECK(parent);
[email protected]edb63cc2011-03-11 02:00:41709 AsMutable(parent)->set_date_folder_modified(time);
[email protected]eea8fd5532009-12-16 00:08:10710
711 if (store_.get())
712 store_->ScheduleSave();
713}
714
[email protected]c6a7a3d2011-03-12 01:04:30715void BookmarkModel::ResetDateFolderModified(const BookmarkNode* node) {
716 SetDateFolderModified(node, Time());
initial.commit09911bf2008-07-26 23:55:29717}
718
kkimlabsf1a7a3732014-11-04 10:30:46719void BookmarkModel::GetBookmarksMatching(const base::string16& text,
720 size_t max_count,
mattreynolds25e9a312016-12-14 21:52:13721 std::vector<TitledUrlMatch>* matches) {
kkimlabsf1a7a3732014-11-04 10:30:46722 GetBookmarksMatching(text, max_count,
723 query_parser::MatchingAlgorithm::DEFAULT, matches);
724}
725
[email protected]b3a84892014-04-23 04:28:07726void BookmarkModel::GetBookmarksMatching(
[email protected]96920152013-12-04 21:00:16727 const base::string16& text,
[email protected]e64e9012010-01-11 23:10:55728 size_t max_count,
kkimlabsf1a7a3732014-11-04 10:30:46729 query_parser::MatchingAlgorithm matching_algorithm,
mattreynolds25e9a312016-12-14 21:52:13730 std::vector<TitledUrlMatch>* matches) {
[email protected]01eec882009-05-22 18:13:28731 if (!loaded_)
732 return;
733
mattreynolds55324d62016-12-09 23:07:29734 index_->GetResultsMatching(text, max_count, matching_algorithm, matches);
[email protected]85d911c2009-05-19 03:59:42735}
736
[email protected]9876bb1c2008-12-16 20:42:25737void BookmarkModel::ClearStore() {
[email protected]265e88e2014-07-07 20:45:19738 store_.reset();
[email protected]9876bb1c2008-12-16 20:42:25739}
740
[email protected]bc770a032011-12-12 17:35:30741void BookmarkModel::SetPermanentNodeVisible(BookmarkNode::Type type,
742 bool value) {
[email protected]043a76d2014-06-05 16:36:24743 BookmarkPermanentNode* node = AsMutable(PermanentNode(type));
744 node->set_visible(value || client_->IsPermanentNodeVisible(node));
[email protected]996dbe82014-05-12 12:32:18745}
746
747const BookmarkPermanentNode* BookmarkModel::PermanentNode(
748 BookmarkNode::Type type) {
[email protected]1da5f712011-12-06 05:52:26749 DCHECK(loaded_);
[email protected]bc770a032011-12-12 17:35:30750 switch (type) {
751 case BookmarkNode::BOOKMARK_BAR:
[email protected]996dbe82014-05-12 12:32:18752 return bookmark_bar_node_;
[email protected]bc770a032011-12-12 17:35:30753 case BookmarkNode::OTHER_NODE:
[email protected]996dbe82014-05-12 12:32:18754 return other_node_;
[email protected]bc770a032011-12-12 17:35:30755 case BookmarkNode::MOBILE:
[email protected]996dbe82014-05-12 12:32:18756 return mobile_node_;
[email protected]bc770a032011-12-12 17:35:30757 default:
758 NOTREACHED();
Ivan Kotenkov75b1c3a2017-10-24 14:47:24759 return nullptr;
[email protected]bc770a032011-12-12 17:35:30760 }
[email protected]1da5f712011-12-06 05:52:26761}
762
avicee78e4e2016-09-30 17:08:14763void BookmarkModel::RestoreRemovedNode(const BookmarkNode* parent,
764 int index,
765 std::unique_ptr<BookmarkNode> node) {
766 BookmarkNode* node_ptr = node.get();
767 AddNode(AsMutable(parent), index, std::move(node));
jianli14436d52015-10-09 22:47:35768
769 // We might be restoring a folder node that have already contained a set of
770 // child nodes. We need to notify all of them.
avicee78e4e2016-09-30 17:08:14771 NotifyNodeAddedForAllDescendents(node_ptr);
jianli14436d52015-10-09 22:47:35772}
773
774void BookmarkModel::NotifyNodeAddedForAllDescendents(const BookmarkNode* node) {
775 for (int i = 0; i < node->child_count(); ++i) {
tfarina2fa1d2fb2016-10-19 01:44:31776 for (BookmarkModelObserver& observer : observers_)
777 observer.BookmarkNodeAdded(this, node, i);
jianli14436d52015-10-09 22:47:35778 NotifyNodeAddedForAllDescendents(node->GetChild(i));
779 }
780}
781
[email protected]dddc1b42008-10-09 20:56:59782bool BookmarkModel::IsBookmarkedNoLock(const GURL& url) {
[email protected]ea2e5aa52009-05-20 18:01:28783 BookmarkNode tmp_node(url);
[email protected]dddc1b42008-10-09 20:56:59784 return (nodes_ordered_by_url_set_.find(&tmp_node) !=
785 nodes_ordered_by_url_set_.end());
786}
787
[email protected]d8e41ed2008-09-11 15:22:32788void BookmarkModel::RemoveNode(BookmarkNode* node,
789 std::set<GURL>* removed_urls) {
[email protected]b3c33d462009-06-26 22:29:20790 if (!loaded_ || !node || is_permanent_node(node)) {
[email protected]f25387b2008-08-21 15:20:33791 NOTREACHED();
792 return;
793 }
794
[email protected]323dbf72013-03-30 17:08:33795 url_lock_.AssertAcquired();
[email protected]0890e60e2011-06-27 14:55:21796 if (node->is_url()) {
danduongf4fde322014-11-04 18:56:56797 RemoveNodeFromInternalMaps(node);
[email protected]5d4077542011-07-21 20:24:07798 removed_urls->insert(node->url());
initial.commit09911bf2008-07-26 23:55:29799 }
800
[email protected]abc2f262011-03-15 21:15:44801 CancelPendingFaviconLoadRequests(node);
initial.commit09911bf2008-07-26 23:55:29802
803 // Recurse through children.
[email protected]9c1a75a2011-03-10 02:38:12804 for (int i = node->child_count() - 1; i >= 0; --i)
[email protected]f25387b2008-08-21 15:20:33805 RemoveNode(node->GetChild(i), removed_urls);
initial.commit09911bf2008-07-26 23:55:29806}
807
dchengacd3f522016-04-21 22:30:41808void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
[email protected]6a848b52014-04-26 22:06:54809 DCHECK(details);
[email protected]01eec882009-05-22 18:13:28810 if (loaded_) {
811 // We should only ever be loaded once.
812 NOTREACHED();
813 return;
814 }
815
[email protected]01eec882009-05-22 18:13:28816 next_node_id_ = details->max_id();
[email protected]367d7072009-07-13 23:27:13817 if (details->computed_checksum() != details->stored_checksum() ||
818 details->ids_reassigned()) {
[email protected]367d7072009-07-13 23:27:13819 // If bookmarks file changed externally, the IDs may have changed
820 // externally. In that case, the decoder may have reassigned IDs to make
821 // them unique. So when the file has changed externally, we should save the
822 // bookmarks file to persist new IDs.
823 if (store_.get())
824 store_->ScheduleSave();
825 }
avicee78e4e2016-09-30 17:08:14826 std::unique_ptr<BookmarkPermanentNode> owned_bb_node =
827 details->owned_bb_node();
828 std::unique_ptr<BookmarkPermanentNode> owned_other_folder_node =
829 details->owned_other_folder_node();
830 std::unique_ptr<BookmarkPermanentNode> owned_mobile_folder_node =
831 details->owned_mobile_folder_node();
832 index_ = details->owned_index();
833
834 bookmark_bar_node_ = owned_bb_node.get();
835 other_node_ = owned_other_folder_node.get();
836 mobile_node_ = owned_mobile_folder_node.get();
[email protected]01eec882009-05-22 18:13:28837
[email protected]043a76d2014-06-05 16:36:24838 // Get any extra nodes and take ownership of them at the |root_|.
avicee78e4e2016-09-30 17:08:14839 std::vector<std::unique_ptr<BookmarkPermanentNode>> extra_nodes =
840 details->owned_extra_nodes();
[email protected]043a76d2014-06-05 16:36:24841
[email protected]82f4655a2011-10-18 13:05:43842 // WARNING: order is important here, various places assume the order is
[email protected]996dbe82014-05-12 12:32:18843 // constant (but can vary between embedders with the initial visibility
844 // of permanent nodes).
avicee78e4e2016-09-30 17:08:14845 std::vector<std::unique_ptr<BookmarkPermanentNode>> root_children;
846 root_children.push_back(std::move(owned_bb_node));
847 root_children.push_back(std::move(owned_other_folder_node));
848 root_children.push_back(std::move(owned_mobile_folder_node));
849 std::move(extra_nodes.begin(), extra_nodes.end(),
850 std::back_inserter(root_children));
robliaoad0efe962015-03-14 00:13:02851
[email protected]043a76d2014-06-05 16:36:24852 std::stable_sort(root_children.begin(),
853 root_children.end(),
sdefresne070a5102016-02-01 13:42:14854 VisibilityComparator(client_.get()));
[email protected]043a76d2014-06-05 16:36:24855 for (size_t i = 0; i < root_children.size(); ++i)
avicee78e4e2016-09-30 17:08:14856 root_.Add(std::move(root_children[i]), static_cast<int>(i));
[email protected]6c1164042009-05-08 14:41:08857
[email protected]39e113452013-11-26 00:43:06858 root_.SetMetaInfoMap(details->model_meta_info_map());
859 root_.set_sync_transaction_version(details->model_sync_transaction_version());
[email protected]1858410f2012-10-26 05:06:45860
[email protected]90ef13132008-08-27 03:27:46861 {
[email protected]20305ec2011-01-21 04:55:52862 base::AutoLock url_lock(url_lock_);
[email protected]90ef13132008-08-27 03:27:46863 // Update nodes_ordered_by_url_set_ from the nodes.
864 PopulateNodesByURL(&root_);
865 }
[email protected]f25387b2008-08-21 15:20:33866
initial.commit09911bf2008-07-26 23:55:29867 loaded_ = true;
868
[email protected]cbcd6412009-03-09 22:31:39869 loaded_signal_.Signal();
[email protected]90ef13132008-08-27 03:27:46870
[email protected]f25387b2008-08-21 15:20:33871 // Notify our direct observers.
tfarina2fa1d2fb2016-10-19 01:44:31872 for (BookmarkModelObserver& observer : observers_)
873 observer.BookmarkModelLoaded(this, details->ids_reassigned());
initial.commit09911bf2008-07-26 23:55:29874}
875
avicee78e4e2016-09-30 17:08:14876void BookmarkModel::RemoveAndDeleteNode(BookmarkNode* node_ptr) {
877 std::unique_ptr<BookmarkNode> node;
initial.commit09911bf2008-07-26 23:55:29878
avicee78e4e2016-09-30 17:08:14879 const BookmarkNode* parent = node_ptr->parent();
initial.commit09911bf2008-07-26 23:55:29880 DCHECK(parent);
avicee78e4e2016-09-30 17:08:14881 int index = parent->GetIndexOf(node_ptr);
deepak.m139312672015-05-04 16:29:43882 DCHECK_NE(-1, index);
[email protected]323dbf72013-03-30 17:08:33883
tfarina2fa1d2fb2016-10-19 01:44:31884 for (BookmarkModelObserver& observer : observers_)
885 observer.OnWillRemoveBookmarks(this, parent, index, node_ptr);
[email protected]472f95e2013-06-10 16:49:18886
[email protected]9109f8a12013-06-12 18:07:48887 std::set<GURL> removed_urls;
[email protected]90ef13132008-08-27 03:27:46888 {
[email protected]20305ec2011-01-21 04:55:52889 base::AutoLock url_lock(url_lock_);
avicee78e4e2016-09-30 17:08:14890 node = RemoveNodeAndGetRemovedUrls(node_ptr, &removed_urls);
[email protected]90ef13132008-08-27 03:27:46891 }
initial.commit09911bf2008-07-26 23:55:29892
[email protected]f25387b2008-08-21 15:20:33893 if (store_.get())
894 store_->ScheduleSave();
895
tfarina2fa1d2fb2016-10-19 01:44:31896 for (BookmarkModelObserver& observer : observers_)
897 observer.BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls);
jianli14436d52015-10-09 22:47:35898
dcheng51606352015-12-26 21:16:23899 undo_delegate()->OnBookmarkNodeRemoved(this, parent, index, std::move(node));
[email protected]323dbf72013-03-30 17:08:33900}
[email protected]f25387b2008-08-21 15:20:33901
danduongf4fde322014-11-04 18:56:56902void BookmarkModel::RemoveNodeFromInternalMaps(BookmarkNode* node) {
903 index_->Remove(node);
[email protected]5db00bca2013-12-23 00:43:09904 // NOTE: this is called in such a way that url_lock_ is already held. As
905 // such, this doesn't explicitly grab the lock.
danduongf4fde322014-11-04 18:56:56906 url_lock_.AssertAcquired();
[email protected]5db00bca2013-12-23 00:43:09907 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node);
908 DCHECK(i != nodes_ordered_by_url_set_.end());
909 // i points to the first node with the URL, advance until we find the
910 // node we're removing.
911 while (*i != node)
912 ++i;
913 nodes_ordered_by_url_set_.erase(i);
914}
915
avicee78e4e2016-09-30 17:08:14916std::unique_ptr<BookmarkNode> BookmarkModel::RemoveNodeAndGetRemovedUrls(
917 BookmarkNode* node_ptr,
918 std::set<GURL>* removed_urls) {
[email protected]323dbf72013-03-30 17:08:33919 // NOTE: this method should be always called with |url_lock_| held.
920 // This method does not explicitly acquires a lock.
921 url_lock_.AssertAcquired();
922 DCHECK(removed_urls);
avicee78e4e2016-09-30 17:08:14923 BookmarkNode* parent = node_ptr->parent();
[email protected]323dbf72013-03-30 17:08:33924 DCHECK(parent);
avicee78e4e2016-09-30 17:08:14925 std::unique_ptr<BookmarkNode> node = parent->Remove(node_ptr);
926 RemoveNode(node_ptr, removed_urls);
[email protected]323dbf72013-03-30 17:08:33927 // RemoveNode adds an entry to removed_urls for each node of type URL. As we
928 // allow duplicates we need to remove any entries that are still bookmarked.
929 for (std::set<GURL>::iterator i = removed_urls->begin();
930 i != removed_urls->end();) {
931 if (IsBookmarkedNoLock(*i)) {
932 // When we erase the iterator pointing at the erasee is
933 // invalidated, so using i++ here within the "erase" call is
934 // important as it advances the iterator before passing the
935 // old value through to erase.
936 removed_urls->erase(i++);
937 } else {
938 ++i;
939 }
940 }
avicee78e4e2016-09-30 17:08:14941
942 return node;
[email protected]323dbf72013-03-30 17:08:33943}
944
[email protected]d8e41ed2008-09-11 15:22:32945BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
946 int index,
avicee78e4e2016-09-30 17:08:14947 std::unique_ptr<BookmarkNode> node) {
948 BookmarkNode* node_ptr = node.get();
949 parent->Add(std::move(node), index);
initial.commit09911bf2008-07-26 23:55:29950
[email protected]f25387b2008-08-21 15:20:33951 if (store_.get())
952 store_->ScheduleSave();
953
jianli14436d52015-10-09 22:47:35954 {
danduongf4fde322014-11-04 18:56:56955 base::AutoLock url_lock(url_lock_);
avicee78e4e2016-09-30 17:08:14956 AddNodeToInternalMaps(node_ptr);
danduongf4fde322014-11-04 18:56:56957 }
958
tfarina2fa1d2fb2016-10-19 01:44:31959 for (BookmarkModelObserver& observer : observers_)
960 observer.BookmarkNodeAdded(this, parent, index);
[email protected]f25387b2008-08-21 15:20:33961
avicee78e4e2016-09-30 17:08:14962 return node_ptr;
initial.commit09911bf2008-07-26 23:55:29963}
964
danduongf4fde322014-11-04 18:56:56965void BookmarkModel::AddNodeToInternalMaps(BookmarkNode* node) {
danduongf4fde322014-11-04 18:56:56966 url_lock_.AssertAcquired();
jianli14436d52015-10-09 22:47:35967 if (node->is_url()) {
968 index_->Add(node);
969 nodes_ordered_by_url_set_.insert(node);
970 }
971 for (int i = 0; i < node->child_count(); ++i)
972 AddNodeToInternalMaps(node->GetChild(i));
danduongf4fde322014-11-04 18:56:56973}
974
[email protected]b3c33d462009-06-26 22:29:20975bool BookmarkModel::IsValidIndex(const BookmarkNode* parent,
[email protected]d8e41ed2008-09-11 15:22:32976 int index,
977 bool allow_end) {
[email protected]776e7492008-10-23 16:47:41978 return (parent && parent->is_folder() &&
[email protected]9c1a75a2011-03-10 02:38:12979 (index >= 0 && (index < parent->child_count() ||
980 (allow_end && index == parent->child_count()))));
[email protected]bd1b96702009-07-08 21:54:14981}
[email protected]f25387b2008-08-21 15:20:33982
[email protected]bc770a032011-12-12 17:35:30983BookmarkPermanentNode* BookmarkModel::CreatePermanentNode(
984 BookmarkNode::Type type) {
[email protected]e1f76c62011-06-30 20:15:39985 DCHECK(type == BookmarkNode::BOOKMARK_BAR ||
986 type == BookmarkNode::OTHER_NODE ||
[email protected]37bc9132011-12-01 22:29:29987 type == BookmarkNode::MOBILE);
[email protected]bc770a032011-12-12 17:35:30988 BookmarkPermanentNode* node =
989 new BookmarkPermanentNode(generate_next_node_id());
[email protected]043a76d2014-06-05 16:36:24990 node->set_type(type);
991 node->set_visible(client_->IsPermanentNodeVisible(node));
[email protected]bc770a032011-12-12 17:35:30992
993 int title_id;
994 switch (type) {
995 case BookmarkNode::BOOKMARK_BAR:
996 title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
997 break;
998 case BookmarkNode::OTHER_NODE:
999 title_id = IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME;
1000 break;
1001 case BookmarkNode::MOBILE:
1002 title_id = IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME;
1003 break;
1004 default:
[email protected]97fdd162011-12-03 20:50:121005 NOTREACHED();
[email protected]bc770a032011-12-12 17:35:301006 title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
1007 break;
[email protected]7caca8a22010-08-21 18:25:311008 }
[email protected]0491ff72011-12-30 00:45:591009 node->SetTitle(l10n_util::GetStringUTF16(title_id));
initial.commit09911bf2008-07-26 23:55:291010 return node;
1011}
1012
[email protected]abc2f262011-03-15 21:15:441013void BookmarkModel::OnFaviconDataAvailable(
[email protected]0ea3db52012-12-07 01:32:011014 BookmarkNode* node,
[email protected]504fca82014-05-07 22:48:081015 favicon_base::IconType icon_type,
[email protected]7627e0b42014-04-17 17:20:531016 const favicon_base::FaviconImageResult& image_result) {
[email protected]4167c3a2008-08-21 18:12:201017 DCHECK(node);
[email protected]e95b717f2014-02-06 13:47:131018 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
[email protected]bcc38612012-10-23 01:10:271019 node->set_favicon_state(BookmarkNode::LOADED_FAVICON);
[email protected]65baa222012-08-30 15:43:511020 if (!image_result.image.IsEmpty()) {
[email protected]504fca82014-05-07 22:48:081021 node->set_favicon_type(icon_type);
[email protected]65baa222012-08-30 15:43:511022 node->set_favicon(image_result.image);
[email protected]2ad0e872012-11-30 01:24:461023 node->set_icon_url(image_result.icon_url);
[email protected]65baa222012-08-30 15:43:511024 FaviconLoaded(node);
Mikel Astiza5ea255f2017-11-06 22:50:151025 } else if (icon_type == favicon_base::IconType::kTouchIcon) {
[email protected]504fca82014-05-07 22:48:081026 // Couldn't load the touch icon, fallback to the regular favicon.
1027 DCHECK(client_->PreferTouchIcon());
Mikel Astiza5ea255f2017-11-06 22:50:151028 LoadFavicon(node, favicon_base::IconType::kFavicon);
Mikel Astiz55b3fe202017-11-08 20:54:501029 } else {
1030 // No favicon available, but we still notify observers.
1031 FaviconLoaded(node);
initial.commit09911bf2008-07-26 23:55:291032 }
1033}
1034
tfarinac0baf0b2014-12-08 18:01:211035void BookmarkModel::LoadFavicon(BookmarkNode* node,
1036 favicon_base::IconType icon_type) {
[email protected]0890e60e2011-06-27 14:55:211037 if (node->is_folder())
initial.commit09911bf2008-07-26 23:55:291038 return;
1039
[email protected]5d4077542011-07-21 20:24:071040 DCHECK(node->url().is_valid());
[email protected]504fca82014-05-07 22:48:081041 node->set_favicon_state(BookmarkNode::LOADING_FAVICON);
[email protected]25244a932014-07-12 23:00:241042 base::CancelableTaskTracker::TaskId taskId =
1043 client_->GetFaviconImageForPageURL(
1044 node->url(),
1045 icon_type,
1046 base::Bind(
1047 &BookmarkModel::OnFaviconDataAvailable,
1048 base::Unretained(this),
1049 node,
1050 icon_type),
1051 &cancelable_task_tracker_);
[email protected]6a848b52014-04-26 22:06:541052 if (taskId != base::CancelableTaskTracker::kBadTaskId)
1053 node->set_favicon_load_task_id(taskId);
initial.commit09911bf2008-07-26 23:55:291054}
1055
[email protected]5b5c9b7f32011-07-21 01:07:181056void BookmarkModel::FaviconLoaded(const BookmarkNode* node) {
tfarina2fa1d2fb2016-10-19 01:44:311057 for (BookmarkModelObserver& observer : observers_)
1058 observer.BookmarkNodeFaviconChanged(this, node);
[email protected]5b5c9b7f32011-07-21 01:07:181059}
1060
[email protected]abc2f262011-03-15 21:15:441061void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) {
[email protected]e95b717f2014-02-06 13:47:131062 if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) {
[email protected]0ea3db52012-12-07 01:32:011063 cancelable_task_tracker_.TryCancel(node->favicon_load_task_id());
[email protected]e95b717f2014-02-06 13:47:131064 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
initial.commit09911bf2008-07-26 23:55:291065 }
1066}
1067
[email protected]d8e41ed2008-09-11 15:22:321068void BookmarkModel::PopulateNodesByURL(BookmarkNode* node) {
[email protected]90ef13132008-08-27 03:27:461069 // NOTE: this is called with url_lock_ already held. As such, this doesn't
1070 // explicitly grab the lock.
[email protected]f25387b2008-08-21 15:20:331071 if (node->is_url())
1072 nodes_ordered_by_url_set_.insert(node);
[email protected]9c1a75a2011-03-10 02:38:121073 for (int i = 0; i < node->child_count(); ++i)
[email protected]f25387b2008-08-21 15:20:331074 PopulateNodesByURL(node->GetChild(i));
1075}
[email protected]4d89f382009-05-12 06:56:491076
avibc5337b2015-12-25 23:16:331077int64_t BookmarkModel::generate_next_node_id() {
[email protected]4d89f382009-05-12 06:56:491078 return next_node_id_++;
1079}
[email protected]01eec882009-05-22 18:13:281080
dchengacd3f522016-04-21 22:30:411081std::unique_ptr<BookmarkLoadDetails> BookmarkModel::CreateLoadDetails() {
[email protected]bc770a032011-12-12 17:35:301082 BookmarkPermanentNode* bb_node =
1083 CreatePermanentNode(BookmarkNode::BOOKMARK_BAR);
1084 BookmarkPermanentNode* other_node =
1085 CreatePermanentNode(BookmarkNode::OTHER_NODE);
1086 BookmarkPermanentNode* mobile_node =
1087 CreatePermanentNode(BookmarkNode::MOBILE);
mattreynolds191b88722016-12-13 19:25:321088 std::unique_ptr<TitledUrlNodeSorter> node_sorter =
1089 base::MakeUnique<TypedCountSorter>(client_.get());
dchengacd3f522016-04-21 22:30:411090 return std::unique_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails(
1091 bb_node, other_node, mobile_node, client_->GetLoadExtraNodesCallback(),
mattreynolds25e9a312016-12-14 21:52:131092 new TitledUrlIndex(std::move(node_sorter)), next_node_id_));
[email protected]01eec882009-05-22 18:13:281093}
tfarinaa0ec34e2015-01-12 18:46:481094
jianli14436d52015-10-09 22:47:351095void BookmarkModel::SetUndoDelegate(BookmarkUndoDelegate* undo_delegate) {
1096 undo_delegate_ = undo_delegate;
1097 if (undo_delegate_)
1098 undo_delegate_->SetUndoProvider(this);
1099}
1100
1101BookmarkUndoDelegate* BookmarkModel::undo_delegate() const {
1102 return undo_delegate_ ? undo_delegate_ : empty_undo_delegate_.get();
1103}
1104
tfarinaa0ec34e2015-01-12 18:46:481105} // namespace bookmarks