bookmark_model.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
13345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_model.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/l10n_util.h" 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/l10n_util_collator.h" 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/callback.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/scoped_vector.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "build/build_config.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_index.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_utils.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_storage.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/history_notifications.h" 173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/profile.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/notification_service.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "gfx/codec/png_codec.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time; 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Helper to get a mutable bookmark node. 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic BookmarkNode* AsMutable(const BookmarkNode* node) { 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return const_cast<BookmarkNode*>(node); 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // anonymous namespace 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// BookmarkNode --------------------------------------------------------------- 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBookmarkNode::BookmarkNode(const GURL& url) 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : url_(url) { 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Initialize(0); 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBookmarkNode::BookmarkNode(int64 id, const GURL& url) 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : url_(url) { 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Initialize(id); 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 463345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickBookmarkNode::~BookmarkNode() { 473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkNode::Initialize(int64 id) { 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id_ = id; 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch loaded_favicon_ = false; 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch favicon_load_handle_ = 0; 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type_ = !url_.is_empty() ? URL : BOOKMARK_BAR; 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch date_added_ = Time::Now(); 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkNode::Reset(const history::StarredEntry& entry) { 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(entry.type != history::StarredEntry::URL || entry.url == url_); 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch favicon_ = SkBitmap(); 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (entry.type) { 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case history::StarredEntry::URL: 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type_ = BookmarkNode::URL; 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case history::StarredEntry::USER_GROUP: 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type_ = BookmarkNode::FOLDER; 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case history::StarredEntry::BOOKMARK_BAR: 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type_ = BookmarkNode::BOOKMARK_BAR; 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case history::StarredEntry::OTHER: 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type_ = BookmarkNode::OTHER_NODE; 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch date_added_ = entry.date_added; 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch date_group_modified_ = entry.date_group_modified; 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetTitle(entry.title); 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// BookmarkModel -------------------------------------------------------------- 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Comparator used when sorting bookmarks. Folders are sorted first, then 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// bookmarks. 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass SortComparator : public std::binary_function<const BookmarkNode*, 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const BookmarkNode*, 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool> { 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch explicit SortComparator(icu::Collator* collator) : collator_(collator) { } 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns true if lhs preceeds rhs. 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool operator() (const BookmarkNode* n1, const BookmarkNode* n2) { 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (n1->type() == n2->type()) { 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Types are the same, compare the names. 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!collator_) 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return n1->GetTitle() < n2->GetTitle(); 1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return l10n_util::CompareStringWithCollator(collator_, 1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick UTF16ToWideHack(n1->GetTitle()), UTF16ToWideHack(n2->GetTitle())) == 1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick UCOL_LESS; 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Types differ, sort such that folders come first. 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return n1->is_folder(); 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch icu::Collator* collator_; 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBookmarkModel::BookmarkModel(Profile* profile) 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : profile_(profile), 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch loaded_(false), 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_changed_(false), 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch root_(GURL()), 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bookmark_bar_node_(NULL), 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch other_node_(NULL), 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch next_node_id_(1), 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch observers_(ObserverList<BookmarkModelObserver>::NOTIFY_EXISTING_ONLY), 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch loaded_signal_(TRUE, FALSE) { 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!profile_) { 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Profile is null during testing. 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DoneLoading(CreateLoadDetails()); 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBookmarkModel::~BookmarkModel() { 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkModelBeingDeleted(this)); 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (store_) { 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The store maintains a reference back to us. We need to tell it we're gone 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // so that it doesn't try and invoke a method back on us again. 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch store_->BookmarkModelDeleted(); 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::Load() { 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (store_.get()) { 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the store is non-null, it means Load was already invoked. Load should 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // only be invoked once. 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Listen for changes to favicons so that we can update the favicon of the 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // node appropriately. 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, NotificationType::FAVICON_CHANGED, 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<Profile>(profile_)); 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Load the bookmarks. BookmarkStorage notifies us when done. 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch store_ = new BookmarkStorage(profile_, this); 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch store_->LoadBookmarks(CreateLoadDetails()); 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst BookmarkNode* BookmarkModel::GetParentForNewNodes() { 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<const BookmarkNode*> nodes = 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bookmark_utils::GetMostRecentlyModifiedGroups(this, 1); 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return nodes.empty() ? bookmark_bar_node_ : nodes[0]; 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::Remove(const BookmarkNode* parent, int index) { 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!loaded_ || !IsValidIndex(parent, index, false) || is_root(parent)) { 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RemoveAndDeleteNode(AsMutable(parent->GetChild(index))); 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::Move(const BookmarkNode* node, 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const BookmarkNode* new_parent, 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index) { 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) || 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_root(new_parent) || is_permanent_node(node)) { 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (new_parent->HasAncestor(node)) { 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Can't make an ancestor of the node be a child of the node. 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetDateGroupModified(new_parent, Time::Now()); 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const BookmarkNode* old_parent = node->GetParent(); 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int old_index = old_parent->IndexOfChild(node); 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (old_parent == new_parent && 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (index == old_index || index == old_index + 1)) { 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Node is already in this position, nothing to do. 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (old_parent == new_parent && index > old_index) 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index--; 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* mutable_new_parent = AsMutable(new_parent); 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch mutable_new_parent->Add(index, AsMutable(node)); 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (store_.get()) 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch store_->ScheduleSave(); 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNodeMoved(this, old_parent, old_index, 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_parent, index)); 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::Copy(const BookmarkNode* node, 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const BookmarkNode* new_parent, 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index) { 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) || 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_root(new_parent) || is_permanent_node(node)) { 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (new_parent->HasAncestor(node)) { 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Can't make an ancestor of the node be a child of the node. 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetDateGroupModified(new_parent, Time::Now()); 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkDragData drag_data_(node); 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<BookmarkDragData::Element> elements(drag_data_.elements); 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // CloneDragData will use BookmarkModel methods to do the job, so we 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // don't need to send notifications here. 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bookmark_utils::CloneDragData(this, elements, new_parent, index); 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (store_.get()) 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch store_->ScheduleSave(); 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkBitmap& BookmarkModel::GetFavIcon(const BookmarkNode* node) { 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(node); 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!node->is_favicon_loaded()) { 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* mutable_node = AsMutable(node); 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch mutable_node->set_favicon_loaded(true); 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LoadFavIcon(mutable_node); 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return node->favicon(); 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::SetTitle(const BookmarkNode* node, const string16& title) { 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!node) { 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (node->GetTitle() == title) 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (node == bookmark_bar_node_ || node == other_node_) { 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The title index doesn't support changing the title, instead we remove then 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // add it back. 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index_->Remove(node); 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AsMutable(node)->SetTitle(title); 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index_->Add(node); 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (store_.get()) 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch store_->ScheduleSave(); 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNodeChanged(this, node)); 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) { 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!node) { 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We cannot change the URL of a folder. 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (node->is_folder()) { 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (url == node->GetURL()) 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AsMutable(node)->InvalidateFavicon(); 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CancelPendingFavIconLoadRequests(AsMutable(node)); 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutoLock url_lock(url_lock_); 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find( 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AsMutable(node)); 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(i != nodes_ordered_by_url_set_.end()); 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // i points to the first node with the URL, advance until we find the 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // node we're removing. 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (*i != node) 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++i; 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch nodes_ordered_by_url_set_.erase(i); 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AsMutable(node)->SetURL(url); 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch nodes_ordered_by_url_set_.insert(AsMutable(node)); 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (store_.get()) 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch store_->ScheduleSave(); 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNodeChanged(this, node)); 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::GetNodesByURL(const GURL& url, 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<const BookmarkNode*>* nodes) { 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutoLock url_lock(url_lock_); 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode tmp_node(url); 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node); 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (i != nodes_ordered_by_url_set_.end() && (*i)->GetURL() == url) { 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch nodes->push_back(*i); 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++i; 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst BookmarkNode* BookmarkModel::GetMostRecentlyAddedNodeForURL( 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& url) { 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<const BookmarkNode*> nodes; 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetNodesByURL(url, &nodes); 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (nodes.empty()) 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::sort(nodes.begin(), nodes.end(), &bookmark_utils::MoreRecentlyAdded); 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return nodes.front(); 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::GetBookmarks(std::vector<GURL>* urls) { 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutoLock url_lock(url_lock_); 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL* last_url = NULL; 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin(); 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != nodes_ordered_by_url_set_.end(); ++i) { 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL* url = &((*i)->GetURL()); 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Only add unique URLs. 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!last_url || *url != *last_url) 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch urls->push_back(*url); 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch last_url = url; 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool BookmarkModel::HasBookmarks() { 3503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick AutoLock url_lock(url_lock_); 3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return !nodes_ordered_by_url_set_.empty(); 3523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 3533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BookmarkModel::IsBookmarked(const GURL& url) { 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutoLock url_lock(url_lock_); 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return IsBookmarkedNoLock(url); 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst BookmarkNode* BookmarkModel::GetNodeByID(int64 id) { 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(sky): TreeNode needs a method that visits all nodes using a predicate. 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return GetNodeByID(&root_, id); 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst BookmarkNode* BookmarkModel::AddGroup(const BookmarkNode* parent, 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index, 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const string16& title) { 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!loaded_ || parent == &root_ || !IsValidIndex(parent, index, true)) { 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Can't add to the root. 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* new_node = new BookmarkNode(generate_next_node_id(), 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL()); 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_node->set_date_group_modified(Time::Now()); 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_node->SetTitle(title); 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_node->set_type(BookmarkNode::FOLDER); 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return AddNode(AsMutable(parent), index, new_node, false); 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent, 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index, 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const string16& title, 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& url) { 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return AddURLWithCreationTime(parent, index, title, url, Time::Now()); 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst BookmarkNode* BookmarkModel::AddURLWithCreationTime( 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const BookmarkNode* parent, 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index, 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const string16& title, 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& url, 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const Time& creation_time) { 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!loaded_ || !url.is_valid() || is_root(parent) || 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !IsValidIndex(parent, index, true)) { 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool was_bookmarked = IsBookmarked(url); 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetDateGroupModified(parent, creation_time); 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* new_node = new BookmarkNode(generate_next_node_id(), url); 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_node->SetTitle(title); 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_node->set_date_added(creation_time); 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_node->set_type(BookmarkNode::URL); 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Only hold the lock for the duration of the insert. 412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutoLock url_lock(url_lock_); 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch nodes_ordered_by_url_set_.insert(new_node); 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return AddNode(AsMutable(parent), index, new_node, was_bookmarked); 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::SortChildren(const BookmarkNode* parent) { 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!parent || !parent->is_folder() || is_root(parent) || 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch parent->GetChildCount() <= 1) { 422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UErrorCode error = U_ZERO_ERROR; 426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<icu::Collator> collator( 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch icu::Collator::createInstance( 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch icu::Locale(g_browser_process->GetApplicationLocale().c_str()), 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error)); 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (U_FAILURE(error)) 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch collator.reset(NULL); 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* mutable_parent = AsMutable(parent); 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::sort(mutable_parent->children().begin(), 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch mutable_parent->children().end(), 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SortComparator(collator.get())); 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (store_.get()) 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch store_->ScheduleSave(); 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNodeChildrenReordered(this, parent)); 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::SetURLStarred(const GURL& url, 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const string16& title, 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool is_starred) { 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<const BookmarkNode*> bookmarks; 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetNodesByURL(url, &bookmarks); 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool bookmarks_exist = !bookmarks.empty(); 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (is_starred == bookmarks_exist) 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; // Nothing to do, state already matches. 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (is_starred) { 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create a bookmark. 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const BookmarkNode* parent = GetParentForNewNodes(); 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddURL(parent, parent->GetChildCount(), title, url); 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Remove all the bookmarks. 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < bookmarks.size(); ++i) { 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const BookmarkNode* node = bookmarks[i]; 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Remove(node->GetParent(), node->GetParent()->IndexOfChild(node)); 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::SetDateGroupModified(const BookmarkNode* parent, 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const Time time) { 468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(parent); 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AsMutable(parent)->set_date_group_modified(time); 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (store_.get()) 472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch store_->ScheduleSave(); 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::ResetDateGroupModified(const BookmarkNode* node) { 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetDateGroupModified(node, Time()); 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::GetBookmarksWithTitlesMatching( 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const string16& text, 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t max_count, 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<bookmark_utils::TitleMatch>* matches) { 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!loaded_) 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick index_->GetBookmarksWithTitlesMatching(text, max_count, matches); 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::ClearStore() { 490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.RemoveAll(); 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch store_ = NULL; 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BookmarkModel::IsBookmarkedNoLock(const GURL& url) { 495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode tmp_node(url); 496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return (nodes_ordered_by_url_set_.find(&tmp_node) != 497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch nodes_ordered_by_url_set_.end()); 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::FavIconLoaded(const BookmarkNode* node) { 501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Send out notification to the observer. 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNodeFavIconLoaded(this, node)); 504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::RemoveNode(BookmarkNode* node, 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<GURL>* removed_urls) { 508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!loaded_ || !node || is_permanent_node(node)) { 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (node->type() == BookmarkNode::URL) { 514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: this is called in such a way that url_lock_ is already held. As 515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // such, this doesn't explicitly grab the lock. 516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node); 517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(i != nodes_ordered_by_url_set_.end()); 518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // i points to the first node with the URL, advance until we find the 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // node we're removing. 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (*i != node) 521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++i; 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch nodes_ordered_by_url_set_.erase(i); 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch removed_urls->insert(node->GetURL()); 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index_->Remove(node); 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CancelPendingFavIconLoadRequests(node); 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Recurse through children. 531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = node->GetChildCount() - 1; i >= 0; --i) 532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RemoveNode(node->GetChild(i), removed_urls); 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::DoneLoading( 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkLoadDetails* details_delete_me) { 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(details_delete_me); 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<BookmarkLoadDetails> details(details_delete_me); 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (loaded_) { 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We should only ever be loaded once. 541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch next_node_id_ = details->max_id(); 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (details->computed_checksum() != details->stored_checksum()) 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetFileChanged(); 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (details->computed_checksum() != details->stored_checksum() || 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch details->ids_reassigned()) { 550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If bookmarks file changed externally, the IDs may have changed 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // externally. In that case, the decoder may have reassigned IDs to make 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // them unique. So when the file has changed externally, we should save the 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // bookmarks file to persist new IDs. 554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (store_.get()) 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch store_->ScheduleSave(); 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bookmark_bar_node_ = details->release_bb_node(); 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch other_node_ = details->release_other_folder_node(); 559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index_.reset(details->release_index()); 560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // WARNING: order is important here, various places assume bookmark bar then 562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // other node. 563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch root_.Add(0, bookmark_bar_node_); 564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch root_.Add(1, other_node_); 565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutoLock url_lock(url_lock_); 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update nodes_ordered_by_url_set_ from the nodes. 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PopulateNodesByURL(&root_); 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch loaded_ = true; 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch loaded_signal_.Signal(); 575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Notify our direct observers. 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, Loaded(this)); 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // And generic notification. 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::current()->Notify( 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::BOOKMARK_MODEL_LOADED, 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<Profile>(profile_), 583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::NoDetails()); 584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::RemoveAndDeleteNode(BookmarkNode* delete_me) { 587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<BookmarkNode> node(delete_me); 588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* parent = AsMutable(node->GetParent()); 590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(parent); 591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index = parent->IndexOfChild(node.get()); 592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch parent->Remove(index); 593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::URLsStarredDetails details(false); 594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { 595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AutoLock url_lock(url_lock_); 596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RemoveNode(node.get(), &details.changed_urls); 597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // RemoveNode adds an entry to changed_urls for each node of type URL. As we 599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // allow duplicates we need to remove any entries that are still bookmarked. 600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::set<GURL>::iterator i = details.changed_urls.begin(); 601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != details.changed_urls.end(); ) { 602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (IsBookmarkedNoLock(*i)) { 603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When we erase the iterator pointing at the erasee is 604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // invalidated, so using i++ here within the "erase" call is 605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // important as it advances the iterator before passing the 606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // old value through to erase. 607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch details.changed_urls.erase(i++); 608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++i; 610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (store_.get()) 615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch store_->ScheduleSave(); 616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNodeRemoved(this, parent, index, node.get())); 619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (details.changed_urls.empty()) { 621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // No point in sending out notification if the starred state didn't change. 622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (profile_) { 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HistoryService* history = 627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); 628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (history) 629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history->URLsNoLongerBookmarked(details.changed_urls); 630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::current()->Notify( 633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::URLS_STARRED, 634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<Profile>(profile_), 635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Details<history::URLsStarredDetails>(&details)); 636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::BeginImportMode() { 639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkImportBeginning(this)); 641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::EndImportMode() { 644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkImportEnding(this)); 646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 648c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent, 649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index, 650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* node, 651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool was_bookmarked) { 652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch parent->Add(index, node); 653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (store_.get()) 655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch store_->ScheduleSave(); 656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNodeAdded(this, parent, index)); 659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index_->Add(node); 661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (node->type() == BookmarkNode::URL && !was_bookmarked) { 663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::URLsStarredDetails details(true); 664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch details.changed_urls.insert(node->GetURL()); 665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::current()->Notify( 666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::URLS_STARRED, 667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<Profile>(profile_), 668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Details<history::URLsStarredDetails>(&details)); 669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return node; 671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::BlockTillLoaded() { 674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch loaded_signal_.Wait(); 675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst BookmarkNode* BookmarkModel::GetNodeByID(const BookmarkNode* node, 678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int64 id) { 679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (node->id() == id) 680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return node; 681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0, child_count = node->GetChildCount(); i < child_count; ++i) { 683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const BookmarkNode* result = GetNodeByID(node->GetChild(i), id); 684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (result) 685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return result; 686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BookmarkModel::IsValidIndex(const BookmarkNode* parent, 691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index, 692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool allow_end) { 693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return (parent && parent->is_folder() && 694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (index >= 0 && (index < parent->GetChildCount() || 695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (allow_end && index == parent->GetChildCount())))); 696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 698c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBookmarkNode* BookmarkModel::CreateBookmarkNode() { 699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::StarredEntry entry; 700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.type = history::StarredEntry::BOOKMARK_BAR; 701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return CreateRootNodeFromStarredEntry(entry); 702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 704c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBookmarkNode* BookmarkModel::CreateOtherBookmarksNode() { 705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::StarredEntry entry; 706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.type = history::StarredEntry::OTHER; 707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return CreateRootNodeFromStarredEntry(entry); 708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 710c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBookmarkNode* BookmarkModel::CreateRootNodeFromStarredEntry( 711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const history::StarredEntry& entry) { 712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(entry.type == history::StarredEntry::BOOKMARK_BAR || 713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.type == history::StarredEntry::OTHER); 714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* node = new BookmarkNode(generate_next_node_id(), GURL()); 715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch node->Reset(entry); 7163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (entry.type == history::StarredEntry::BOOKMARK_BAR) { 7173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick node->SetTitle(l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_FOLDER_NAME)); 7183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } else { 7193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick node->SetTitle( 7203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OTHER_FOLDER_NAME)); 7213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return node; 723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::OnFavIconDataAvailable( 726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FaviconService::Handle handle, 727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool know_favicon, 728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_refptr<RefCountedMemory> data, 729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool expired, 730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL icon_url) { 731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkBitmap fav_icon; 732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* node = 733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch load_consumer_.GetClientData( 734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_->GetFaviconService(Profile::EXPLICIT_ACCESS), handle); 735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(node); 736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch node->set_favicon_load_handle(0); 737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (know_favicon && data.get() && data->size() && 738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::PNGCodec::Decode(data->front(), data->size(), &fav_icon)) { 739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch node->set_favicon(fav_icon); 740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FavIconLoaded(node); 741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::LoadFavIcon(BookmarkNode* node) { 745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (node->type() != BookmarkNode::URL) 746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(node->GetURL().is_valid()); 749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FaviconService* favicon_service = 750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_->GetFaviconService(Profile::EXPLICIT_ACCESS); 751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!favicon_service) 752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FaviconService::Handle handle = favicon_service->GetFaviconForURL( 754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch node->GetURL(), &load_consumer_, 755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewCallback(this, &BookmarkModel::OnFavIconDataAvailable)); 756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch load_consumer_.SetClientData(favicon_service, handle, node); 757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch node->set_favicon_load_handle(handle); 758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::CancelPendingFavIconLoadRequests(BookmarkNode* node) { 761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (node->favicon_load_handle()) { 762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FaviconService* favicon_service = 763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_->GetFaviconService(Profile::EXPLICIT_ACCESS); 764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (favicon_service) 765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch favicon_service->CancelRequest(node->favicon_load_handle()); 766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch node->set_favicon_load_handle(0); 767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::Observe(NotificationType type, 771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationSource& source, 772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationDetails& details) { 773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (type.value) { 774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case NotificationType::FAVICON_CHANGED: { 775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Prevent the observers from getting confused for multiple favicon loads. 776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Details<history::FavIconChangeDetails> favicon_details(details); 777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::set<GURL>::const_iterator i = favicon_details->urls.begin(); 778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != favicon_details->urls.end(); ++i) { 779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<const BookmarkNode*> nodes; 780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetNodesByURL(*i, &nodes); 781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < nodes.size(); ++i) { 782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Got an updated favicon, for a URL, do a new request. 783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* node = AsMutable(nodes[i]); 784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch node->InvalidateFavicon(); 785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CancelPendingFavIconLoadRequests(node); 786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, 787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNodeChanged(this, node)); 788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::PopulateNodesByURL(BookmarkNode* node) { 800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: this is called with url_lock_ already held. As such, this doesn't 801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // explicitly grab the lock. 802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (node->is_url()) 803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch nodes_ordered_by_url_set_.insert(node); 804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < node->GetChildCount(); ++i) 805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PopulateNodesByURL(node->GetChild(i)); 806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint64 BookmarkModel::generate_next_node_id() { 809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return next_node_id_++; 810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkModel::SetFileChanged() { 813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_changed_ = true; 814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 816c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBookmarkLoadDetails* BookmarkModel::CreateLoadDetails() { 817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* bb_node = CreateBookmarkNode(); 818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* other_folder_node = CreateOtherBookmarksNode(); 819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return new BookmarkLoadDetails( 820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bb_node, other_folder_node, new BookmarkIndex(profile()), next_node_id_); 821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 822