15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_model.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <functional>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/i18n/string_compare.h"
135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/logging.h"
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/macros.h"
155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/strings/string_util.h"
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_expanded_state_tracker.h"
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_index.h"
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_match.h"
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_model_observer.h"
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_node_data.h"
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_storage.h"
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_utils.h"
230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/favicon_base/favicon_types.h"
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "grit/components_strings.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/favicon_size.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing bookmarks::BookmarkClient;
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)using bookmarks::BookmarkExpandedStateTracker;
3146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)using bookmarks::BookmarkIndex;
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using bookmarks::BookmarkLoadDetails;
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)using bookmarks::BookmarkMatch;
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)using bookmarks::BookmarkNodeData;
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using bookmarks::BookmarkStorage;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper to get a mutable bookmark node.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkNode* AsMutable(const BookmarkNode* node) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return const_cast<BookmarkNode*>(node);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Helper to get a mutable permanent bookmark node.
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)BookmarkPermanentNode* AsMutable(const BookmarkPermanentNode* node) {
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return const_cast<BookmarkPermanentNode*>(node);
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Comparator used when sorting permanent nodes. Nodes that are initially
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// visible are sorted before nodes that are initially hidden.
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class VisibilityComparator
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : public std::binary_function<const BookmarkPermanentNode*,
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                  const BookmarkPermanentNode*,
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                  bool> {
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) public:
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  explicit VisibilityComparator(BookmarkClient* client) : client_(client) {}
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Returns true if |n1| preceeds |n2|.
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool operator()(const BookmarkPermanentNode* n1,
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                  const BookmarkPermanentNode* n2) {
6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    bool n1_visible = client_->IsPermanentNodeVisible(n1);
6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    bool n2_visible = client_->IsPermanentNodeVisible(n2);
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return n1_visible != n2_visible && n1_visible;
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private:
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BookmarkClient* client_;
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Comparator used when sorting bookmarks. Folders are sorted first, then
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// bookmarks.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SortComparator : public std::binary_function<const BookmarkNode*,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   const BookmarkNode*,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   bool> {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit SortComparator(icu::Collator* collator) : collator_(collator) {}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if |n1| preceeds |n2|.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (n1->type() == n2->type()) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Types are the same, compare the names.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!collator_)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return n1->GetTitle() < n2->GetTitle();
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return base::i18n::CompareString16WithCollator(
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          collator_, n1->GetTitle(), n2->GetTitle()) == UCOL_LESS;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Types differ, sort such that folders come first.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return n1->is_folder();
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icu::Collator* collator_;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BookmarkModel --------------------------------------------------------------
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciBookmarkModel::BookmarkModel(BookmarkClient* client)
1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : client_(client),
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      loaded_(false),
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      root_(GURL()),
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark_bar_node_(NULL),
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      other_node_(NULL),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mobile_node_(NULL),
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_node_id_(1),
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      observers_(ObserverList<BookmarkModelObserver>::NOTIFY_EXISTING_ONLY),
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      loaded_signal_(true, false),
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extensive_changes_(0) {
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(client_);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkModel::~BookmarkModel() {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    BookmarkModelBeingDeleted(this));
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (store_.get()) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The store maintains a reference back to us. We need to tell it we're gone
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // so that it doesn't try and invoke a method back on us again.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    store_->BookmarkModelDeleted();
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::Shutdown() {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (loaded_)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See comment in HistoryService::ShutdownOnUIThread where this is invoked for
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // details. It is also called when the BookmarkModel is deleted.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  loaded_signal_.Signal();
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void BookmarkModel::Load(
1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    PrefService* pref_service,
1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& accept_languages,
1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const base::FilePath& profile_path,
1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
1385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (store_.get()) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the store is non-null, it means Load was already invoked. Load should
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // only be invoked once.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  expanded_state_tracker_.reset(
1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      new BookmarkExpandedStateTracker(this, pref_service));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Load the bookmarks. BookmarkStorage notifies us when done.
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  store_ .reset(new BookmarkStorage(this, profile_path, io_task_runner.get()));
1515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  store_->LoadBookmarks(CreateLoadDetails(accept_languages), ui_task_runner);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* BookmarkModel::GetParentForNewNodes() {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<const BookmarkNode*> nodes =
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      bookmarks::GetMostRecentlyModifiedUserFolders(this, 1);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!nodes.empty());  // This list is always padded with default folders.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return nodes[0];
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::AddObserver(BookmarkModelObserver* observer) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.AddObserver(observer);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::RemoveObserver(BookmarkModelObserver* observer) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.RemoveObserver(observer);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::BeginExtensiveChanges() {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (++extensive_changes_ == 1) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      ExtensiveBookmarkChangesBeginning(this));
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::EndExtensiveChanges() {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  --extensive_changes_;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(extensive_changes_, 0);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (extensive_changes_ == 0) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      ExtensiveBookmarkChangesEnded(this));
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BookmarkModel::BeginGroupedChanges() {
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    GroupedBookmarkChangesBeginning(this));
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BookmarkModel::EndGroupedChanges() {
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    GroupedBookmarkChangesEnded(this));
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::Remove(const BookmarkNode* parent, int index) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!loaded_ || !IsValidIndex(parent, index, false) || is_root_node(parent)) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RemoveAndDeleteNode(AsMutable(parent->GetChild(index)));
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void BookmarkModel::RemoveAllUserBookmarks() {
2047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  std::set<GURL> removed_urls;
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedVector<BookmarkNode> removed_nodes;
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    OnWillRemoveAllUserBookmarks(this));
209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  BeginExtensiveChanges();
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Skip deleting permanent nodes. Permanent bookmark nodes are the root and
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // its immediate children. For removing all non permanent nodes just remove
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // all children of non-root permanent nodes.
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  {
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::AutoLock url_lock(url_lock_);
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (int i = 0; i < root_.child_count(); ++i) {
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      BookmarkNode* permanent_node = root_.GetChild(i);
21846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
21946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (!client_->CanBeEditedByUser(permanent_node))
22046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        continue;
22146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      for (int j = permanent_node->child_count() - 1; j >= 0; --j) {
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        BookmarkNode* child_node = permanent_node->GetChild(j);
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        removed_nodes.push_back(child_node);
2257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        RemoveNodeAndGetRemovedUrls(child_node, &removed_urls);
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EndExtensiveChanges();
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (store_.get())
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    store_->ScheduleSave();
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    BookmarkAllUserNodesRemoved(this, removed_urls));
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::Move(const BookmarkNode* node,
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const BookmarkNode* new_parent,
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         int index) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_root_node(new_parent) || is_permanent_node(node)) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (new_parent->HasAncestor(node)) {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Can't make an ancestor of the node be a child of the node.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* old_parent = node->parent();
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int old_index = old_parent->GetIndexOf(node);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_parent == new_parent &&
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (index == old_index || index == old_index + 1)) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Node is already in this position, nothing to do.
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetDateFolderModified(new_parent, Time::Now());
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_parent == new_parent && index > old_index)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index--;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkNode* mutable_new_parent = AsMutable(new_parent);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mutable_new_parent->Add(AsMutable(node), index);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (store_.get())
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    store_->ScheduleSave();
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    BookmarkNodeMoved(this, old_parent, old_index,
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      new_parent, index));
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::Copy(const BookmarkNode* node,
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const BookmarkNode* new_parent,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         int index) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_root_node(new_parent) || is_permanent_node(node)) {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (new_parent->HasAncestor(node)) {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Can't make an ancestor of the node be a child of the node.
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetDateFolderModified(new_parent, Time::Now());
29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  BookmarkNodeData drag_data(node);
29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<BookmarkNodeData::Element> elements(drag_data.elements);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CloneBookmarkNode will use BookmarkModel methods to do the job, so we
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // don't need to send notifications here.
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bookmarks::CloneBookmarkNode(this, elements, new_parent, index, true);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (store_.get())
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    store_->ScheduleSave();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const gfx::Image& BookmarkModel::GetFavicon(const BookmarkNode* node) {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(node);
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->favicon_state() == BookmarkNode::INVALID_FAVICON) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BookmarkNode* mutable_node = AsMutable(node);
306010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    LoadFavicon(
307010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        mutable_node,
308010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        client_->PreferTouchIcon() ?
309010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            favicon_base::TOUCH_ICON :
310010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            favicon_base::FAVICON);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return node->favicon();
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)favicon_base::IconType BookmarkModel::GetFaviconType(const BookmarkNode* node) {
316010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(node);
317010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return node->favicon_type();
318010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
319010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
3205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BookmarkModel::SetTitle(const BookmarkNode* node,
3215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                             const base::string16& title) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->GetTitle() == title)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (is_permanent_node(node) && !client_->CanSetPermanentNodeTitle(node)) {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
335868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    OnWillChangeBookmarkNode(this, node));
336868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The title index doesn't support changing the title, instead we remove then
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // add it back.
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  index_->Remove(node);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AsMutable(node)->SetTitle(title);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  index_->Add(node);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (store_.get())
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    store_->ScheduleSave();
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    BookmarkNodeChanged(this, node));
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We cannot change the URL of a folder.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->is_folder()) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->url() == url)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkNode* mutable_node = AsMutable(node);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mutable_node->InvalidateFavicon();
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelPendingFaviconLoadRequests(mutable_node);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
370868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    OnWillChangeBookmarkNode(this, node));
371868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock url_lock(url_lock_);
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RemoveNodeFromURLSet(mutable_node);
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mutable_node->set_url(url);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nodes_ordered_by_url_set_.insert(mutable_node);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (store_.get())
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    store_->ScheduleSave();
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    BookmarkNodeChanged(this, node));
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::SetNodeMetaInfo(const BookmarkNode* node,
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const std::string& key,
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const std::string& value) {
389f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string old_value;
390f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (node->GetMetaInfo(key, &old_value) && old_value == value)
391f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
392f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
3948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                    OnWillChangeBookmarkMetaInfo(this, node));
3958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AsMutable(node)->SetMetaInfo(key, value) && store_.get())
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    store_->ScheduleSave();
3988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
3998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
4008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                    BookmarkMetaInfoChanged(this, node));
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
403a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BookmarkModel::SetNodeMetaInfoMap(
404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const BookmarkNode* node,
405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const BookmarkNode::MetaInfoMap& meta_info_map) {
406a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const BookmarkNode::MetaInfoMap* old_meta_info_map = node->GetMetaInfoMap();
407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if ((!old_meta_info_map && meta_info_map.empty()) ||
408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      (old_meta_info_map && meta_info_map == *old_meta_info_map))
409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
410a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
412a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    OnWillChangeBookmarkMetaInfo(this, node));
413a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
414a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  AsMutable(node)->SetMetaInfoMap(meta_info_map);
415a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (store_.get())
416a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    store_->ScheduleSave();
417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    BookmarkMetaInfoChanged(this, node));
420a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
421a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::DeleteNodeMetaInfo(const BookmarkNode* node,
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const std::string& key) {
424f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const BookmarkNode::MetaInfoMap* meta_info_map = node->GetMetaInfoMap();
425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!meta_info_map || meta_info_map->find(key) == meta_info_map->end())
426f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
4298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                    OnWillChangeBookmarkMetaInfo(this, node));
4308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AsMutable(node)->DeleteMetaInfo(key) && store_.get())
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    store_->ScheduleSave();
4338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
4348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
4358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                    BookmarkMetaInfoChanged(this, node));
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
438f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void BookmarkModel::SetNodeSyncTransactionVersion(
439f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const BookmarkNode* node,
440f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int64 sync_transaction_version) {
44146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(client_->CanSyncNode(node));
44246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
443f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (sync_transaction_version == node->sync_transaction_version())
444f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
445f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
446f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  AsMutable(node)->set_sync_transaction_version(sync_transaction_version);
447f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (store_.get())
448f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    store_->ScheduleSave();
449f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
450f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BookmarkModel::OnFaviconChanged(const std::set<GURL>& urls) {
4525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Ignore events if |Load| has not been called yet.
4535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!store_)
4545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
4555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
4565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Prevent the observers from getting confused for multiple favicon loads.
4575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
4585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    std::vector<const BookmarkNode*> nodes;
4595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    GetNodesByURL(*i, &nodes);
4605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    for (size_t i = 0; i < nodes.size(); ++i) {
4615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      // Got an updated favicon, for a URL, do a new request.
4625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      BookmarkNode* node = AsMutable(nodes[i]);
4635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      node->InvalidateFavicon();
4645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      CancelPendingFaviconLoadRequests(node);
4655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      FOR_EACH_OBSERVER(BookmarkModelObserver,
4665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                        observers_,
4675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                        BookmarkNodeFaviconChanged(this, node));
4685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
4695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
4705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
4715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::SetDateAdded(const BookmarkNode* node,
473cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                 Time date_added) {
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node) {
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->date_added() == date_added)
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_permanent_node(node)) {
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AsMutable(node)->set_date_added(date_added);
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Syncing might result in dates newer than the folder's last modified date.
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (date_added > node->parent()->date_folder_modified()) {
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Will trigger store_->ScheduleSave().
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetDateFolderModified(node->parent(), date_added);
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (store_.get()) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    store_->ScheduleSave();
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::GetNodesByURL(const GURL& url,
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  std::vector<const BookmarkNode*>* nodes) {
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock url_lock(url_lock_);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkNode tmp_node(url);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node);
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (i != nodes_ordered_by_url_set_.end() && (*i)->url() == url) {
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nodes->push_back(*i);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++i;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL(
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<const BookmarkNode*> nodes;
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetNodesByURL(url, &nodes);
513116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::sort(nodes.begin(), nodes.end(), &bookmarks::MoreRecentlyAdded);
51446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
51546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Look for the first node that the user can edit.
51646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (size_t i = 0; i < nodes.size(); ++i) {
51746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (client_->CanBeEditedByUser(nodes[i]))
51846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return nodes[i];
51946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
52046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
52146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return NULL;
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkModel::HasBookmarks() {
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock url_lock(url_lock_);
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !nodes_ordered_by_url_set_.empty();
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkModel::IsBookmarked(const GURL& url) {
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock url_lock(url_lock_);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return IsBookmarkedNoLock(url);
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::GetBookmarks(
53546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    std::vector<BookmarkModel::URLAndTitle>* bookmarks) {
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock url_lock(url_lock_);
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const GURL* last_url = NULL;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin();
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != nodes_ordered_by_url_set_.end(); ++i) {
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL* url = &((*i)->url());
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only add unique URLs.
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!last_url || *url != *last_url) {
54346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      BookmarkModel::URLAndTitle bookmark;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark.url = *url;
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark.title = (*i)->GetTitle();
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmarks->push_back(bookmark);
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_url = url;
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::BlockTillLoaded() {
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  loaded_signal_.Wait();
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* BookmarkModel::AddFolder(const BookmarkNode* parent,
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             int index,
558a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                             const base::string16& title) {
5590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return AddFolderWithMetaInfo(parent, index, title, NULL);
5600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
5610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst BookmarkNode* BookmarkModel::AddFolderWithMetaInfo(
5620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const BookmarkNode* parent,
5630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int index,
5640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const base::string16& title,
5650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const BookmarkNode::MetaInfoMap* meta_info) {
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!loaded_ || is_root_node(parent) || !IsValidIndex(parent, index, true)) {
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Can't add to the root.
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkNode* new_node = new BookmarkNode(generate_next_node_id(), GURL());
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_node->set_date_folder_modified(Time::Now());
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Folders shouldn't have line breaks in their titles.
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_node->SetTitle(title);
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_node->set_type(BookmarkNode::FOLDER);
5770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (meta_info)
5780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    new_node->SetMetaInfoMap(*meta_info);
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return AddNode(AsMutable(parent), index, new_node);
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent,
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          int index,
585a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                          const base::string16& title,
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          const GURL& url) {
5870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return AddURLWithCreationTimeAndMetaInfo(
5880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      parent,
5890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      index,
5900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::CollapseWhitespace(title, false),
5910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      url,
5920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      Time::Now(),
5930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      NULL);
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst BookmarkNode* BookmarkModel::AddURLWithCreationTimeAndMetaInfo(
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* parent,
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index,
599a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& title,
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
6010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const Time& creation_time,
6020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const BookmarkNode::MetaInfoMap* meta_info) {
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!loaded_ || !url.is_valid() || is_root_node(parent) ||
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !IsValidIndex(parent, index, true)) {
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Syncing may result in dates newer than the last modified date.
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (creation_time > parent->date_folder_modified())
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetDateFolderModified(parent, creation_time);
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkNode* new_node = new BookmarkNode(generate_next_node_id(), url);
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_node->SetTitle(title);
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_node->set_date_added(creation_time);
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_node->set_type(BookmarkNode::URL);
6170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (meta_info)
6180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    new_node->SetMetaInfoMap(*meta_info);
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only hold the lock for the duration of the insert.
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock url_lock(url_lock_);
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nodes_ordered_by_url_set_.insert(new_node);
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return AddNode(AsMutable(parent), index, new_node);
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::SortChildren(const BookmarkNode* parent) {
63046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(client_->CanBeEditedByUser(parent));
63146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!parent || !parent->is_folder() || is_root_node(parent) ||
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent->child_count() <= 1) {
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
637868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
638868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    OnWillReorderBookmarkNode(this, parent));
639868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UErrorCode error = U_ZERO_ERROR;
641c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (U_FAILURE(error))
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    collator.reset(NULL);
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkNode* mutable_parent = AsMutable(parent);
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(mutable_parent->children().begin(),
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mutable_parent->children().end(),
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SortComparator(collator.get()));
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (store_.get())
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    store_->ScheduleSave();
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    BookmarkNodeChildrenReordered(this, parent));
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
656868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void BookmarkModel::ReorderChildren(
657868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const BookmarkNode* parent,
6582385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    const std::vector<const BookmarkNode*>& ordered_nodes) {
65946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(client_->CanBeEditedByUser(parent));
66046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
661868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Ensure that all children in |parent| are in |ordered_nodes|.
662868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(static_cast<size_t>(parent->child_count()), ordered_nodes.size());
663868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (size_t i = 0; i < ordered_nodes.size(); ++i)
664868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_EQ(parent, ordered_nodes[i]->parent());
665868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
666868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
667868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    OnWillReorderBookmarkNode(this, parent));
668868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
6692385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  AsMutable(parent)->SetChildren(
6702385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      *(reinterpret_cast<const std::vector<BookmarkNode*>*>(&ordered_nodes)));
671868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
672868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (store_.get())
673868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    store_->ScheduleSave();
674868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
675868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
676868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    BookmarkNodeChildrenReordered(this, parent));
677868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
678868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::SetDateFolderModified(const BookmarkNode* parent,
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          const Time time) {
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(parent);
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AsMutable(parent)->set_date_folder_modified(time);
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (store_.get())
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    store_->ScheduleSave();
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::ResetDateFolderModified(const BookmarkNode* node) {
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetDateFolderModified(node, Time());
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid BookmarkModel::GetBookmarksMatching(
693a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& text,
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t max_count,
6950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<BookmarkMatch>* matches) {
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!loaded_)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  index_->GetBookmarksMatching(text, max_count, matches);
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::ClearStore() {
703116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  store_.reset();
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::SetPermanentNodeVisible(BookmarkNode::Type type,
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            bool value) {
70846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  BookmarkPermanentNode* node = AsMutable(PermanentNode(type));
70946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  node->set_visible(value || client_->IsPermanentNodeVisible(node));
710cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
711cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
712cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const BookmarkPermanentNode* BookmarkModel::PermanentNode(
713cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    BookmarkNode::Type type) {
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(loaded_);
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BookmarkNode::BOOKMARK_BAR:
717cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return bookmark_bar_node_;
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BookmarkNode::OTHER_NODE:
719cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return other_node_;
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BookmarkNode::MOBILE:
721cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return mobile_node_;
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
724cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return NULL;
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkModel::IsBookmarkedNoLock(const GURL& url) {
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkNode tmp_node(url);
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (nodes_ordered_by_url_set_.find(&tmp_node) !=
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          nodes_ordered_by_url_set_.end());
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::RemoveNode(BookmarkNode* node,
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               std::set<GURL>* removed_urls) {
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!loaded_ || !node || is_permanent_node(node)) {
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
741c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  url_lock_.AssertAcquired();
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->is_url()) {
7435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RemoveNodeFromURLSet(node);
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    removed_urls->insert(node->url());
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index_->Remove(node);
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelPendingFaviconLoadRequests(node);
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Recurse through children.
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = node->child_count() - 1; i >= 0; --i)
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RemoveNode(node->GetChild(i), removed_urls);
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BookmarkModel::DoneLoading(scoped_ptr<BookmarkLoadDetails> details) {
7565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(details);
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (loaded_) {
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should only ever be loaded once.
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  next_node_id_ = details->max_id();
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (details->computed_checksum() != details->stored_checksum() ||
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      details->ids_reassigned()) {
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If bookmarks file changed externally, the IDs may have changed
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // externally. In that case, the decoder may have reassigned IDs to make
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // them unique. So when the file has changed externally, we should save the
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // bookmarks file to persist new IDs.
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (store_.get())
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      store_->ScheduleSave();
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_bar_node_ = details->release_bb_node();
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other_node_ = details->release_other_folder_node();
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mobile_node_ = details->release_mobile_folder_node();
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  index_.reset(details->release_index());
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
77846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Get any extra nodes and take ownership of them at the |root_|.
77946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::vector<BookmarkPermanentNode*> extra_nodes;
78046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  details->release_extra_nodes(&extra_nodes);
78146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // WARNING: order is important here, various places assume the order is
783cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // constant (but can vary between embedders with the initial visibility
784cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // of permanent nodes).
78546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::vector<BookmarkPermanentNode*> root_children;
78646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  root_children.push_back(bookmark_bar_node_);
78746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  root_children.push_back(other_node_);
78846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  root_children.push_back(mobile_node_);
78946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (size_t i = 0; i < extra_nodes.size(); ++i)
79046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    root_children.push_back(extra_nodes[i]);
79146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::stable_sort(root_children.begin(),
79246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                   root_children.end(),
793cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   VisibilityComparator(client_));
79446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (size_t i = 0; i < root_children.size(); ++i)
795cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    root_.Add(root_children[i], static_cast<int>(i));
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
797f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  root_.SetMetaInfoMap(details->model_meta_info_map());
798f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  root_.set_sync_transaction_version(details->model_sync_transaction_version());
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock url_lock(url_lock_);
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update nodes_ordered_by_url_set_ from the nodes.
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PopulateNodesByURL(&root_);
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  loaded_ = true;
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  loaded_signal_.Signal();
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notify our direct observers.
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
8125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    BookmarkModelLoaded(this, details->ids_reassigned()));
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::RemoveAndDeleteNode(BookmarkNode* delete_me) {
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<BookmarkNode> node(delete_me);
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
818c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const BookmarkNode* parent = node->parent();
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(parent);
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index = parent->GetIndexOf(node.get());
821c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
822868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
823868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    OnWillRemoveBookmarks(this, parent, index, node.get()));
824868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
8257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  std::set<GURL> removed_urls;
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock url_lock(url_lock_);
8287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    RemoveNodeAndGetRemovedUrls(node.get(), &removed_urls);
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (store_.get())
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    store_->ScheduleSave();
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
834010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  FOR_EACH_OBSERVER(
835010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      BookmarkModelObserver,
836010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      observers_,
837010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls));
838c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
839c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
8405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BookmarkModel::RemoveNodeFromURLSet(BookmarkNode* node) {
8415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // NOTE: this is called in such a way that url_lock_ is already held. As
8425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // such, this doesn't explicitly grab the lock.
8435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node);
8445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(i != nodes_ordered_by_url_set_.end());
8455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // i points to the first node with the URL, advance until we find the
8465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // node we're removing.
8475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (*i != node)
8485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ++i;
8495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  nodes_ordered_by_url_set_.erase(i);
8505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
852c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void BookmarkModel::RemoveNodeAndGetRemovedUrls(BookmarkNode* node,
853c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                std::set<GURL>* removed_urls) {
854c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // NOTE: this method should be always called with |url_lock_| held.
855c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // This method does not explicitly acquires a lock.
856c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  url_lock_.AssertAcquired();
857c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(removed_urls);
858c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  BookmarkNode* parent = AsMutable(node->parent());
859c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(parent);
860c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  parent->Remove(node);
861c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RemoveNode(node, removed_urls);
862c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // RemoveNode adds an entry to removed_urls for each node of type URL. As we
863c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // allow duplicates we need to remove any entries that are still bookmarked.
864c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (std::set<GURL>::iterator i = removed_urls->begin();
865c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       i != removed_urls->end();) {
866c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (IsBookmarkedNoLock(*i)) {
867c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // When we erase the iterator pointing at the erasee is
868c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // invalidated, so using i++ here within the "erase" call is
869c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // important as it advances the iterator before passing the
870c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // old value through to erase.
871c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      removed_urls->erase(i++);
872c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
873c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ++i;
874c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
875c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
876c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     int index,
8802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     BookmarkNode* node) {
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parent->Add(node, index);
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (store_.get())
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    store_->ScheduleSave();
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    BookmarkNodeAdded(this, parent, index));
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  index_->Add(node);
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return node;
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkModel::IsValidIndex(const BookmarkNode* parent,
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 int index,
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 bool allow_end) {
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (parent && parent->is_folder() &&
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (index >= 0 && (index < parent->child_count() ||
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          (allow_end && index == parent->child_count()))));
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkPermanentNode* BookmarkModel::CreatePermanentNode(
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BookmarkNode::Type type) {
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(type == BookmarkNode::BOOKMARK_BAR ||
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         type == BookmarkNode::OTHER_NODE ||
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         type == BookmarkNode::MOBILE);
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkPermanentNode* node =
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new BookmarkPermanentNode(generate_next_node_id());
90946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  node->set_type(type);
91046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  node->set_visible(client_->IsPermanentNodeVisible(node));
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int title_id;
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BookmarkNode::BOOKMARK_BAR:
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BookmarkNode::OTHER_NODE:
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      title_id = IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME;
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case BookmarkNode::MOBILE:
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      title_id = IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME;
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  node->SetTitle(l10n_util::GetStringUTF16(title_id));
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return node;
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::OnFaviconDataAvailable(
9332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BookmarkNode* node,
934010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    favicon_base::IconType icon_type,
9350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const favicon_base::FaviconImageResult& image_result) {
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(node);
9375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  node->set_favicon_state(BookmarkNode::LOADED_FAVICON);
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!image_result.image.IsEmpty()) {
940010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    node->set_favicon_type(icon_type);
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    node->set_favicon(image_result.image);
9422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    node->set_icon_url(image_result.icon_url);
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FaviconLoaded(node);
944010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  } else if (icon_type == favicon_base::TOUCH_ICON) {
945010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Couldn't load the touch icon, fallback to the regular favicon.
946010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK(client_->PreferTouchIcon());
947010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    LoadFavicon(node, favicon_base::FAVICON);
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
951010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void BookmarkModel::LoadFavicon(
952010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    BookmarkNode* node,
953010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    favicon_base::IconType icon_type) {
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->is_folder())
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(node->url().is_valid());
958010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  node->set_favicon_state(BookmarkNode::LOADING_FAVICON);
959116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::CancelableTaskTracker::TaskId taskId =
960116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      client_->GetFaviconImageForPageURL(
961116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          node->url(),
962116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          icon_type,
963116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          base::Bind(
964116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              &BookmarkModel::OnFaviconDataAvailable,
965116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              base::Unretained(this),
966116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              node,
967116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              icon_type),
968116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          &cancelable_task_tracker_);
9695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (taskId != base::CancelableTaskTracker::kBadTaskId)
9705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    node->set_favicon_load_task_id(taskId);
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::FaviconLoaded(const BookmarkNode* node) {
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    BookmarkNodeFaviconChanged(this, node));
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) {
9795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) {
9802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    cancelable_task_tracker_.TryCancel(node->favicon_load_task_id());
9815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId);
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkModel::PopulateNodesByURL(BookmarkNode* node) {
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: this is called with url_lock_ already held. As such, this doesn't
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // explicitly grab the lock.
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->is_url())
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nodes_ordered_by_url_set_.insert(node);
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < node->child_count(); ++i)
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PopulateNodesByURL(node->GetChild(i));
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 BookmarkModel::generate_next_node_id() {
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return next_node_id_++;
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuscoped_ptr<BookmarkLoadDetails> BookmarkModel::CreateLoadDetails(
9995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& accept_languages) {
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkPermanentNode* bb_node =
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CreatePermanentNode(BookmarkNode::BOOKMARK_BAR);
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkPermanentNode* other_node =
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CreatePermanentNode(BookmarkNode::OTHER_NODE);
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkPermanentNode* mobile_node =
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CreatePermanentNode(BookmarkNode::MOBILE);
10065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return scoped_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails(
10075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      bb_node,
10085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      other_node,
10095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      mobile_node,
101046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      client_->GetLoadExtraNodesCallback(),
10111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new BookmarkIndex(client_, accept_languages),
10125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      next_node_id_));
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1014