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