bookmark_utils.cc revision 201ade2fbba22bfb27ae029f4d23fca6ded109a0
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_utils.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/drag_drop_types.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/l10n_util.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/tree_node_iterator.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/basictypes.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_path.h"
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string16.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h"
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
16201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "chrome/browser/bookmarks/bookmark_node_data.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_model.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX)
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_list.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_window.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/query_parser.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/platform_util.h"
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/profile.h"
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/page_navigator.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_contents.h"
304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h"
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/notification_service.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/app_strings.h"
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/chromium_strings.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_util.h"
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/event.h"
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(TOOLKIT_VIEWS)
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/os_exchange_data.h"
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/drag_utils.h"
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/root_view.h"
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/widget.h"
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(TOOLKIT_GTK)
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/gtk/custom_drag.h"
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time;
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A PageNavigator implementation that creates a new Browser. This is used when
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// opening a url and there is no Browser open. The Browser is created the first
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// time the PageNavigator method is invoked.
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass NewBrowserPageNavigator : public PageNavigator {
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit NewBrowserPageNavigator(Profile* profile)
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : profile_(profile),
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        browser_(NULL) {}
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual ~NewBrowserPageNavigator() {
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (browser_)
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      browser_->window()->Show();
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser() const { return browser_; }
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OpenURL(const GURL& url,
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       const GURL& referrer,
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       WindowOpenDisposition disposition,
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       PageTransition::Type transition) {
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser_) {
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Profile* profile = (disposition == OFF_THE_RECORD) ?
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          profile_->GetOffTheRecordProfile() : profile_;
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      browser_ = Browser::Create(profile);
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Always open the first tab in the foreground.
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      disposition = NEW_FOREGROUND_TAB;
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser_->OpenURL(url, referrer, NEW_FOREGROUND_TAB, transition);
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Profile* profile_;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser_;
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(NewBrowserPageNavigator);
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid CloneBookmarkNodeImpl(BookmarkModel* model,
90201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                           const BookmarkNodeData::Element& element,
914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                           const BookmarkNode* parent,
924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                           int index_to_add_at) {
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (element.is_url) {
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    model->AddURL(parent, index_to_add_at, element.title, element.url);
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* new_folder = model->AddGroup(parent,
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                     index_to_add_at,
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                     element.title);
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (int i = 0; i < static_cast<int>(element.children.size()); ++i)
1004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      CloneBookmarkNodeImpl(model, element.children[i], new_folder, i);
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns the number of descendants of node that are of type url.
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint DescendantURLCount(const BookmarkNode* node) {
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int result = 0;
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < node->GetChildCount(); ++i) {
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* child = node->GetChild(i);
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (child->is_url())
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      result++;
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      result += DescendantURLCount(child);
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Implementation of OpenAll. Opens all nodes of type URL and recurses for
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// groups. |navigator| is the PageNavigator used to open URLs. After the first
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// url is opened |opened_url| is set to true and |navigator| is set to the
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// PageNavigator of the last active tab. This is done to handle a window
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// disposition of new window, in which case we want subsequent tabs to open in
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// that window.
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid OpenAllImpl(const BookmarkNode* node,
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 WindowOpenDisposition initial_disposition,
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 PageNavigator** navigator,
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 bool* opened_url) {
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (node->is_url()) {
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    WindowOpenDisposition disposition;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (*opened_url)
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      disposition = NEW_BACKGROUND_TAB;
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      disposition = initial_disposition;
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*navigator)->OpenURL(node->GetURL(), GURL(), disposition,
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          PageTransition::AUTO_BOOKMARK);
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!*opened_url) {
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *opened_url = true;
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We opened the first URL which may have opened a new window or clobbered
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // the current page, reset the navigator just to be sure.
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Browser* new_browser = BrowserList::GetLastActive();
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (new_browser) {
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        TabContents* current_tab = new_browser->GetSelectedTabContents();
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK(new_browser && current_tab);
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (new_browser && current_tab)
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          *navigator = current_tab;
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }  // else, new_browser == NULL, which happens during testing.
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Group, recurse through children.
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (int i = 0; i < node->GetChildCount(); ++i) {
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      OpenAllImpl(node->GetChild(i), initial_disposition, navigator,
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  opened_url);
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ShouldOpenAll(gfx::NativeWindow parent,
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   const std::vector<const BookmarkNode*>& nodes) {
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int descendant_count = 0;
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < nodes.size(); ++i)
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    descendant_count += DescendantURLCount(nodes[i]);
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (descendant_count < bookmark_utils::num_urls_before_prompting)
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string16 message = l10n_util::GetStringFUTF16(
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL,
1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      base::IntToString16(descendant_count));
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string16 title = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return platform_util::SimpleYesNoBox(parent, title, message);
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Comparison function that compares based on date modified of the two nodes.
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool MoreRecentlyModified(const BookmarkNode* n1, const BookmarkNode* n2) {
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return n1->date_group_modified() > n2->date_group_modified();
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns true if |text| contains each string in |words|. This is used when
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// searching for bookmarks.
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DoesBookmarkTextContainWords(const string16& text,
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const std::vector<string16>& words) {
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < words.size(); ++i) {
1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (text.find(words[i]) == string16::npos)
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns true if |node|s title or url contains the strings in |words|.
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// |languages| argument is user's accept-language setting to decode IDN.
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DoesBookmarkContainWords(const BookmarkNode* node,
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              const std::vector<string16>& words,
1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                              const std::string& languages) {
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DoesBookmarkTextContainWords(
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          l10n_util::ToLower(node->GetTitle()), words) ||
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DoesBookmarkTextContainWords(
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          l10n_util::ToLower(UTF8ToUTF16(node->GetURL().spec())), words) ||
1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      DoesBookmarkTextContainWords(l10n_util::ToLower(
1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          net::FormatUrl(node->GetURL(), languages, net::kFormatUrlOmitNothing,
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                         UnescapeRule::NORMAL, NULL, NULL, NULL)), words);
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace bookmark_utils {
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint num_urls_before_prompting = 15;
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint PreferredDropOperation(int source_operations, int operations) {
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int common_ops = (source_operations & operations);
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!common_ops)
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return 0;
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (DragDropTypes::DRAG_COPY & common_ops)
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DragDropTypes::DRAG_COPY;
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (DragDropTypes::DRAG_LINK & common_ops)
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DragDropTypes::DRAG_LINK;
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (DragDropTypes::DRAG_MOVE & common_ops)
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DragDropTypes::DRAG_MOVE;
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return DragDropTypes::DRAG_NONE;
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BookmarkDragOperation(const BookmarkNode* node) {
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (node->is_url()) {
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE |
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           DragDropTypes::DRAG_LINK;
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BookmarkDropOperation(Profile* profile,
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const views::DropTargetEvent& event,
231201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                          const BookmarkNodeData& data,
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const BookmarkNode* parent,
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          int index) {
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (data.IsFromProfile(profile) && data.size() > 1)
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Currently only accept one dragged node at a time.
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DragDropTypes::DRAG_NONE;
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!bookmark_utils::IsValidDropLocation(profile, data, parent, index))
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DragDropTypes::DRAG_NONE;
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (data.GetFirstNode(profile)) {
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // User is dragging from this profile: move.
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DragDropTypes::DRAG_MOVE;
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // User is dragging from another app, copy.
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return PreferredDropOperation(event.GetSourceOperations(),
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK);
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint PerformBookmarkDrop(Profile* profile,
251201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                        const BookmarkNodeData& data,
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        const BookmarkNode* parent_node,
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        int index) {
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkModel* model = profile->GetBookmarkModel();
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (data.IsFromProfile(profile)) {
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::vector<const BookmarkNode*> dragged_nodes =
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        data.GetNodes(profile);
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!dragged_nodes.empty()) {
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Drag from same profile. Move nodes.
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      for (size_t i = 0; i < dragged_nodes.size(); ++i) {
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        model->Move(dragged_nodes[i], parent_node, index);
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        index = parent_node->IndexOfChild(dragged_nodes[i]) + 1;
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return DragDropTypes::DRAG_MOVE;
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DragDropTypes::DRAG_NONE;
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Dropping a group from different profile. Always accept.
2694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  bookmark_utils::CloneBookmarkNode(model, data.elements, parent_node, index);
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return DragDropTypes::DRAG_COPY;
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool IsValidDropLocation(Profile* profile,
274201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                         const BookmarkNodeData& data,
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         const BookmarkNode* drop_parent,
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         int index) {
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!drop_parent->is_folder()) {
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!data.is_valid())
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (data.IsFromProfile(profile)) {
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<const BookmarkNode*> nodes = data.GetNodes(profile);
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < nodes.size(); ++i) {
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Don't allow the drop if the user is attempting to drop on one of the
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // nodes being dragged.
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const BookmarkNode* node = nodes[i];
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int node_index = (drop_parent == node->GetParent()) ?
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          drop_parent->IndexOfChild(nodes[i]) : -1;
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (node_index != -1 && (index == node_index || index == node_index + 1))
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // drop_parent can't accept a child that is an ancestor.
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (drop_parent->HasAncestor(node))
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // From the same profile, always accept.
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid CloneBookmarkNode(BookmarkModel* model,
307201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                       const std::vector<BookmarkNodeData::Element>& elements,
3084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                       const BookmarkNode* parent,
3094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                       int index_to_add_at) {
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!parent->is_folder() || !model) {
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < elements.size(); ++i)
3154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    CloneBookmarkNodeImpl(model, elements[i], parent, index_to_add_at + i);
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Bookmark dragging
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DragBookmarks(Profile* profile,
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   const std::vector<const BookmarkNode*>& nodes,
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   gfx::NativeView view) {
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!nodes.empty());
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(TOOLKIT_VIEWS)
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set up our OLE machinery
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  OSExchangeData data;
328201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  BookmarkNodeData drag_data(nodes);
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drag_data.Write(profile, &data);
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  views::RootView* root_view =
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      views::Widget::GetWidgetFromNativeView(view)->GetRootView();
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Allow nested message loop so we get DnD events as we drag this around.
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool was_nested = MessageLoop::current()->IsNested();
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop::current()->SetNestableTasksAllowed(true);
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  root_view->StartDragForViewFromMouseEvent(NULL, data,
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE |
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DragDropTypes::DRAG_LINK);
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop::current()->SetNestableTasksAllowed(was_nested);
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_MACOSX)
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Allow nested message loop so we get DnD events as we drag this around.
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool was_nested = MessageLoop::current()->IsNested();
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop::current()->SetNestableTasksAllowed(true);
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bookmark_pasteboard_helper_mac::StartDrag(profile, nodes, view);
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop::current()->SetNestableTasksAllowed(was_nested);
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(TOOLKIT_GTK)
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkDrag::BeginDrag(profile, nodes);
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid OpenAll(gfx::NativeWindow parent,
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             Profile* profile,
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             PageNavigator* navigator,
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             const std::vector<const BookmarkNode*>& nodes,
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             WindowOpenDisposition initial_disposition) {
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ShouldOpenAll(parent, nodes))
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NewBrowserPageNavigator navigator_impl(profile);
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!navigator) {
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Browser* browser =
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        BrowserList::FindBrowserWithType(profile, Browser::TYPE_NORMAL, false);
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser || !browser->GetSelectedTabContents()) {
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      navigator = &navigator_impl;
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (initial_disposition != NEW_WINDOW &&
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          initial_disposition != OFF_THE_RECORD) {
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        browser->window()->Activate();
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      navigator = browser->GetSelectedTabContents();
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool opened_url = false;
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < nodes.size(); ++i)
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OpenAllImpl(nodes[i], initial_disposition, &navigator, &opened_url);
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid OpenAll(gfx::NativeWindow parent,
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             Profile* profile,
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             PageNavigator* navigator,
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             const BookmarkNode* node,
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             WindowOpenDisposition initial_disposition) {
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<const BookmarkNode*> nodes;
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  nodes.push_back(node);
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  OpenAll(parent, profile, navigator, nodes, initial_disposition);
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CopyToClipboard(BookmarkModel* model,
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     const std::vector<const BookmarkNode*>& nodes,
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     bool remove_nodes) {
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (nodes.empty())
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
398201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  BookmarkNodeData(nodes).WriteToClipboard(NULL);
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (remove_nodes) {
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < nodes.size(); ++i) {
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      model->Remove(nodes[i]->GetParent(),
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    nodes[i]->GetParent()->IndexOfChild(nodes[i]));
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasteFromClipboard(BookmarkModel* model,
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        const BookmarkNode* parent,
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        int index) {
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!parent)
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
414201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  BookmarkNodeData bookmark_data;
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!bookmark_data.ReadFromClipboard())
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index == -1)
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    index = parent->GetChildCount();
4204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  bookmark_utils::CloneBookmarkNode(
4214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      model, bookmark_data.elements, parent, index);
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CanPasteFromClipboard(const BookmarkNode* node) {
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!node)
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
427201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return BookmarkNodeData::ClipboardContainsBookmarks();
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string GetNameForURL(const GURL& url) {
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (url.is_valid()) {
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return WideToUTF8(net::GetSuggestedFilename(
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        url, std::string(), std::string(), FilePath()).ToWStringHack());
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return l10n_util::GetStringUTF8(IDS_APP_UNTITLED_SHORTCUT_FILE_NAME);
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::vector<const BookmarkNode*> GetMostRecentlyModifiedGroups(
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BookmarkModel* model,
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    size_t max_count) {
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<const BookmarkNode*> nodes;
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TreeNodeIterator<const BookmarkNode> iterator(model->root_node());
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (iterator.has_next()) {
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* parent = iterator.Next();
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (parent->is_folder() && parent->date_group_modified() > base::Time()) {
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (max_count == 0) {
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        nodes.push_back(parent);
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::vector<const BookmarkNode*>::iterator i =
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            std::upper_bound(nodes.begin(), nodes.end(), parent,
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             &MoreRecentlyModified);
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (nodes.size() < max_count || i != nodes.end()) {
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          nodes.insert(i, parent);
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          while (nodes.size() > max_count)
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            nodes.pop_back();
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }  // else case, the root node, which we don't care about or imported nodes
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       // (which have a time of 0).
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (nodes.size() < max_count) {
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Add the bookmark bar and other nodes if there is space.
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (find(nodes.begin(), nodes.end(), model->GetBookmarkBarNode()) ==
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        nodes.end()) {
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      nodes.push_back(model->GetBookmarkBarNode());
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (nodes.size() < max_count &&
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        find(nodes.begin(), nodes.end(), model->other_node()) == nodes.end()) {
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      nodes.push_back(model->other_node());
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return nodes;
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetMostRecentlyAddedEntries(BookmarkModel* model,
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 size_t count,
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 std::vector<const BookmarkNode*>* nodes) {
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TreeNodeIterator<const BookmarkNode> iterator(model->root_node());
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (iterator.has_next()) {
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* node = iterator.Next();
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (node->is_url()) {
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::vector<const BookmarkNode*>::iterator insert_position =
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          std::upper_bound(nodes->begin(), nodes->end(), node,
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           &MoreRecentlyAdded);
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (nodes->size() < count || insert_position != nodes->end()) {
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        nodes->insert(insert_position, node);
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        while (nodes->size() > count)
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          nodes->pop_back();
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool MoreRecentlyAdded(const BookmarkNode* n1, const BookmarkNode* n2) {
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return n1->date_added() > n2->date_added();
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetBookmarksContainingText(BookmarkModel* model,
5023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                const string16& text,
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                size_t max_count,
5043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                const std::string& languages,
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                std::vector<const BookmarkNode*>* nodes) {
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<string16> words;
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  QueryParser parser;
5083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (words.empty())
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TreeNodeIterator<const BookmarkNode> iterator(model->root_node());
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (iterator.has_next()) {
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* node = iterator.Next();
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (node->is_url() && DoesBookmarkContainWords(node, words, languages)) {
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      nodes->push_back(node);
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (nodes->size() == max_count)
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return;
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DoesBookmarkContainText(const BookmarkNode* node,
5243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                             const string16& text,
5253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                             const std::string& languages) {
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<string16> words;
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  QueryParser parser;
5283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (words.empty())
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return (node->is_url() && DoesBookmarkContainWords(node, words, languages));
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const BookmarkNode* CreateNewNode(BookmarkModel* model,
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* parent, const BookmarkEditor::EditDetails& details,
5373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const string16& new_title, const GURL& new_url) {
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* node;
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (details.type == BookmarkEditor::EditDetails::NEW_URL) {
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    node = model->AddURL(parent, parent->GetChildCount(), new_title, new_url);
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    node = model->AddGroup(parent, parent->GetChildCount(), new_title);
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < details.urls.size(); ++i) {
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      model->AddURL(node, node->GetChildCount(), details.urls[i].second,
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    details.urls[i].first);
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    model->SetDateGroupModified(parent, Time::Now());
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return node;
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst BookmarkNode* ApplyEditsWithNoGroupChange(BookmarkModel* model,
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* parent, const BookmarkEditor::EditDetails& details,
5583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const string16& new_title, const GURL& new_url) {
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (details.type == BookmarkEditor::EditDetails::NEW_URL ||
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return CreateNewNode(model, parent, details, new_title, new_url);
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* node = details.existing_node;
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(node);
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (node->is_url())
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    model->SetURL(node, new_url);
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model->SetTitle(node, new_title);
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return node;
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst BookmarkNode* ApplyEditsWithPossibleGroupChange(BookmarkModel* model,
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* new_parent, const BookmarkEditor::EditDetails& details,
5763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const string16& new_title, const GURL& new_url) {
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (details.type == BookmarkEditor::EditDetails::NEW_URL ||
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return CreateNewNode(model, new_parent, details, new_title, new_url);
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* node = details.existing_node;
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(node);
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (new_parent != node->GetParent())
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    model->Move(node, new_parent, new_parent->GetChildCount());
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (node->is_url())
588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    model->SetURL(node, new_url);
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model->SetTitle(node, new_title);
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return node;
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Formerly in BookmarkBarView
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ToggleWhenVisible(Profile* profile) {
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PrefService* prefs = profile->GetPrefs();
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const bool always_show = !prefs->GetBoolean(prefs::kShowBookmarkBar);
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The user changed when the bookmark bar is shown, update the preferences.
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs->SetBoolean(prefs::kShowBookmarkBar, always_show);
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs->ScheduleSavePersistentPrefs();
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // And notify the notification service.
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Source<Profile> source(profile);
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationService::current()->Notify(
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      source,
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationService::NoDetails());
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid RegisterUserPrefs(PrefService* prefs) {
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs->RegisterBooleanPref(prefs::kShowBookmarkBar, false);
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetURLAndTitleToBookmark(TabContents* tab_contents,
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              GURL* url,
6173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                              string16* title) {
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *url = tab_contents->GetURL();
6193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  *title = tab_contents->GetTitle();
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetURLsForOpenTabs(Browser* browser,
6233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::vector<std::pair<GURL, string16> >* urls) {
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < browser->tab_count(); ++i) {
6253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::pair<GURL, string16> entry;
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GetURLAndTitleToBookmark(browser->GetTabContentsAt(i), &(entry.first),
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             &(entry.second));
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    urls->push_back(entry);
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst BookmarkNode* GetParentForNewNodes(
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* parent,
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::vector<const BookmarkNode*>& selection,
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int* index) {
636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* real_parent = parent;
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (selection.size() == 1 && selection[0]->is_folder())
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    real_parent = selection[0];
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index) {
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (selection.size() == 1 && selection[0]->is_url()) {
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *index = real_parent->IndexOfChild(selection[0]) + 1;
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (*index == 0) {
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Node doesn't exist in parent, add to end.
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED();
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        *index = real_parent->GetChildCount();
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *index = real_parent->GetChildCount();
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return real_parent;
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
657201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochbool NodeHasURLs(const BookmarkNode* node) {
658201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK(node);
659201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
660201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (node->is_url())
661201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return true;
662201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
663201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  for (int i = 0; i < node->GetChildCount(); ++i) {
664201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (NodeHasURLs(node->GetChild(i)))
665201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      return true;
666201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
667201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return false;
668201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
669201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace bookmark_utils
671