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