blob: 5f26f67ce2ead1706714e428714fe44701bb1c8b [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>
9
[email protected]bbdd2982011-10-08 18:14:2410#include "base/bind.h"
11#include "base/bind_helpers.h"
[email protected]9a08fe82013-04-23 05:06:0512#include "base/i18n/string_compare.h"
[email protected]6a848b52014-04-26 22:06:5413#include "base/logging.h"
[email protected]996dbe82014-05-12 12:32:1814#include "base/macros.h"
[email protected]6a848b52014-04-26 22:06:5415#include "base/strings/string_util.h"
[email protected]a90c8ca2014-05-20 17:16:0416#include "components/bookmarks/browser/bookmark_expanded_state_tracker.h"
17#include "components/bookmarks/browser/bookmark_index.h"
18#include "components/bookmarks/browser/bookmark_match.h"
19#include "components/bookmarks/browser/bookmark_model_observer.h"
20#include "components/bookmarks/browser/bookmark_node_data.h"
21#include "components/bookmarks/browser/bookmark_storage.h"
22#include "components/bookmarks/browser/bookmark_utils.h"
[email protected]7627e0b42014-04-17 17:20:5323#include "components/favicon_base/favicon_types.h"
[email protected]426d676a2014-05-28 14:41:0324#include "grit/components_strings.h"
[email protected]c051a1b2011-01-21 23:30:1725#include "ui/base/l10n/l10n_util.h"
[email protected]65baa222012-08-30 15:43:5126#include "ui/gfx/favicon_size.h"
initial.commit09911bf2008-07-26 23:55:2927
[email protected]e1acf6f2008-10-27 20:43:3328using base::Time;
[email protected]5d4832f2014-06-27 01:26:1529using bookmarks::BookmarkClient;
[email protected]05c90652014-06-13 02:42:0030using bookmarks::BookmarkExpandedStateTracker;
[email protected]c45f5622014-06-01 21:35:4831using bookmarks::BookmarkIndex;
[email protected]9e422ecc2014-05-27 22:31:3132using bookmarks::BookmarkLoadDetails;
[email protected]19c602f12014-06-12 07:37:0533using bookmarks::BookmarkMatch;
[email protected]433e94e2014-07-30 03:51:3134using bookmarks::BookmarkNodeData;
[email protected]9e422ecc2014-05-27 22:31:3135using bookmarks::BookmarkStorage;
[email protected]e1acf6f2008-10-27 20:43:3336
[email protected]b3c33d462009-06-26 22:29:2037namespace {
38
39// Helper to get a mutable bookmark node.
[email protected]7b084b02011-07-08 16:06:4840BookmarkNode* AsMutable(const BookmarkNode* node) {
[email protected]b3c33d462009-06-26 22:29:2041 return const_cast<BookmarkNode*>(node);
42}
43
[email protected]996dbe82014-05-12 12:32:1844// Helper to get a mutable permanent bookmark node.
45BookmarkPermanentNode* AsMutable(const BookmarkPermanentNode* node) {
46 return const_cast<BookmarkPermanentNode*>(node);
47}
48
49// Comparator used when sorting permanent nodes. Nodes that are initially
50// visible are sorted before nodes that are initially hidden.
51class VisibilityComparator
52 : public std::binary_function<const BookmarkPermanentNode*,
53 const BookmarkPermanentNode*,
54 bool> {
55 public:
56 explicit VisibilityComparator(BookmarkClient* client) : client_(client) {}
57
58 // Returns true if |n1| preceeds |n2|.
59 bool operator()(const BookmarkPermanentNode* n1,
60 const BookmarkPermanentNode* n2) {
[email protected]043a76d2014-06-05 16:36:2461 bool n1_visible = client_->IsPermanentNodeVisible(n1);
62 bool n2_visible = client_->IsPermanentNodeVisible(n2);
[email protected]996dbe82014-05-12 12:32:1863 return n1_visible != n2_visible && n1_visible;
64 }
65
66 private:
67 BookmarkClient* client_;
68};
69
[email protected]ef762642009-03-05 16:30:2570// Comparator used when sorting bookmarks. Folders are sorted first, then
[email protected]2c685cc22009-08-28 00:17:4471// bookmarks.
[email protected]b3c33d462009-06-26 22:29:2072class SortComparator : public std::binary_function<const BookmarkNode*,
73 const BookmarkNode*,
[email protected]ef762642009-03-05 16:30:2574 bool> {
75 public:
[email protected]a48f87d2012-10-09 18:06:3376 explicit SortComparator(icu::Collator* collator) : collator_(collator) {}
[email protected]ef762642009-03-05 16:30:2577
[email protected]a48f87d2012-10-09 18:06:3378 // Returns true if |n1| preceeds |n2|.
79 bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) {
[email protected]037db002009-10-19 20:06:0880 if (n1->type() == n2->type()) {
[email protected]ef762642009-03-05 16:30:2581 // Types are the same, compare the names.
82 if (!collator_)
[email protected]440b37b22010-08-30 05:31:4083 return n1->GetTitle() < n2->GetTitle();
[email protected]9a08fe82013-04-23 05:06:0584 return base::i18n::CompareString16WithCollator(
[email protected]3abebda2011-01-07 20:17:1585 collator_, n1->GetTitle(), n2->GetTitle()) == UCOL_LESS;
[email protected]ef762642009-03-05 16:30:2586 }
87 // Types differ, sort such that folders come first.
88 return n1->is_folder();
89 }
90
91 private:
[email protected]b5b2385a2009-08-18 05:12:2992 icu::Collator* collator_;
[email protected]ef762642009-03-05 16:30:2593};
94
[email protected]bc770a032011-12-12 17:35:3095} // namespace
[email protected]97fdd162011-12-03 20:50:1296
[email protected]97fdd162011-12-03 20:50:1297// BookmarkModel --------------------------------------------------------------
98
[email protected]6a848b52014-04-26 22:06:5499BookmarkModel::BookmarkModel(BookmarkClient* client, bool index_urls)
100 : client_(client),
initial.commit09911bf2008-07-26 23:55:29101 loaded_(false),
[email protected]ea2e5aa52009-05-20 18:01:28102 root_(GURL()),
initial.commit09911bf2008-07-26 23:55:29103 bookmark_bar_node_(NULL),
[email protected]90ef13132008-08-27 03:27:46104 other_node_(NULL),
[email protected]37bc9132011-12-01 22:29:29105 mobile_node_(NULL),
[email protected]4d89f382009-05-12 06:56:49106 next_node_id_(1),
[email protected]b3e2fad02008-10-31 03:32:06107 observers_(ObserverList<BookmarkModelObserver>::NOTIFY_EXISTING_ONLY),
[email protected]b3a84892014-04-23 04:28:07108 index_urls_(index_urls),
[email protected]b68a8172012-02-17 00:25:18109 loaded_signal_(true, false),
110 extensive_changes_(0) {
[email protected]6a848b52014-04-26 22:06:54111 DCHECK(client_);
initial.commit09911bf2008-07-26 23:55:29112}
113
[email protected]d8e41ed2008-09-11 15:22:32114BookmarkModel::~BookmarkModel() {
[email protected]d8e41ed2008-09-11 15:22:32115 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
[email protected]3de6fd342008-09-05 02:44:51116 BookmarkModelBeingDeleted(this));
117
[email protected]dc24976f2013-06-02 21:15:09118 if (store_.get()) {
[email protected]f25387b2008-08-21 15:20:33119 // The store maintains a reference back to us. We need to tell it we're gone
120 // so that it doesn't try and invoke a method back on us again.
121 store_->BookmarkModelDeleted();
initial.commit09911bf2008-07-26 23:55:29122 }
123}
124
[email protected]f61f4782012-06-08 21:54:21125void BookmarkModel::Shutdown() {
[email protected]88e6a232011-09-14 14:53:20126 if (loaded_)
127 return;
128
[email protected]f61f4782012-06-08 21:54:21129 // See comment in HistoryService::ShutdownOnUIThread where this is invoked for
130 // details. It is also called when the BookmarkModel is deleted.
[email protected]88e6a232011-09-14 14:53:20131 loaded_signal_.Signal();
132}
133
[email protected]afecfb72013-04-18 17:17:33134void BookmarkModel::Load(
[email protected]6a848b52014-04-26 22:06:54135 PrefService* pref_service,
136 const std::string& accept_languages,
137 const base::FilePath& profile_path,
138 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
139 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) {
[email protected]90ef13132008-08-27 03:27:46140 if (store_.get()) {
141 // If the store is non-null, it means Load was already invoked. Load should
142 // only be invoked once.
143 NOTREACHED();
144 return;
145 }
146
[email protected]6df6ec022013-07-16 03:05:22147 expanded_state_tracker_.reset(
[email protected]6a848b52014-04-26 22:06:54148 new BookmarkExpandedStateTracker(this, pref_service));
[email protected]90ef13132008-08-27 03:27:46149
150 // Load the bookmarks. BookmarkStorage notifies us when done.
[email protected]265e88e2014-07-07 20:45:19151 store_ .reset(new BookmarkStorage(this, profile_path, io_task_runner.get()));
[email protected]6a848b52014-04-26 22:06:54152 store_->LoadBookmarks(CreateLoadDetails(accept_languages), ui_task_runner);
[email protected]90ef13132008-08-27 03:27:46153}
154
[email protected]b3c33d462009-06-26 22:29:20155const BookmarkNode* BookmarkModel::GetParentForNewNodes() {
156 std::vector<const BookmarkNode*> nodes =
[email protected]2cd924d2014-07-15 18:56:52157 bookmarks::GetMostRecentlyModifiedUserFolders(this, 1);
[email protected]82f4655a2011-10-18 13:05:43158 DCHECK(!nodes.empty()); // This list is always padded with default folders.
159 return nodes[0];
initial.commit09911bf2008-07-26 23:55:29160}
161
[email protected]125b234182011-07-08 19:54:41162void BookmarkModel::AddObserver(BookmarkModelObserver* observer) {
163 observers_.AddObserver(observer);
164}
165
166void BookmarkModel::RemoveObserver(BookmarkModelObserver* observer) {
167 observers_.RemoveObserver(observer);
168}
169
[email protected]b68a8172012-02-17 00:25:18170void BookmarkModel::BeginExtensiveChanges() {
171 if (++extensive_changes_ == 1) {
172 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
173 ExtensiveBookmarkChangesBeginning(this));
174 }
[email protected]125b234182011-07-08 19:54:41175}
176
[email protected]b68a8172012-02-17 00:25:18177void BookmarkModel::EndExtensiveChanges() {
178 --extensive_changes_;
179 DCHECK_GE(extensive_changes_, 0);
180 if (extensive_changes_ == 0) {
181 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
182 ExtensiveBookmarkChangesEnded(this));
183 }
[email protected]125b234182011-07-08 19:54:41184}
185
[email protected]346453a2014-03-12 10:14:37186void BookmarkModel::BeginGroupedChanges() {
187 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
188 GroupedBookmarkChangesBeginning(this));
189}
190
191void BookmarkModel::EndGroupedChanges() {
192 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
193 GroupedBookmarkChangesEnded(this));
194}
195
[email protected]b3c33d462009-06-26 22:29:20196void BookmarkModel::Remove(const BookmarkNode* parent, int index) {
[email protected]6b4d64c2011-07-29 21:33:24197 if (!loaded_ || !IsValidIndex(parent, index, false) || is_root_node(parent)) {
[email protected]f25387b2008-08-21 15:20:33198 NOTREACHED();
199 return;
200 }
[email protected]b3c33d462009-06-26 22:29:20201 RemoveAndDeleteNode(AsMutable(parent->GetChild(index)));
[email protected]f25387b2008-08-21 15:20:33202}
203
[email protected]5cd942208a2014-06-11 06:16:46204void BookmarkModel::RemoveAllUserBookmarks() {
[email protected]9109f8a12013-06-12 18:07:48205 std::set<GURL> removed_urls;
[email protected]323dbf72013-03-30 17:08:33206 ScopedVector<BookmarkNode> removed_nodes;
[email protected]472f95e2013-06-10 16:49:18207
208 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
[email protected]5cd942208a2014-06-11 06:16:46209 OnWillRemoveAllUserBookmarks(this));
[email protected]472f95e2013-06-10 16:49:18210
[email protected]323dbf72013-03-30 17:08:33211 BeginExtensiveChanges();
212 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and
213 // its immediate children. For removing all non permanent nodes just remove
214 // all children of non-root permanent nodes.
215 {
216 base::AutoLock url_lock(url_lock_);
217 for (int i = 0; i < root_.child_count(); ++i) {
[email protected]ed18102fa2013-12-26 04:02:00218 BookmarkNode* permanent_node = root_.GetChild(i);
[email protected]043a76d2014-06-05 16:36:24219
[email protected]23e39692014-06-06 21:10:13220 if (!client_->CanBeEditedByUser(permanent_node))
[email protected]043a76d2014-06-05 16:36:24221 continue;
222
[email protected]323dbf72013-03-30 17:08:33223 for (int j = permanent_node->child_count() - 1; j >= 0; --j) {
[email protected]ed18102fa2013-12-26 04:02:00224 BookmarkNode* child_node = permanent_node->GetChild(j);
[email protected]323dbf72013-03-30 17:08:33225 removed_nodes.push_back(child_node);
[email protected]9109f8a12013-06-12 18:07:48226 RemoveNodeAndGetRemovedUrls(child_node, &removed_urls);
[email protected]323dbf72013-03-30 17:08:33227 }
228 }
229 }
230 EndExtensiveChanges();
231 if (store_.get())
232 store_->ScheduleSave();
233
[email protected]323dbf72013-03-30 17:08:33234 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
[email protected]5cd942208a2014-06-11 06:16:46235 BookmarkAllUserNodesRemoved(this, removed_urls));
236}
237
[email protected]b3c33d462009-06-26 22:29:20238void BookmarkModel::Move(const BookmarkNode* node,
239 const BookmarkNode* new_parent,
[email protected]d8e41ed2008-09-11 15:22:32240 int index) {
[email protected]f25387b2008-08-21 15:20:33241 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
[email protected]6b4d64c2011-07-29 21:33:24242 is_root_node(new_parent) || is_permanent_node(node)) {
initial.commit09911bf2008-07-26 23:55:29243 NOTREACHED();
244 return;
245 }
246
247 if (new_parent->HasAncestor(node)) {
248 // Can't make an ancestor of the node be a child of the node.
249 NOTREACHED();
250 return;
251 }
252
[email protected]2d48ee842011-03-08 23:27:29253 const BookmarkNode* old_parent = node->parent();
[email protected]368f3a72011-03-08 17:17:48254 int old_index = old_parent->GetIndexOf(node);
initial.commit09911bf2008-07-26 23:55:29255
256 if (old_parent == new_parent &&
257 (index == old_index || index == old_index + 1)) {
258 // Node is already in this position, nothing to do.
259 return;
260 }
261
[email protected]9e583642012-12-05 02:48:32262 SetDateFolderModified(new_parent, Time::Now());
263
initial.commit09911bf2008-07-26 23:55:29264 if (old_parent == new_parent && index > old_index)
265 index--;
[email protected]b3c33d462009-06-26 22:29:20266 BookmarkNode* mutable_new_parent = AsMutable(new_parent);
[email protected]a0dd6a32011-03-18 17:31:37267 mutable_new_parent->Add(AsMutable(node), index);
initial.commit09911bf2008-07-26 23:55:29268
[email protected]f25387b2008-08-21 15:20:33269 if (store_.get())
270 store_->ScheduleSave();
271
[email protected]d8e41ed2008-09-11 15:22:32272 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
initial.commit09911bf2008-07-26 23:55:29273 BookmarkNodeMoved(this, old_parent, old_index,
274 new_parent, index));
275}
276
[email protected]4e187ef652010-03-11 05:21:35277void BookmarkModel::Copy(const BookmarkNode* node,
278 const BookmarkNode* new_parent,
279 int index) {
280 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
[email protected]6b4d64c2011-07-29 21:33:24281 is_root_node(new_parent) || is_permanent_node(node)) {
[email protected]4e187ef652010-03-11 05:21:35282 NOTREACHED();
283 return;
284 }
285
286 if (new_parent->HasAncestor(node)) {
287 // Can't make an ancestor of the node be a child of the node.
288 NOTREACHED();
289 return;
290 }
291
[email protected]c6a7a3d2011-03-12 01:04:30292 SetDateFolderModified(new_parent, Time::Now());
[email protected]67a8ae42013-05-20 09:42:39293 BookmarkNodeData drag_data(node);
294 std::vector<BookmarkNodeData::Element> elements(drag_data.elements);
[email protected]b1864502010-11-13 00:55:51295 // CloneBookmarkNode will use BookmarkModel methods to do the job, so we
[email protected]1a566fae2010-04-16 01:05:06296 // don't need to send notifications here.
[email protected]2cd924d2014-07-15 18:56:52297 bookmarks::CloneBookmarkNode(this, elements, new_parent, index, true);
[email protected]4e187ef652010-03-11 05:21:35298
299 if (store_.get())
300 store_->ScheduleSave();
[email protected]4e187ef652010-03-11 05:21:35301}
302
[email protected]6a4e5a02012-06-26 19:47:48303const gfx::Image& BookmarkModel::GetFavicon(const BookmarkNode* node) {
[email protected]ea2e5aa52009-05-20 18:01:28304 DCHECK(node);
[email protected]bcc38612012-10-23 01:10:27305 if (node->favicon_state() == BookmarkNode::INVALID_FAVICON) {
[email protected]b3c33d462009-06-26 22:29:20306 BookmarkNode* mutable_node = AsMutable(node);
[email protected]504fca82014-05-07 22:48:08307 LoadFavicon(
308 mutable_node,
309 client_->PreferTouchIcon() ?
310 favicon_base::TOUCH_ICON :
311 favicon_base::FAVICON);
[email protected]ea2e5aa52009-05-20 18:01:28312 }
313 return node->favicon();
314}
315
[email protected]504fca82014-05-07 22:48:08316favicon_base::IconType BookmarkModel::GetFaviconType(const BookmarkNode* node) {
317 DCHECK(node);
318 return node->favicon_type();
319}
320
[email protected]6a848b52014-04-26 22:06:54321void BookmarkModel::SetTitle(const BookmarkNode* node,
322 const base::string16& title) {
[email protected]f25387b2008-08-21 15:20:33323 if (!node) {
324 NOTREACHED();
325 return;
326 }
[email protected]0491ff72011-12-30 00:45:59327 if (node->GetTitle() == title)
initial.commit09911bf2008-07-26 23:55:29328 return;
[email protected]f25387b2008-08-21 15:20:33329
[email protected]043a76d2014-06-05 16:36:24330 if (is_permanent_node(node) && !client_->CanSetPermanentNodeTitle(node)) {
[email protected]baf4f922009-10-19 16:44:07331 NOTREACHED();
332 return;
333 }
334
[email protected]472f95e2013-06-10 16:49:18335 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
336 OnWillChangeBookmarkNode(this, node));
337
[email protected]85d911c2009-05-19 03:59:42338 // The title index doesn't support changing the title, instead we remove then
339 // add it back.
[email protected]01eec882009-05-22 18:13:28340 index_->Remove(node);
[email protected]0491ff72011-12-30 00:45:59341 AsMutable(node)->SetTitle(title);
[email protected]01eec882009-05-22 18:13:28342 index_->Add(node);
[email protected]85d911c2009-05-19 03:59:42343
[email protected]f25387b2008-08-21 15:20:33344 if (store_.get())
345 store_->ScheduleSave();
346
[email protected]d8e41ed2008-09-11 15:22:32347 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
initial.commit09911bf2008-07-26 23:55:29348 BookmarkNodeChanged(this, node));
349}
350
[email protected]e5486602010-02-09 21:27:55351void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) {
352 if (!node) {
353 NOTREACHED();
354 return;
355 }
356
357 // We cannot change the URL of a folder.
358 if (node->is_folder()) {
359 NOTREACHED();
360 return;
361 }
362
[email protected]5d4077542011-07-21 20:24:07363 if (node->url() == url)
[email protected]e5486602010-02-09 21:27:55364 return;
365
[email protected]5b5c9b7f32011-07-21 01:07:18366 BookmarkNode* mutable_node = AsMutable(node);
367 mutable_node->InvalidateFavicon();
368 CancelPendingFaviconLoadRequests(mutable_node);
[email protected]e5486602010-02-09 21:27:55369
[email protected]472f95e2013-06-10 16:49:18370 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
371 OnWillChangeBookmarkNode(this, node));
372
[email protected]e5486602010-02-09 21:27:55373 {
[email protected]20305ec2011-01-21 04:55:52374 base::AutoLock url_lock(url_lock_);
[email protected]5db00bca2013-12-23 00:43:09375 RemoveNodeFromURLSet(mutable_node);
[email protected]5d4077542011-07-21 20:24:07376 mutable_node->set_url(url);
[email protected]5b5c9b7f32011-07-21 01:07:18377 nodes_ordered_by_url_set_.insert(mutable_node);
[email protected]e5486602010-02-09 21:27:55378 }
379
380 if (store_.get())
381 store_->ScheduleSave();
382
383 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
384 BookmarkNodeChanged(this, node));
385}
386
[email protected]1858410f2012-10-26 05:06:45387void BookmarkModel::SetNodeMetaInfo(const BookmarkNode* node,
388 const std::string& key,
389 const std::string& value) {
[email protected]39e113452013-11-26 00:43:06390 std::string old_value;
391 if (node->GetMetaInfo(key, &old_value) && old_value == value)
392 return;
393
[email protected]cd869ede2013-10-17 12:29:40394 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
395 OnWillChangeBookmarkMetaInfo(this, node));
396
[email protected]1858410f2012-10-26 05:06:45397 if (AsMutable(node)->SetMetaInfo(key, value) && store_.get())
398 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40399
400 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
401 BookmarkMetaInfoChanged(this, node));
[email protected]1858410f2012-10-26 05:06:45402}
403
[email protected]e38a87d2013-12-05 01:35:18404void BookmarkModel::SetNodeMetaInfoMap(
405 const BookmarkNode* node,
406 const BookmarkNode::MetaInfoMap& meta_info_map) {
407 const BookmarkNode::MetaInfoMap* old_meta_info_map = node->GetMetaInfoMap();
408 if ((!old_meta_info_map && meta_info_map.empty()) ||
409 (old_meta_info_map && meta_info_map == *old_meta_info_map))
410 return;
411
412 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
413 OnWillChangeBookmarkMetaInfo(this, node));
414
415 AsMutable(node)->SetMetaInfoMap(meta_info_map);
416 if (store_.get())
417 store_->ScheduleSave();
418
419 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
420 BookmarkMetaInfoChanged(this, node));
421}
422
[email protected]1858410f2012-10-26 05:06:45423void BookmarkModel::DeleteNodeMetaInfo(const BookmarkNode* node,
424 const std::string& key) {
[email protected]39e113452013-11-26 00:43:06425 const BookmarkNode::MetaInfoMap* meta_info_map = node->GetMetaInfoMap();
426 if (!meta_info_map || meta_info_map->find(key) == meta_info_map->end())
427 return;
428
[email protected]cd869ede2013-10-17 12:29:40429 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
430 OnWillChangeBookmarkMetaInfo(this, node));
431
[email protected]1858410f2012-10-26 05:06:45432 if (AsMutable(node)->DeleteMetaInfo(key) && store_.get())
433 store_->ScheduleSave();
[email protected]cd869ede2013-10-17 12:29:40434
435 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
436 BookmarkMetaInfoChanged(this, node));
[email protected]1858410f2012-10-26 05:06:45437}
438
[email protected]39e113452013-11-26 00:43:06439void BookmarkModel::SetNodeSyncTransactionVersion(
440 const BookmarkNode* node,
441 int64 sync_transaction_version) {
[email protected]043a76d2014-06-05 16:36:24442 DCHECK(client_->CanSyncNode(node));
443
[email protected]39e113452013-11-26 00:43:06444 if (sync_transaction_version == node->sync_transaction_version())
445 return;
446
447 AsMutable(node)->set_sync_transaction_version(sync_transaction_version);
448 if (store_.get())
449 store_->ScheduleSave();
450}
451
[email protected]6a848b52014-04-26 22:06:54452void BookmarkModel::OnFaviconChanged(const std::set<GURL>& urls) {
453 // Ignore events if |Load| has not been called yet.
454 if (!store_)
455 return;
456
457 // Prevent the observers from getting confused for multiple favicon loads.
458 for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
459 std::vector<const BookmarkNode*> nodes;
460 GetNodesByURL(*i, &nodes);
461 for (size_t i = 0; i < nodes.size(); ++i) {
462 // Got an updated favicon, for a URL, do a new request.
463 BookmarkNode* node = AsMutable(nodes[i]);
464 node->InvalidateFavicon();
465 CancelPendingFaviconLoadRequests(node);
466 FOR_EACH_OBSERVER(BookmarkModelObserver,
467 observers_,
468 BookmarkNodeFaviconChanged(this, node));
469 }
470 }
471}
472
[email protected]b61445c2012-10-27 00:11:42473void BookmarkModel::SetDateAdded(const BookmarkNode* node,
[email protected]af77ce622014-05-10 11:48:16474 Time date_added) {
[email protected]b61445c2012-10-27 00:11:42475 if (!node) {
476 NOTREACHED();
477 return;
478 }
479
480 if (node->date_added() == date_added)
481 return;
482
483 if (is_permanent_node(node)) {
484 NOTREACHED();
485 return;
486 }
487
488 AsMutable(node)->set_date_added(date_added);
489
490 // Syncing might result in dates newer than the folder's last modified date.
491 if (date_added > node->parent()->date_folder_modified()) {
492 // Will trigger store_->ScheduleSave().
493 SetDateFolderModified(node->parent(), date_added);
494 } else if (store_.get()) {
495 store_->ScheduleSave();
496 }
497}
498
[email protected]848cd05e2008-09-19 18:33:48499void BookmarkModel::GetNodesByURL(const GURL& url,
[email protected]b3c33d462009-06-26 22:29:20500 std::vector<const BookmarkNode*>* nodes) {
[email protected]20305ec2011-01-21 04:55:52501 base::AutoLock url_lock(url_lock_);
[email protected]ea2e5aa52009-05-20 18:01:28502 BookmarkNode tmp_node(url);
initial.commit09911bf2008-07-26 23:55:29503 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node);
[email protected]5d4077542011-07-21 20:24:07504 while (i != nodes_ordered_by_url_set_.end() && (*i)->url() == url) {
[email protected]848cd05e2008-09-19 18:33:48505 nodes->push_back(*i);
506 ++i;
507 }
508}
509
[email protected]23e39692014-06-06 21:10:13510const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL(
[email protected]b3c33d462009-06-26 22:29:20511 const GURL& url) {
512 std::vector<const BookmarkNode*> nodes;
[email protected]848cd05e2008-09-19 18:33:48513 GetNodesByURL(url, &nodes);
[email protected]2cd924d2014-07-15 18:56:52514 std::sort(nodes.begin(), nodes.end(), &bookmarks::MoreRecentlyAdded);
[email protected]23e39692014-06-06 21:10:13515
516 // Look for the first node that the user can edit.
517 for (size_t i = 0; i < nodes.size(); ++i) {
518 if (client_->CanBeEditedByUser(nodes[i]))
519 return nodes[i];
520 }
521
522 return NULL;
initial.commit09911bf2008-07-26 23:55:29523}
524
[email protected]cf8e8172011-07-23 00:46:24525bool BookmarkModel::HasBookmarks() {
526 base::AutoLock url_lock(url_lock_);
527 return !nodes_ordered_by_url_set_.empty();
528}
529
530bool BookmarkModel::IsBookmarked(const GURL& url) {
531 base::AutoLock url_lock(url_lock_);
532 return IsBookmarkedNoLock(url);
533}
534
[email protected]0f7bee52012-08-06 20:04:17535void BookmarkModel::GetBookmarks(
[email protected]cef7931c2014-06-06 09:56:09536 std::vector<BookmarkModel::URLAndTitle>* bookmarks) {
[email protected]20305ec2011-01-21 04:55:52537 base::AutoLock url_lock(url_lock_);
[email protected]848cd05e2008-09-19 18:33:48538 const GURL* last_url = NULL;
[email protected]90ef13132008-08-27 03:27:46539 for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin();
540 i != nodes_ordered_by_url_set_.end(); ++i) {
[email protected]5d4077542011-07-21 20:24:07541 const GURL* url = &((*i)->url());
[email protected]848cd05e2008-09-19 18:33:48542 // Only add unique URLs.
[email protected]0f7bee52012-08-06 20:04:17543 if (!last_url || *url != *last_url) {
[email protected]cef7931c2014-06-06 09:56:09544 BookmarkModel::URLAndTitle bookmark;
[email protected]0f7bee52012-08-06 20:04:17545 bookmark.url = *url;
546 bookmark.title = (*i)->GetTitle();
547 bookmarks->push_back(bookmark);
548 }
[email protected]848cd05e2008-09-19 18:33:48549 last_url = url;
[email protected]90ef13132008-08-27 03:27:46550 }
551}
552
[email protected]cf8e8172011-07-23 00:46:24553void BookmarkModel::BlockTillLoaded() {
554 loaded_signal_.Wait();
[email protected]848cd05e2008-09-19 18:33:48555}
556
[email protected]39703292011-03-18 17:03:40557const BookmarkNode* BookmarkModel::AddFolder(const BookmarkNode* parent,
558 int index,
[email protected]96920152013-12-04 21:00:16559 const base::string16& title) {
[email protected]eb59ad12014-04-24 00:05:08560 return AddFolderWithMetaInfo(parent, index, title, NULL);
561}
562const BookmarkNode* BookmarkModel::AddFolderWithMetaInfo(
563 const BookmarkNode* parent,
564 int index,
565 const base::string16& title,
566 const BookmarkNode::MetaInfoMap* meta_info) {
[email protected]6b4d64c2011-07-29 21:33:24567 if (!loaded_ || is_root_node(parent) || !IsValidIndex(parent, index, true)) {
initial.commit09911bf2008-07-26 23:55:29568 // Can't add to the root.
569 NOTREACHED();
570 return NULL;
571 }
572
[email protected]5b5c9b7f32011-07-21 01:07:18573 BookmarkNode* new_node = new BookmarkNode(generate_next_node_id(), GURL());
[email protected]edb63cc2011-03-11 02:00:41574 new_node->set_date_folder_modified(Time::Now());
[email protected]aee236542011-12-01 04:34:03575 // Folders shouldn't have line breaks in their titles.
[email protected]0491ff72011-12-30 00:45:59576 new_node->SetTitle(title);
[email protected]037db002009-10-19 20:06:08577 new_node->set_type(BookmarkNode::FOLDER);
[email protected]eb59ad12014-04-24 00:05:08578 if (meta_info)
579 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29580
[email protected]a42ec64a2012-12-20 17:04:24581 return AddNode(AsMutable(parent), index, new_node);
initial.commit09911bf2008-07-26 23:55:29582}
583
[email protected]e64e9012010-01-11 23:10:55584const BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent,
585 int index,
[email protected]96920152013-12-04 21:00:16586 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55587 const GURL& url) {
[email protected]eb59ad12014-04-24 00:05:08588 return AddURLWithCreationTimeAndMetaInfo(
589 parent,
590 index,
591 base::CollapseWhitespace(title, false),
592 url,
593 Time::Now(),
594 NULL);
initial.commit09911bf2008-07-26 23:55:29595}
596
[email protected]eb59ad12014-04-24 00:05:08597const BookmarkNode* BookmarkModel::AddURLWithCreationTimeAndMetaInfo(
[email protected]e64e9012010-01-11 23:10:55598 const BookmarkNode* parent,
599 int index,
[email protected]96920152013-12-04 21:00:16600 const base::string16& title,
[email protected]e64e9012010-01-11 23:10:55601 const GURL& url,
[email protected]eb59ad12014-04-24 00:05:08602 const Time& creation_time,
603 const BookmarkNode::MetaInfoMap* meta_info) {
[email protected]6b4d64c2011-07-29 21:33:24604 if (!loaded_ || !url.is_valid() || is_root_node(parent) ||
[email protected]f25387b2008-08-21 15:20:33605 !IsValidIndex(parent, index, true)) {
initial.commit09911bf2008-07-26 23:55:29606 NOTREACHED();
607 return NULL;
608 }
initial.commit09911bf2008-07-26 23:55:29609
[email protected]b61445c2012-10-27 00:11:42610 // Syncing may result in dates newer than the last modified date.
[email protected]8ad613b2012-10-12 21:28:45611 if (creation_time > parent->date_folder_modified())
612 SetDateFolderModified(parent, creation_time);
initial.commit09911bf2008-07-26 23:55:29613
[email protected]ea2e5aa52009-05-20 18:01:28614 BookmarkNode* new_node = new BookmarkNode(generate_next_node_id(), url);
[email protected]0491ff72011-12-30 00:45:59615 new_node->SetTitle(title);
[email protected]b3c33d462009-06-26 22:29:20616 new_node->set_date_added(creation_time);
[email protected]037db002009-10-19 20:06:08617 new_node->set_type(BookmarkNode::URL);
[email protected]eb59ad12014-04-24 00:05:08618 if (meta_info)
619 new_node->SetMetaInfoMap(*meta_info);
initial.commit09911bf2008-07-26 23:55:29620
[email protected]776e7492008-10-23 16:47:41621 {
622 // Only hold the lock for the duration of the insert.
[email protected]20305ec2011-01-21 04:55:52623 base::AutoLock url_lock(url_lock_);
[email protected]776e7492008-10-23 16:47:41624 nodes_ordered_by_url_set_.insert(new_node);
625 }
initial.commit09911bf2008-07-26 23:55:29626
[email protected]a42ec64a2012-12-20 17:04:24627 return AddNode(AsMutable(parent), index, new_node);
initial.commit09911bf2008-07-26 23:55:29628}
629
[email protected]b3c33d462009-06-26 22:29:20630void BookmarkModel::SortChildren(const BookmarkNode* parent) {
[email protected]23e39692014-06-06 21:10:13631 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24632
[email protected]6b4d64c2011-07-29 21:33:24633 if (!parent || !parent->is_folder() || is_root_node(parent) ||
[email protected]9c1a75a2011-03-10 02:38:12634 parent->child_count() <= 1) {
[email protected]e2f86d92009-02-25 00:22:01635 return;
636 }
637
[email protected]472f95e2013-06-10 16:49:18638 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
639 OnWillReorderBookmarkNode(this, parent));
640
[email protected]ef762642009-03-05 16:30:25641 UErrorCode error = U_ZERO_ERROR;
[email protected]94d914522013-04-02 19:49:47642 scoped_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
[email protected]ef762642009-03-05 16:30:25643 if (U_FAILURE(error))
644 collator.reset(NULL);
[email protected]b3c33d462009-06-26 22:29:20645 BookmarkNode* mutable_parent = AsMutable(parent);
646 std::sort(mutable_parent->children().begin(),
647 mutable_parent->children().end(),
[email protected]ef762642009-03-05 16:30:25648 SortComparator(collator.get()));
[email protected]e2f86d92009-02-25 00:22:01649
[email protected]997a0362009-03-12 03:10:51650 if (store_.get())
651 store_->ScheduleSave();
652
[email protected]e2f86d92009-02-25 00:22:01653 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
654 BookmarkNodeChildrenReordered(this, parent));
655}
656
[email protected]472f95e2013-06-10 16:49:18657void BookmarkModel::ReorderChildren(
658 const BookmarkNode* parent,
[email protected]257d5082013-08-06 07:46:43659 const std::vector<const BookmarkNode*>& ordered_nodes) {
[email protected]23e39692014-06-06 21:10:13660 DCHECK(client_->CanBeEditedByUser(parent));
[email protected]043a76d2014-06-05 16:36:24661
[email protected]472f95e2013-06-10 16:49:18662 // Ensure that all children in |parent| are in |ordered_nodes|.
663 DCHECK_EQ(static_cast<size_t>(parent->child_count()), ordered_nodes.size());
664 for (size_t i = 0; i < ordered_nodes.size(); ++i)
665 DCHECK_EQ(parent, ordered_nodes[i]->parent());
666
667 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
668 OnWillReorderBookmarkNode(this, parent));
669
[email protected]257d5082013-08-06 07:46:43670 AsMutable(parent)->SetChildren(
671 *(reinterpret_cast<const std::vector<BookmarkNode*>*>(&ordered_nodes)));
[email protected]472f95e2013-06-10 16:49:18672
673 if (store_.get())
674 store_->ScheduleSave();
675
676 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
677 BookmarkNodeChildrenReordered(this, parent));
678}
679
[email protected]c6a7a3d2011-03-12 01:04:30680void BookmarkModel::SetDateFolderModified(const BookmarkNode* parent,
681 const Time time) {
[email protected]eea8fd5532009-12-16 00:08:10682 DCHECK(parent);
[email protected]edb63cc2011-03-11 02:00:41683 AsMutable(parent)->set_date_folder_modified(time);
[email protected]eea8fd5532009-12-16 00:08:10684
685 if (store_.get())
686 store_->ScheduleSave();
687}
688
[email protected]c6a7a3d2011-03-12 01:04:30689void BookmarkModel::ResetDateFolderModified(const BookmarkNode* node) {
690 SetDateFolderModified(node, Time());
initial.commit09911bf2008-07-26 23:55:29691}
692
[email protected]b3a84892014-04-23 04:28:07693void BookmarkModel::GetBookmarksMatching(
[email protected]96920152013-12-04 21:00:16694 const base::string16& text,
[email protected]e64e9012010-01-11 23:10:55695 size_t max_count,
[email protected]b3a84892014-04-23 04:28:07696 std::vector<BookmarkMatch>* matches) {
[email protected]01eec882009-05-22 18:13:28697 if (!loaded_)
698 return;
699
[email protected]b3a84892014-04-23 04:28:07700 index_->GetBookmarksMatching(text, max_count, matches);
[email protected]85d911c2009-05-19 03:59:42701}
702
[email protected]9876bb1c2008-12-16 20:42:25703void BookmarkModel::ClearStore() {
[email protected]265e88e2014-07-07 20:45:19704 store_.reset();
[email protected]9876bb1c2008-12-16 20:42:25705}
706
[email protected]bc770a032011-12-12 17:35:30707void BookmarkModel::SetPermanentNodeVisible(BookmarkNode::Type type,
708 bool value) {
[email protected]043a76d2014-06-05 16:36:24709 BookmarkPermanentNode* node = AsMutable(PermanentNode(type));
710 node->set_visible(value || client_->IsPermanentNodeVisible(node));
[email protected]996dbe82014-05-12 12:32:18711}
712
713const BookmarkPermanentNode* BookmarkModel::PermanentNode(
714 BookmarkNode::Type type) {
[email protected]1da5f712011-12-06 05:52:26715 DCHECK(loaded_);
[email protected]bc770a032011-12-12 17:35:30716 switch (type) {
717 case BookmarkNode::BOOKMARK_BAR:
[email protected]996dbe82014-05-12 12:32:18718 return bookmark_bar_node_;
[email protected]bc770a032011-12-12 17:35:30719 case BookmarkNode::OTHER_NODE:
[email protected]996dbe82014-05-12 12:32:18720 return other_node_;
[email protected]bc770a032011-12-12 17:35:30721 case BookmarkNode::MOBILE:
[email protected]996dbe82014-05-12 12:32:18722 return mobile_node_;
[email protected]bc770a032011-12-12 17:35:30723 default:
724 NOTREACHED();
[email protected]996dbe82014-05-12 12:32:18725 return NULL;
[email protected]bc770a032011-12-12 17:35:30726 }
[email protected]1da5f712011-12-06 05:52:26727}
728
[email protected]dddc1b42008-10-09 20:56:59729bool BookmarkModel::IsBookmarkedNoLock(const GURL& url) {
[email protected]ea2e5aa52009-05-20 18:01:28730 BookmarkNode tmp_node(url);
[email protected]dddc1b42008-10-09 20:56:59731 return (nodes_ordered_by_url_set_.find(&tmp_node) !=
732 nodes_ordered_by_url_set_.end());
733}
734
[email protected]d8e41ed2008-09-11 15:22:32735void BookmarkModel::RemoveNode(BookmarkNode* node,
736 std::set<GURL>* removed_urls) {
[email protected]b3c33d462009-06-26 22:29:20737 if (!loaded_ || !node || is_permanent_node(node)) {
[email protected]f25387b2008-08-21 15:20:33738 NOTREACHED();
739 return;
740 }
741
[email protected]323dbf72013-03-30 17:08:33742 url_lock_.AssertAcquired();
[email protected]0890e60e2011-06-27 14:55:21743 if (node->is_url()) {
[email protected]5db00bca2013-12-23 00:43:09744 RemoveNodeFromURLSet(node);
[email protected]5d4077542011-07-21 20:24:07745 removed_urls->insert(node->url());
[email protected]01eec882009-05-22 18:13:28746 index_->Remove(node);
initial.commit09911bf2008-07-26 23:55:29747 }
748
[email protected]abc2f262011-03-15 21:15:44749 CancelPendingFaviconLoadRequests(node);
initial.commit09911bf2008-07-26 23:55:29750
751 // Recurse through children.
[email protected]9c1a75a2011-03-10 02:38:12752 for (int i = node->child_count() - 1; i >= 0; --i)
[email protected]f25387b2008-08-21 15:20:33753 RemoveNode(node->GetChild(i), removed_urls);
initial.commit09911bf2008-07-26 23:55:29754}
755
[email protected]6a848b52014-04-26 22:06:54756void BookmarkModel::DoneLoading(scoped_ptr<BookmarkLoadDetails> details) {
757 DCHECK(details);
[email protected]01eec882009-05-22 18:13:28758 if (loaded_) {
759 // We should only ever be loaded once.
760 NOTREACHED();
761 return;
762 }
763
[email protected]01eec882009-05-22 18:13:28764 next_node_id_ = details->max_id();
[email protected]367d7072009-07-13 23:27:13765 if (details->computed_checksum() != details->stored_checksum() ||
766 details->ids_reassigned()) {
767 // If bookmarks file changed externally, the IDs may have changed
768 // externally. In that case, the decoder may have reassigned IDs to make
769 // them unique. So when the file has changed externally, we should save the
770 // bookmarks file to persist new IDs.
771 if (store_.get())
772 store_->ScheduleSave();
773 }
[email protected]d22d8732010-05-04 19:24:42774 bookmark_bar_node_ = details->release_bb_node();
775 other_node_ = details->release_other_folder_node();
[email protected]37bc9132011-12-01 22:29:29776 mobile_node_ = details->release_mobile_folder_node();
[email protected]d22d8732010-05-04 19:24:42777 index_.reset(details->release_index());
[email protected]01eec882009-05-22 18:13:28778
[email protected]043a76d2014-06-05 16:36:24779 // Get any extra nodes and take ownership of them at the |root_|.
780 std::vector<BookmarkPermanentNode*> extra_nodes;
781 details->release_extra_nodes(&extra_nodes);
782
[email protected]82f4655a2011-10-18 13:05:43783 // WARNING: order is important here, various places assume the order is
[email protected]996dbe82014-05-12 12:32:18784 // constant (but can vary between embedders with the initial visibility
785 // of permanent nodes).
[email protected]043a76d2014-06-05 16:36:24786 std::vector<BookmarkPermanentNode*> root_children;
787 root_children.push_back(bookmark_bar_node_);
788 root_children.push_back(other_node_);
789 root_children.push_back(mobile_node_);
790 for (size_t i = 0; i < extra_nodes.size(); ++i)
791 root_children.push_back(extra_nodes[i]);
792 std::stable_sort(root_children.begin(),
793 root_children.end(),
[email protected]996dbe82014-05-12 12:32:18794 VisibilityComparator(client_));
[email protected]043a76d2014-06-05 16:36:24795 for (size_t i = 0; i < root_children.size(); ++i)
[email protected]996dbe82014-05-12 12:32:18796 root_.Add(root_children[i], static_cast<int>(i));
[email protected]6c1164042009-05-08 14:41:08797
[email protected]39e113452013-11-26 00:43:06798 root_.SetMetaInfoMap(details->model_meta_info_map());
799 root_.set_sync_transaction_version(details->model_sync_transaction_version());
[email protected]1858410f2012-10-26 05:06:45800
[email protected]90ef13132008-08-27 03:27:46801 {
[email protected]20305ec2011-01-21 04:55:52802 base::AutoLock url_lock(url_lock_);
[email protected]90ef13132008-08-27 03:27:46803 // Update nodes_ordered_by_url_set_ from the nodes.
804 PopulateNodesByURL(&root_);
805 }
[email protected]f25387b2008-08-21 15:20:33806
initial.commit09911bf2008-07-26 23:55:29807 loaded_ = true;
808
[email protected]cbcd6412009-03-09 22:31:39809 loaded_signal_.Signal();
[email protected]90ef13132008-08-27 03:27:46810
[email protected]f25387b2008-08-21 15:20:33811 // Notify our direct observers.
[email protected]c58c5ea2011-07-13 21:43:16812 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
[email protected]d1bc7af2013-12-26 05:45:13813 BookmarkModelLoaded(this, details->ids_reassigned()));
initial.commit09911bf2008-07-26 23:55:29814}
815
[email protected]d8e41ed2008-09-11 15:22:32816void BookmarkModel::RemoveAndDeleteNode(BookmarkNode* delete_me) {
817 scoped_ptr<BookmarkNode> node(delete_me);
initial.commit09911bf2008-07-26 23:55:29818
[email protected]323dbf72013-03-30 17:08:33819 const BookmarkNode* parent = node->parent();
initial.commit09911bf2008-07-26 23:55:29820 DCHECK(parent);
[email protected]368f3a72011-03-08 17:17:48821 int index = parent->GetIndexOf(node.get());
[email protected]323dbf72013-03-30 17:08:33822
[email protected]472f95e2013-06-10 16:49:18823 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
824 OnWillRemoveBookmarks(this, parent, index, node.get()));
825
[email protected]9109f8a12013-06-12 18:07:48826 std::set<GURL> removed_urls;
[email protected]90ef13132008-08-27 03:27:46827 {
[email protected]20305ec2011-01-21 04:55:52828 base::AutoLock url_lock(url_lock_);
[email protected]9109f8a12013-06-12 18:07:48829 RemoveNodeAndGetRemovedUrls(node.get(), &removed_urls);
[email protected]90ef13132008-08-27 03:27:46830 }
initial.commit09911bf2008-07-26 23:55:29831
[email protected]f25387b2008-08-21 15:20:33832 if (store_.get())
833 store_->ScheduleSave();
834
[email protected]ba8b6ac2014-05-02 01:07:34835 FOR_EACH_OBSERVER(
836 BookmarkModelObserver,
837 observers_,
838 BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls));
[email protected]323dbf72013-03-30 17:08:33839}
[email protected]f25387b2008-08-21 15:20:33840
[email protected]5db00bca2013-12-23 00:43:09841void BookmarkModel::RemoveNodeFromURLSet(BookmarkNode* node) {
842 // NOTE: this is called in such a way that url_lock_ is already held. As
843 // such, this doesn't explicitly grab the lock.
844 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node);
845 DCHECK(i != nodes_ordered_by_url_set_.end());
846 // i points to the first node with the URL, advance until we find the
847 // node we're removing.
848 while (*i != node)
849 ++i;
850 nodes_ordered_by_url_set_.erase(i);
851}
852
[email protected]323dbf72013-03-30 17:08:33853void BookmarkModel::RemoveNodeAndGetRemovedUrls(BookmarkNode* node,
854 std::set<GURL>* removed_urls) {
855 // NOTE: this method should be always called with |url_lock_| held.
856 // This method does not explicitly acquires a lock.
857 url_lock_.AssertAcquired();
858 DCHECK(removed_urls);
859 BookmarkNode* parent = AsMutable(node->parent());
860 DCHECK(parent);
861 parent->Remove(node);
862 RemoveNode(node, removed_urls);
863 // RemoveNode adds an entry to removed_urls for each node of type URL. As we
864 // allow duplicates we need to remove any entries that are still bookmarked.
865 for (std::set<GURL>::iterator i = removed_urls->begin();
866 i != removed_urls->end();) {
867 if (IsBookmarkedNoLock(*i)) {
868 // When we erase the iterator pointing at the erasee is
869 // invalidated, so using i++ here within the "erase" call is
870 // important as it advances the iterator before passing the
871 // old value through to erase.
872 removed_urls->erase(i++);
873 } else {
874 ++i;
875 }
876 }
877}
878
[email protected]d8e41ed2008-09-11 15:22:32879BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
880 int index,
[email protected]a42ec64a2012-12-20 17:04:24881 BookmarkNode* node) {
[email protected]224e1d12014-06-17 03:03:05882 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
883 OnWillAddBookmarkNode(this, node));
884
[email protected]a0dd6a32011-03-18 17:31:37885 parent->Add(node, index);
initial.commit09911bf2008-07-26 23:55:29886
[email protected]f25387b2008-08-21 15:20:33887 if (store_.get())
888 store_->ScheduleSave();
889
[email protected]d8e41ed2008-09-11 15:22:32890 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
initial.commit09911bf2008-07-26 23:55:29891 BookmarkNodeAdded(this, parent, index));
[email protected]f25387b2008-08-21 15:20:33892
[email protected]01eec882009-05-22 18:13:28893 index_->Add(node);
[email protected]85d911c2009-05-19 03:59:42894
initial.commit09911bf2008-07-26 23:55:29895 return node;
896}
897
[email protected]b3c33d462009-06-26 22:29:20898bool BookmarkModel::IsValidIndex(const BookmarkNode* parent,
[email protected]d8e41ed2008-09-11 15:22:32899 int index,
900 bool allow_end) {
[email protected]776e7492008-10-23 16:47:41901 return (parent && parent->is_folder() &&
[email protected]9c1a75a2011-03-10 02:38:12902 (index >= 0 && (index < parent->child_count() ||
903 (allow_end && index == parent->child_count()))));
[email protected]bd1b96702009-07-08 21:54:14904}
[email protected]f25387b2008-08-21 15:20:33905
[email protected]bc770a032011-12-12 17:35:30906BookmarkPermanentNode* BookmarkModel::CreatePermanentNode(
907 BookmarkNode::Type type) {
[email protected]e1f76c62011-06-30 20:15:39908 DCHECK(type == BookmarkNode::BOOKMARK_BAR ||
909 type == BookmarkNode::OTHER_NODE ||
[email protected]37bc9132011-12-01 22:29:29910 type == BookmarkNode::MOBILE);
[email protected]bc770a032011-12-12 17:35:30911 BookmarkPermanentNode* node =
912 new BookmarkPermanentNode(generate_next_node_id());
[email protected]043a76d2014-06-05 16:36:24913 node->set_type(type);
914 node->set_visible(client_->IsPermanentNodeVisible(node));
[email protected]bc770a032011-12-12 17:35:30915
916 int title_id;
917 switch (type) {
918 case BookmarkNode::BOOKMARK_BAR:
919 title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
920 break;
921 case BookmarkNode::OTHER_NODE:
922 title_id = IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME;
923 break;
924 case BookmarkNode::MOBILE:
925 title_id = IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME;
926 break;
927 default:
[email protected]97fdd162011-12-03 20:50:12928 NOTREACHED();
[email protected]bc770a032011-12-12 17:35:30929 title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
930 break;
[email protected]7caca8a22010-08-21 18:25:31931 }
[email protected]0491ff72011-12-30 00:45:59932 node->SetTitle(l10n_util::GetStringUTF16(title_id));
initial.commit09911bf2008-07-26 23:55:29933 return node;
934}
935
[email protected]abc2f262011-03-15 21:15:44936void BookmarkModel::OnFaviconDataAvailable(
[email protected]0ea3db52012-12-07 01:32:01937 BookmarkNode* node,
[email protected]504fca82014-05-07 22:48:08938 favicon_base::IconType icon_type,
[email protected]7627e0b42014-04-17 17:20:53939 const favicon_base::FaviconImageResult& image_result) {
[email protected]4167c3a2008-08-21 18:12:20940 DCHECK(node);
[email protected]e95b717f2014-02-06 13:47:13941 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
[email protected]bcc38612012-10-23 01:10:27942 node->set_favicon_state(BookmarkNode::LOADED_FAVICON);
[email protected]65baa222012-08-30 15:43:51943 if (!image_result.image.IsEmpty()) {
[email protected]504fca82014-05-07 22:48:08944 node->set_favicon_type(icon_type);
[email protected]65baa222012-08-30 15:43:51945 node->set_favicon(image_result.image);
[email protected]2ad0e872012-11-30 01:24:46946 node->set_icon_url(image_result.icon_url);
[email protected]65baa222012-08-30 15:43:51947 FaviconLoaded(node);
[email protected]504fca82014-05-07 22:48:08948 } else if (icon_type == favicon_base::TOUCH_ICON) {
949 // Couldn't load the touch icon, fallback to the regular favicon.
950 DCHECK(client_->PreferTouchIcon());
951 LoadFavicon(node, favicon_base::FAVICON);
initial.commit09911bf2008-07-26 23:55:29952 }
953}
954
[email protected]504fca82014-05-07 22:48:08955void BookmarkModel::LoadFavicon(
956 BookmarkNode* node,
957 favicon_base::IconType icon_type) {
[email protected]0890e60e2011-06-27 14:55:21958 if (node->is_folder())
initial.commit09911bf2008-07-26 23:55:29959 return;
960
[email protected]5d4077542011-07-21 20:24:07961 DCHECK(node->url().is_valid());
[email protected]504fca82014-05-07 22:48:08962 node->set_favicon_state(BookmarkNode::LOADING_FAVICON);
[email protected]25244a932014-07-12 23:00:24963 base::CancelableTaskTracker::TaskId taskId =
964 client_->GetFaviconImageForPageURL(
965 node->url(),
966 icon_type,
967 base::Bind(
968 &BookmarkModel::OnFaviconDataAvailable,
969 base::Unretained(this),
970 node,
971 icon_type),
972 &cancelable_task_tracker_);
[email protected]6a848b52014-04-26 22:06:54973 if (taskId != base::CancelableTaskTracker::kBadTaskId)
974 node->set_favicon_load_task_id(taskId);
initial.commit09911bf2008-07-26 23:55:29975}
976
[email protected]5b5c9b7f32011-07-21 01:07:18977void BookmarkModel::FaviconLoaded(const BookmarkNode* node) {
978 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
979 BookmarkNodeFaviconChanged(this, node));
980}
981
[email protected]abc2f262011-03-15 21:15:44982void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) {
[email protected]e95b717f2014-02-06 13:47:13983 if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) {
[email protected]0ea3db52012-12-07 01:32:01984 cancelable_task_tracker_.TryCancel(node->favicon_load_task_id());
[email protected]e95b717f2014-02-06 13:47:13985 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
initial.commit09911bf2008-07-26 23:55:29986 }
987}
988
[email protected]d8e41ed2008-09-11 15:22:32989void BookmarkModel::PopulateNodesByURL(BookmarkNode* node) {
[email protected]90ef13132008-08-27 03:27:46990 // NOTE: this is called with url_lock_ already held. As such, this doesn't
991 // explicitly grab the lock.
[email protected]f25387b2008-08-21 15:20:33992 if (node->is_url())
993 nodes_ordered_by_url_set_.insert(node);
[email protected]9c1a75a2011-03-10 02:38:12994 for (int i = 0; i < node->child_count(); ++i)
[email protected]f25387b2008-08-21 15:20:33995 PopulateNodesByURL(node->GetChild(i));
996}
[email protected]4d89f382009-05-12 06:56:49997
[email protected]367d7072009-07-13 23:27:13998int64 BookmarkModel::generate_next_node_id() {
[email protected]4d89f382009-05-12 06:56:49999 return next_node_id_++;
1000}
[email protected]01eec882009-05-22 18:13:281001
[email protected]6a848b52014-04-26 22:06:541002scoped_ptr<BookmarkLoadDetails> BookmarkModel::CreateLoadDetails(
1003 const std::string& accept_languages) {
[email protected]bc770a032011-12-12 17:35:301004 BookmarkPermanentNode* bb_node =
1005 CreatePermanentNode(BookmarkNode::BOOKMARK_BAR);
1006 BookmarkPermanentNode* other_node =
1007 CreatePermanentNode(BookmarkNode::OTHER_NODE);
1008 BookmarkPermanentNode* mobile_node =
1009 CreatePermanentNode(BookmarkNode::MOBILE);
[email protected]6a848b52014-04-26 22:06:541010 return scoped_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails(
1011 bb_node,
1012 other_node,
1013 mobile_node,
[email protected]043a76d2014-06-05 16:36:241014 client_->GetLoadExtraNodesCallback(),
[email protected]6a848b52014-04-26 22:06:541015 new BookmarkIndex(client_, index_urls_, accept_languages),
1016 next_node_id_));
[email protected]01eec882009-05-22 18:13:281017}