Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(400)

Side by Side Diff: components/bookmarks/core/browser/bookmark_model.cc

Issue 284893003: Move bookmarks/core/... to bookmarks/... (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixing errors reported by presubmit Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/bookmarks/core/browser/bookmark_model.h"
6
7 #include <algorithm>
8 #include <functional>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/i18n/string_compare.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/strings/string_util.h"
16 #include "components/bookmarks/core/browser/bookmark_expanded_state_tracker.h"
17 #include "components/bookmarks/core/browser/bookmark_index.h"
18 #include "components/bookmarks/core/browser/bookmark_match.h"
19 #include "components/bookmarks/core/browser/bookmark_model_observer.h"
20 #include "components/bookmarks/core/browser/bookmark_node_data.h"
21 #include "components/bookmarks/core/browser/bookmark_storage.h"
22 #include "components/bookmarks/core/browser/bookmark_utils.h"
23 #include "components/favicon_base/favicon_types.h"
24 #include "grit/component_strings.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/gfx/favicon_size.h"
27
28 using base::Time;
29
30 namespace {
31
32 // Helper to get a mutable bookmark node.
33 BookmarkNode* AsMutable(const BookmarkNode* node) {
34 return const_cast<BookmarkNode*>(node);
35 }
36
37 // Helper to get a mutable permanent bookmark node.
38 BookmarkPermanentNode* AsMutable(const BookmarkPermanentNode* node) {
39 return const_cast<BookmarkPermanentNode*>(node);
40 }
41
42 // Comparator used when sorting permanent nodes. Nodes that are initially
43 // visible are sorted before nodes that are initially hidden.
44 class VisibilityComparator
45 : public std::binary_function<const BookmarkPermanentNode*,
46 const BookmarkPermanentNode*,
47 bool> {
48 public:
49 explicit VisibilityComparator(BookmarkClient* client) : client_(client) {}
50
51 // Returns true if |n1| preceeds |n2|.
52 bool operator()(const BookmarkPermanentNode* n1,
53 const BookmarkPermanentNode* n2) {
54 bool n1_visible = client_->IsPermanentNodeVisible(n1->type());
55 bool n2_visible = client_->IsPermanentNodeVisible(n2->type());
56 return n1_visible != n2_visible && n1_visible;
57 }
58
59 private:
60 BookmarkClient* client_;
61 };
62
63 // Comparator used when sorting bookmarks. Folders are sorted first, then
64 // bookmarks.
65 class SortComparator : public std::binary_function<const BookmarkNode*,
66 const BookmarkNode*,
67 bool> {
68 public:
69 explicit SortComparator(icu::Collator* collator) : collator_(collator) {}
70
71 // Returns true if |n1| preceeds |n2|.
72 bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) {
73 if (n1->type() == n2->type()) {
74 // Types are the same, compare the names.
75 if (!collator_)
76 return n1->GetTitle() < n2->GetTitle();
77 return base::i18n::CompareString16WithCollator(
78 collator_, n1->GetTitle(), n2->GetTitle()) == UCOL_LESS;
79 }
80 // Types differ, sort such that folders come first.
81 return n1->is_folder();
82 }
83
84 private:
85 icu::Collator* collator_;
86 };
87
88 } // namespace
89
90 // BookmarkModel --------------------------------------------------------------
91
92 BookmarkModel::BookmarkModel(BookmarkClient* client, bool index_urls)
93 : client_(client),
94 loaded_(false),
95 root_(GURL()),
96 bookmark_bar_node_(NULL),
97 other_node_(NULL),
98 mobile_node_(NULL),
99 next_node_id_(1),
100 observers_(ObserverList<BookmarkModelObserver>::NOTIFY_EXISTING_ONLY),
101 index_urls_(index_urls),
102 loaded_signal_(true, false),
103 extensive_changes_(0) {
104 DCHECK(client_);
105 }
106
107 BookmarkModel::~BookmarkModel() {
108 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
109 BookmarkModelBeingDeleted(this));
110
111 if (store_.get()) {
112 // The store maintains a reference back to us. We need to tell it we're gone
113 // so that it doesn't try and invoke a method back on us again.
114 store_->BookmarkModelDeleted();
115 }
116 }
117
118 void BookmarkModel::Shutdown() {
119 if (loaded_)
120 return;
121
122 // See comment in HistoryService::ShutdownOnUIThread where this is invoked for
123 // details. It is also called when the BookmarkModel is deleted.
124 loaded_signal_.Signal();
125 }
126
127 void BookmarkModel::Load(
128 PrefService* pref_service,
129 const std::string& accept_languages,
130 const base::FilePath& profile_path,
131 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
132 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) {
133 if (store_.get()) {
134 // If the store is non-null, it means Load was already invoked. Load should
135 // only be invoked once.
136 NOTREACHED();
137 return;
138 }
139
140 expanded_state_tracker_.reset(
141 new BookmarkExpandedStateTracker(this, pref_service));
142
143 // Load the bookmarks. BookmarkStorage notifies us when done.
144 store_ = new BookmarkStorage(this, profile_path, io_task_runner.get());
145 store_->LoadBookmarks(CreateLoadDetails(accept_languages), ui_task_runner);
146 }
147
148 const BookmarkNode* BookmarkModel::GetParentForNewNodes() {
149 std::vector<const BookmarkNode*> nodes =
150 bookmark_utils::GetMostRecentlyModifiedFolders(this, 1);
151 DCHECK(!nodes.empty()); // This list is always padded with default folders.
152 return nodes[0];
153 }
154
155 void BookmarkModel::AddObserver(BookmarkModelObserver* observer) {
156 observers_.AddObserver(observer);
157 }
158
159 void BookmarkModel::RemoveObserver(BookmarkModelObserver* observer) {
160 observers_.RemoveObserver(observer);
161 }
162
163 void BookmarkModel::BeginExtensiveChanges() {
164 if (++extensive_changes_ == 1) {
165 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
166 ExtensiveBookmarkChangesBeginning(this));
167 }
168 }
169
170 void BookmarkModel::EndExtensiveChanges() {
171 --extensive_changes_;
172 DCHECK_GE(extensive_changes_, 0);
173 if (extensive_changes_ == 0) {
174 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
175 ExtensiveBookmarkChangesEnded(this));
176 }
177 }
178
179 void BookmarkModel::BeginGroupedChanges() {
180 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
181 GroupedBookmarkChangesBeginning(this));
182 }
183
184 void BookmarkModel::EndGroupedChanges() {
185 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
186 GroupedBookmarkChangesEnded(this));
187 }
188
189 void BookmarkModel::Remove(const BookmarkNode* parent, int index) {
190 if (!loaded_ || !IsValidIndex(parent, index, false) || is_root_node(parent)) {
191 NOTREACHED();
192 return;
193 }
194 RemoveAndDeleteNode(AsMutable(parent->GetChild(index)));
195 }
196
197 void BookmarkModel::RemoveAll() {
198 std::set<GURL> removed_urls;
199 ScopedVector<BookmarkNode> removed_nodes;
200
201 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
202 OnWillRemoveAllBookmarks(this));
203
204 BeginExtensiveChanges();
205 // Skip deleting permanent nodes. Permanent bookmark nodes are the root and
206 // its immediate children. For removing all non permanent nodes just remove
207 // all children of non-root permanent nodes.
208 {
209 base::AutoLock url_lock(url_lock_);
210 for (int i = 0; i < root_.child_count(); ++i) {
211 BookmarkNode* permanent_node = root_.GetChild(i);
212 for (int j = permanent_node->child_count() - 1; j >= 0; --j) {
213 BookmarkNode* child_node = permanent_node->GetChild(j);
214 removed_nodes.push_back(child_node);
215 RemoveNodeAndGetRemovedUrls(child_node, &removed_urls);
216 }
217 }
218 }
219 EndExtensiveChanges();
220 if (store_.get())
221 store_->ScheduleSave();
222
223 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
224 BookmarkAllNodesRemoved(this, removed_urls));
225 }
226
227 void BookmarkModel::Move(const BookmarkNode* node,
228 const BookmarkNode* new_parent,
229 int index) {
230 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
231 is_root_node(new_parent) || is_permanent_node(node)) {
232 NOTREACHED();
233 return;
234 }
235
236 if (new_parent->HasAncestor(node)) {
237 // Can't make an ancestor of the node be a child of the node.
238 NOTREACHED();
239 return;
240 }
241
242 const BookmarkNode* old_parent = node->parent();
243 int old_index = old_parent->GetIndexOf(node);
244
245 if (old_parent == new_parent &&
246 (index == old_index || index == old_index + 1)) {
247 // Node is already in this position, nothing to do.
248 return;
249 }
250
251 SetDateFolderModified(new_parent, Time::Now());
252
253 if (old_parent == new_parent && index > old_index)
254 index--;
255 BookmarkNode* mutable_new_parent = AsMutable(new_parent);
256 mutable_new_parent->Add(AsMutable(node), index);
257
258 if (store_.get())
259 store_->ScheduleSave();
260
261 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
262 BookmarkNodeMoved(this, old_parent, old_index,
263 new_parent, index));
264 }
265
266 void BookmarkModel::Copy(const BookmarkNode* node,
267 const BookmarkNode* new_parent,
268 int index) {
269 if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
270 is_root_node(new_parent) || is_permanent_node(node)) {
271 NOTREACHED();
272 return;
273 }
274
275 if (new_parent->HasAncestor(node)) {
276 // Can't make an ancestor of the node be a child of the node.
277 NOTREACHED();
278 return;
279 }
280
281 SetDateFolderModified(new_parent, Time::Now());
282 BookmarkNodeData drag_data(node);
283 std::vector<BookmarkNodeData::Element> elements(drag_data.elements);
284 // CloneBookmarkNode will use BookmarkModel methods to do the job, so we
285 // don't need to send notifications here.
286 bookmark_utils::CloneBookmarkNode(this, elements, new_parent, index, true);
287
288 if (store_.get())
289 store_->ScheduleSave();
290 }
291
292 const gfx::Image& BookmarkModel::GetFavicon(const BookmarkNode* node) {
293 DCHECK(node);
294 if (node->favicon_state() == BookmarkNode::INVALID_FAVICON) {
295 BookmarkNode* mutable_node = AsMutable(node);
296 LoadFavicon(
297 mutable_node,
298 client_->PreferTouchIcon() ?
299 favicon_base::TOUCH_ICON :
300 favicon_base::FAVICON);
301 }
302 return node->favicon();
303 }
304
305 favicon_base::IconType BookmarkModel::GetFaviconType(const BookmarkNode* node) {
306 DCHECK(node);
307 return node->favicon_type();
308 }
309
310 void BookmarkModel::SetTitle(const BookmarkNode* node,
311 const base::string16& title) {
312 if (!node) {
313 NOTREACHED();
314 return;
315 }
316 if (node->GetTitle() == title)
317 return;
318
319 if (is_permanent_node(node)) {
320 NOTREACHED();
321 return;
322 }
323
324 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
325 OnWillChangeBookmarkNode(this, node));
326
327 // The title index doesn't support changing the title, instead we remove then
328 // add it back.
329 index_->Remove(node);
330 AsMutable(node)->SetTitle(title);
331 index_->Add(node);
332
333 if (store_.get())
334 store_->ScheduleSave();
335
336 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
337 BookmarkNodeChanged(this, node));
338 }
339
340 void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) {
341 if (!node) {
342 NOTREACHED();
343 return;
344 }
345
346 // We cannot change the URL of a folder.
347 if (node->is_folder()) {
348 NOTREACHED();
349 return;
350 }
351
352 if (node->url() == url)
353 return;
354
355 BookmarkNode* mutable_node = AsMutable(node);
356 mutable_node->InvalidateFavicon();
357 CancelPendingFaviconLoadRequests(mutable_node);
358
359 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
360 OnWillChangeBookmarkNode(this, node));
361
362 {
363 base::AutoLock url_lock(url_lock_);
364 RemoveNodeFromURLSet(mutable_node);
365 mutable_node->set_url(url);
366 nodes_ordered_by_url_set_.insert(mutable_node);
367 }
368
369 if (store_.get())
370 store_->ScheduleSave();
371
372 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
373 BookmarkNodeChanged(this, node));
374 }
375
376 void BookmarkModel::SetNodeMetaInfo(const BookmarkNode* node,
377 const std::string& key,
378 const std::string& value) {
379 std::string old_value;
380 if (node->GetMetaInfo(key, &old_value) && old_value == value)
381 return;
382
383 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
384 OnWillChangeBookmarkMetaInfo(this, node));
385
386 if (AsMutable(node)->SetMetaInfo(key, value) && store_.get())
387 store_->ScheduleSave();
388
389 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
390 BookmarkMetaInfoChanged(this, node));
391 }
392
393 void BookmarkModel::SetNodeMetaInfoMap(
394 const BookmarkNode* node,
395 const BookmarkNode::MetaInfoMap& meta_info_map) {
396 const BookmarkNode::MetaInfoMap* old_meta_info_map = node->GetMetaInfoMap();
397 if ((!old_meta_info_map && meta_info_map.empty()) ||
398 (old_meta_info_map && meta_info_map == *old_meta_info_map))
399 return;
400
401 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
402 OnWillChangeBookmarkMetaInfo(this, node));
403
404 AsMutable(node)->SetMetaInfoMap(meta_info_map);
405 if (store_.get())
406 store_->ScheduleSave();
407
408 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
409 BookmarkMetaInfoChanged(this, node));
410 }
411
412 void BookmarkModel::DeleteNodeMetaInfo(const BookmarkNode* node,
413 const std::string& key) {
414 const BookmarkNode::MetaInfoMap* meta_info_map = node->GetMetaInfoMap();
415 if (!meta_info_map || meta_info_map->find(key) == meta_info_map->end())
416 return;
417
418 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
419 OnWillChangeBookmarkMetaInfo(this, node));
420
421 if (AsMutable(node)->DeleteMetaInfo(key) && store_.get())
422 store_->ScheduleSave();
423
424 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
425 BookmarkMetaInfoChanged(this, node));
426 }
427
428 void BookmarkModel::SetNodeSyncTransactionVersion(
429 const BookmarkNode* node,
430 int64 sync_transaction_version) {
431 if (sync_transaction_version == node->sync_transaction_version())
432 return;
433
434 AsMutable(node)->set_sync_transaction_version(sync_transaction_version);
435 if (store_.get())
436 store_->ScheduleSave();
437 }
438
439 void BookmarkModel::OnFaviconChanged(const std::set<GURL>& urls) {
440 // Ignore events if |Load| has not been called yet.
441 if (!store_)
442 return;
443
444 // Prevent the observers from getting confused for multiple favicon loads.
445 for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
446 std::vector<const BookmarkNode*> nodes;
447 GetNodesByURL(*i, &nodes);
448 for (size_t i = 0; i < nodes.size(); ++i) {
449 // Got an updated favicon, for a URL, do a new request.
450 BookmarkNode* node = AsMutable(nodes[i]);
451 node->InvalidateFavicon();
452 CancelPendingFaviconLoadRequests(node);
453 FOR_EACH_OBSERVER(BookmarkModelObserver,
454 observers_,
455 BookmarkNodeFaviconChanged(this, node));
456 }
457 }
458 }
459
460 void BookmarkModel::SetDateAdded(const BookmarkNode* node,
461 Time date_added) {
462 if (!node) {
463 NOTREACHED();
464 return;
465 }
466
467 if (node->date_added() == date_added)
468 return;
469
470 if (is_permanent_node(node)) {
471 NOTREACHED();
472 return;
473 }
474
475 AsMutable(node)->set_date_added(date_added);
476
477 // Syncing might result in dates newer than the folder's last modified date.
478 if (date_added > node->parent()->date_folder_modified()) {
479 // Will trigger store_->ScheduleSave().
480 SetDateFolderModified(node->parent(), date_added);
481 } else if (store_.get()) {
482 store_->ScheduleSave();
483 }
484 }
485
486 void BookmarkModel::GetNodesByURL(const GURL& url,
487 std::vector<const BookmarkNode*>* nodes) {
488 base::AutoLock url_lock(url_lock_);
489 BookmarkNode tmp_node(url);
490 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node);
491 while (i != nodes_ordered_by_url_set_.end() && (*i)->url() == url) {
492 nodes->push_back(*i);
493 ++i;
494 }
495 }
496
497 const BookmarkNode* BookmarkModel::GetMostRecentlyAddedNodeForURL(
498 const GURL& url) {
499 std::vector<const BookmarkNode*> nodes;
500 GetNodesByURL(url, &nodes);
501 if (nodes.empty())
502 return NULL;
503
504 std::sort(nodes.begin(), nodes.end(), &bookmark_utils::MoreRecentlyAdded);
505 return nodes.front();
506 }
507
508 bool BookmarkModel::HasBookmarks() {
509 base::AutoLock url_lock(url_lock_);
510 return !nodes_ordered_by_url_set_.empty();
511 }
512
513 bool BookmarkModel::IsBookmarked(const GURL& url) {
514 base::AutoLock url_lock(url_lock_);
515 return IsBookmarkedNoLock(url);
516 }
517
518 void BookmarkModel::GetBookmarks(
519 std::vector<BookmarkService::URLAndTitle>* bookmarks) {
520 base::AutoLock url_lock(url_lock_);
521 const GURL* last_url = NULL;
522 for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin();
523 i != nodes_ordered_by_url_set_.end(); ++i) {
524 const GURL* url = &((*i)->url());
525 // Only add unique URLs.
526 if (!last_url || *url != *last_url) {
527 BookmarkService::URLAndTitle bookmark;
528 bookmark.url = *url;
529 bookmark.title = (*i)->GetTitle();
530 bookmarks->push_back(bookmark);
531 }
532 last_url = url;
533 }
534 }
535
536 void BookmarkModel::BlockTillLoaded() {
537 loaded_signal_.Wait();
538 }
539
540 const BookmarkNode* BookmarkModel::AddFolder(const BookmarkNode* parent,
541 int index,
542 const base::string16& title) {
543 return AddFolderWithMetaInfo(parent, index, title, NULL);
544 }
545 const BookmarkNode* BookmarkModel::AddFolderWithMetaInfo(
546 const BookmarkNode* parent,
547 int index,
548 const base::string16& title,
549 const BookmarkNode::MetaInfoMap* meta_info) {
550 if (!loaded_ || is_root_node(parent) || !IsValidIndex(parent, index, true)) {
551 // Can't add to the root.
552 NOTREACHED();
553 return NULL;
554 }
555
556 BookmarkNode* new_node = new BookmarkNode(generate_next_node_id(), GURL());
557 new_node->set_date_folder_modified(Time::Now());
558 // Folders shouldn't have line breaks in their titles.
559 new_node->SetTitle(title);
560 new_node->set_type(BookmarkNode::FOLDER);
561 if (meta_info)
562 new_node->SetMetaInfoMap(*meta_info);
563
564 return AddNode(AsMutable(parent), index, new_node);
565 }
566
567 const BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent,
568 int index,
569 const base::string16& title,
570 const GURL& url) {
571 return AddURLWithCreationTimeAndMetaInfo(
572 parent,
573 index,
574 base::CollapseWhitespace(title, false),
575 url,
576 Time::Now(),
577 NULL);
578 }
579
580 const BookmarkNode* BookmarkModel::AddURLWithCreationTimeAndMetaInfo(
581 const BookmarkNode* parent,
582 int index,
583 const base::string16& title,
584 const GURL& url,
585 const Time& creation_time,
586 const BookmarkNode::MetaInfoMap* meta_info) {
587 if (!loaded_ || !url.is_valid() || is_root_node(parent) ||
588 !IsValidIndex(parent, index, true)) {
589 NOTREACHED();
590 return NULL;
591 }
592
593 // Syncing may result in dates newer than the last modified date.
594 if (creation_time > parent->date_folder_modified())
595 SetDateFolderModified(parent, creation_time);
596
597 BookmarkNode* new_node = new BookmarkNode(generate_next_node_id(), url);
598 new_node->SetTitle(title);
599 new_node->set_date_added(creation_time);
600 new_node->set_type(BookmarkNode::URL);
601 if (meta_info)
602 new_node->SetMetaInfoMap(*meta_info);
603
604 {
605 // Only hold the lock for the duration of the insert.
606 base::AutoLock url_lock(url_lock_);
607 nodes_ordered_by_url_set_.insert(new_node);
608 }
609
610 return AddNode(AsMutable(parent), index, new_node);
611 }
612
613 void BookmarkModel::SortChildren(const BookmarkNode* parent) {
614 if (!parent || !parent->is_folder() || is_root_node(parent) ||
615 parent->child_count() <= 1) {
616 return;
617 }
618
619 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
620 OnWillReorderBookmarkNode(this, parent));
621
622 UErrorCode error = U_ZERO_ERROR;
623 scoped_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
624 if (U_FAILURE(error))
625 collator.reset(NULL);
626 BookmarkNode* mutable_parent = AsMutable(parent);
627 std::sort(mutable_parent->children().begin(),
628 mutable_parent->children().end(),
629 SortComparator(collator.get()));
630
631 if (store_.get())
632 store_->ScheduleSave();
633
634 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
635 BookmarkNodeChildrenReordered(this, parent));
636 }
637
638 void BookmarkModel::ReorderChildren(
639 const BookmarkNode* parent,
640 const std::vector<const BookmarkNode*>& ordered_nodes) {
641 // Ensure that all children in |parent| are in |ordered_nodes|.
642 DCHECK_EQ(static_cast<size_t>(parent->child_count()), ordered_nodes.size());
643 for (size_t i = 0; i < ordered_nodes.size(); ++i)
644 DCHECK_EQ(parent, ordered_nodes[i]->parent());
645
646 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
647 OnWillReorderBookmarkNode(this, parent));
648
649 AsMutable(parent)->SetChildren(
650 *(reinterpret_cast<const std::vector<BookmarkNode*>*>(&ordered_nodes)));
651
652 if (store_.get())
653 store_->ScheduleSave();
654
655 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
656 BookmarkNodeChildrenReordered(this, parent));
657 }
658
659 void BookmarkModel::SetDateFolderModified(const BookmarkNode* parent,
660 const Time time) {
661 DCHECK(parent);
662 AsMutable(parent)->set_date_folder_modified(time);
663
664 if (store_.get())
665 store_->ScheduleSave();
666 }
667
668 void BookmarkModel::ResetDateFolderModified(const BookmarkNode* node) {
669 SetDateFolderModified(node, Time());
670 }
671
672 void BookmarkModel::GetBookmarksMatching(
673 const base::string16& text,
674 size_t max_count,
675 std::vector<BookmarkMatch>* matches) {
676 if (!loaded_)
677 return;
678
679 index_->GetBookmarksMatching(text, max_count, matches);
680 }
681
682 void BookmarkModel::ClearStore() {
683 store_ = NULL;
684 }
685
686 void BookmarkModel::SetPermanentNodeVisible(BookmarkNode::Type type,
687 bool value) {
688 AsMutable(PermanentNode(type))->set_visible(
689 value || client_->IsPermanentNodeVisible(type));
690 }
691
692 const BookmarkPermanentNode* BookmarkModel::PermanentNode(
693 BookmarkNode::Type type) {
694 DCHECK(loaded_);
695 switch (type) {
696 case BookmarkNode::BOOKMARK_BAR:
697 return bookmark_bar_node_;
698 case BookmarkNode::OTHER_NODE:
699 return other_node_;
700 case BookmarkNode::MOBILE:
701 return mobile_node_;
702 default:
703 NOTREACHED();
704 return NULL;
705 }
706 }
707
708 bool BookmarkModel::IsBookmarkedNoLock(const GURL& url) {
709 BookmarkNode tmp_node(url);
710 return (nodes_ordered_by_url_set_.find(&tmp_node) !=
711 nodes_ordered_by_url_set_.end());
712 }
713
714 void BookmarkModel::RemoveNode(BookmarkNode* node,
715 std::set<GURL>* removed_urls) {
716 if (!loaded_ || !node || is_permanent_node(node)) {
717 NOTREACHED();
718 return;
719 }
720
721 url_lock_.AssertAcquired();
722 if (node->is_url()) {
723 RemoveNodeFromURLSet(node);
724 removed_urls->insert(node->url());
725 index_->Remove(node);
726 }
727
728 CancelPendingFaviconLoadRequests(node);
729
730 // Recurse through children.
731 for (int i = node->child_count() - 1; i >= 0; --i)
732 RemoveNode(node->GetChild(i), removed_urls);
733 }
734
735 void BookmarkModel::DoneLoading(scoped_ptr<BookmarkLoadDetails> details) {
736 DCHECK(details);
737 if (loaded_) {
738 // We should only ever be loaded once.
739 NOTREACHED();
740 return;
741 }
742
743 next_node_id_ = details->max_id();
744 if (details->computed_checksum() != details->stored_checksum() ||
745 details->ids_reassigned()) {
746 // If bookmarks file changed externally, the IDs may have changed
747 // externally. In that case, the decoder may have reassigned IDs to make
748 // them unique. So when the file has changed externally, we should save the
749 // bookmarks file to persist new IDs.
750 if (store_.get())
751 store_->ScheduleSave();
752 }
753 bookmark_bar_node_ = details->release_bb_node();
754 other_node_ = details->release_other_folder_node();
755 mobile_node_ = details->release_mobile_folder_node();
756 index_.reset(details->release_index());
757
758 // WARNING: order is important here, various places assume the order is
759 // constant (but can vary between embedders with the initial visibility
760 // of permanent nodes).
761 BookmarkPermanentNode* root_children[] = {
762 bookmark_bar_node_, other_node_, mobile_node_,
763 };
764 std::stable_sort(root_children,
765 root_children + arraysize(root_children),
766 VisibilityComparator(client_));
767 for (size_t i = 0; i < arraysize(root_children); ++i) {
768 root_.Add(root_children[i], static_cast<int>(i));
769 }
770
771 root_.SetMetaInfoMap(details->model_meta_info_map());
772 root_.set_sync_transaction_version(details->model_sync_transaction_version());
773
774 {
775 base::AutoLock url_lock(url_lock_);
776 // Update nodes_ordered_by_url_set_ from the nodes.
777 PopulateNodesByURL(&root_);
778 }
779
780 loaded_ = true;
781
782 loaded_signal_.Signal();
783
784 // Notify our direct observers.
785 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
786 BookmarkModelLoaded(this, details->ids_reassigned()));
787 }
788
789 void BookmarkModel::RemoveAndDeleteNode(BookmarkNode* delete_me) {
790 scoped_ptr<BookmarkNode> node(delete_me);
791
792 const BookmarkNode* parent = node->parent();
793 DCHECK(parent);
794 int index = parent->GetIndexOf(node.get());
795
796 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
797 OnWillRemoveBookmarks(this, parent, index, node.get()));
798
799 std::set<GURL> removed_urls;
800 {
801 base::AutoLock url_lock(url_lock_);
802 RemoveNodeAndGetRemovedUrls(node.get(), &removed_urls);
803 }
804
805 if (store_.get())
806 store_->ScheduleSave();
807
808 FOR_EACH_OBSERVER(
809 BookmarkModelObserver,
810 observers_,
811 BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls));
812 }
813
814 void BookmarkModel::RemoveNodeFromURLSet(BookmarkNode* node) {
815 // NOTE: this is called in such a way that url_lock_ is already held. As
816 // such, this doesn't explicitly grab the lock.
817 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node);
818 DCHECK(i != nodes_ordered_by_url_set_.end());
819 // i points to the first node with the URL, advance until we find the
820 // node we're removing.
821 while (*i != node)
822 ++i;
823 nodes_ordered_by_url_set_.erase(i);
824 }
825
826 void BookmarkModel::RemoveNodeAndGetRemovedUrls(BookmarkNode* node,
827 std::set<GURL>* removed_urls) {
828 // NOTE: this method should be always called with |url_lock_| held.
829 // This method does not explicitly acquires a lock.
830 url_lock_.AssertAcquired();
831 DCHECK(removed_urls);
832 BookmarkNode* parent = AsMutable(node->parent());
833 DCHECK(parent);
834 parent->Remove(node);
835 RemoveNode(node, removed_urls);
836 // RemoveNode adds an entry to removed_urls for each node of type URL. As we
837 // allow duplicates we need to remove any entries that are still bookmarked.
838 for (std::set<GURL>::iterator i = removed_urls->begin();
839 i != removed_urls->end();) {
840 if (IsBookmarkedNoLock(*i)) {
841 // When we erase the iterator pointing at the erasee is
842 // invalidated, so using i++ here within the "erase" call is
843 // important as it advances the iterator before passing the
844 // old value through to erase.
845 removed_urls->erase(i++);
846 } else {
847 ++i;
848 }
849 }
850 }
851
852 BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
853 int index,
854 BookmarkNode* node) {
855 parent->Add(node, index);
856
857 if (store_.get())
858 store_->ScheduleSave();
859
860 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
861 BookmarkNodeAdded(this, parent, index));
862
863 index_->Add(node);
864
865 return node;
866 }
867
868 bool BookmarkModel::IsValidIndex(const BookmarkNode* parent,
869 int index,
870 bool allow_end) {
871 return (parent && parent->is_folder() &&
872 (index >= 0 && (index < parent->child_count() ||
873 (allow_end && index == parent->child_count()))));
874 }
875
876 BookmarkPermanentNode* BookmarkModel::CreatePermanentNode(
877 BookmarkNode::Type type) {
878 DCHECK(type == BookmarkNode::BOOKMARK_BAR ||
879 type == BookmarkNode::OTHER_NODE ||
880 type == BookmarkNode::MOBILE);
881 BookmarkPermanentNode* node =
882 new BookmarkPermanentNode(generate_next_node_id());
883 node->set_visible(client_->IsPermanentNodeVisible(type));
884
885 int title_id;
886 switch (type) {
887 case BookmarkNode::BOOKMARK_BAR:
888 title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
889 break;
890 case BookmarkNode::OTHER_NODE:
891 title_id = IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME;
892 break;
893 case BookmarkNode::MOBILE:
894 title_id = IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME;
895 break;
896 default:
897 NOTREACHED();
898 title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
899 break;
900 }
901 node->SetTitle(l10n_util::GetStringUTF16(title_id));
902 node->set_type(type);
903 return node;
904 }
905
906 void BookmarkModel::OnFaviconDataAvailable(
907 BookmarkNode* node,
908 favicon_base::IconType icon_type,
909 const favicon_base::FaviconImageResult& image_result) {
910 DCHECK(node);
911 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
912 node->set_favicon_state(BookmarkNode::LOADED_FAVICON);
913 if (!image_result.image.IsEmpty()) {
914 node->set_favicon_type(icon_type);
915 node->set_favicon(image_result.image);
916 node->set_icon_url(image_result.icon_url);
917 FaviconLoaded(node);
918 } else if (icon_type == favicon_base::TOUCH_ICON) {
919 // Couldn't load the touch icon, fallback to the regular favicon.
920 DCHECK(client_->PreferTouchIcon());
921 LoadFavicon(node, favicon_base::FAVICON);
922 }
923 }
924
925 void BookmarkModel::LoadFavicon(
926 BookmarkNode* node,
927 favicon_base::IconType icon_type) {
928 if (node->is_folder())
929 return;
930
931 DCHECK(node->url().is_valid());
932 node->set_favicon_state(BookmarkNode::LOADING_FAVICON);
933 base::CancelableTaskTracker::TaskId taskId = client_->GetFaviconImageForURL(
934 node->url(),
935 icon_type,
936 icon_type == favicon_base::FAVICON ? gfx::kFaviconSize : 0,
937 base::Bind(
938 &BookmarkModel::OnFaviconDataAvailable,
939 base::Unretained(this),
940 node,
941 icon_type),
942 &cancelable_task_tracker_);
943 if (taskId != base::CancelableTaskTracker::kBadTaskId)
944 node->set_favicon_load_task_id(taskId);
945 }
946
947 void BookmarkModel::FaviconLoaded(const BookmarkNode* node) {
948 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
949 BookmarkNodeFaviconChanged(this, node));
950 }
951
952 void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) {
953 if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) {
954 cancelable_task_tracker_.TryCancel(node->favicon_load_task_id());
955 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
956 }
957 }
958
959 void BookmarkModel::PopulateNodesByURL(BookmarkNode* node) {
960 // NOTE: this is called with url_lock_ already held. As such, this doesn't
961 // explicitly grab the lock.
962 if (node->is_url())
963 nodes_ordered_by_url_set_.insert(node);
964 for (int i = 0; i < node->child_count(); ++i)
965 PopulateNodesByURL(node->GetChild(i));
966 }
967
968 int64 BookmarkModel::generate_next_node_id() {
969 return next_node_id_++;
970 }
971
972 scoped_ptr<BookmarkLoadDetails> BookmarkModel::CreateLoadDetails(
973 const std::string& accept_languages) {
974 BookmarkPermanentNode* bb_node =
975 CreatePermanentNode(BookmarkNode::BOOKMARK_BAR);
976 BookmarkPermanentNode* other_node =
977 CreatePermanentNode(BookmarkNode::OTHER_NODE);
978 BookmarkPermanentNode* mobile_node =
979 CreatePermanentNode(BookmarkNode::MOBILE);
980 return scoped_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails(
981 bb_node,
982 other_node,
983 mobile_node,
984 new BookmarkIndex(client_, index_urls_, accept_languages),
985 next_node_id_));
986 }
OLDNEW
« no previous file with comments | « components/bookmarks/core/browser/bookmark_model.h ('k') | components/bookmarks/core/browser/bookmark_model_observer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698