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

Side by Side Diff: chrome/browser/bookmarks/bookmark_model.cc

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

Powered by Google App Engine
This is Rietveld 408576698