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