172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/stl_util-inl.h"
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_model.h"
10dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/bookmarks/bookmark_node_data.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_utils.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/metrics/user_metrics.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/prefs/pref_service.h"
1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser.h"
16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/event_utils.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/pref_names.h"
19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/page_navigator.h"
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/page_transition_types.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/app_resources.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h"
2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/dragdrop/os_exchange_data.h"
2572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/button/menu_button.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing views::MenuItemView;
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Max width of a menu. There does not appear to be an OS value for this, yet
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// both IE and FF restrict the max width of a menu.
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic const int kMaxMenuWidth = 400;
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBookmarkMenuController::BookmarkMenuController(Browser* browser,
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               Profile* profile,
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               PageNavigator* navigator,
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               gfx::NativeWindow parent,
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               const BookmarkNode* node,
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               int start_child_index)
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : browser_(browser),
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      profile_(profile),
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      page_navigator_(navigator),
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      parent_(parent),
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      node_(node),
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      menu_(NULL),
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      observer_(NULL),
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      for_drop_(false),
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bookmark_bar_(NULL),
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      next_menu_id_(1) {
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  menu_ = CreateMenu(node, start_child_index);
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkMenuController::RunMenuAt(BookmarkBarView* bookmark_bar,
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       bool for_drop) {
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bookmark_bar_ = bookmark_bar;
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  views::MenuButton* menu_button = bookmark_bar_->GetMenuButtonForNode(node_);
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(menu_button);
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MenuItemView::AnchorPosition anchor;
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int start_index;
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bookmark_bar_->GetAnchorPositionAndStartIndexForButton(
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      menu_button, &anchor, &start_index);
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RunMenuAt(menu_button, anchor, for_drop);
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkMenuController::RunMenuAt(
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    views::MenuButton* button,
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MenuItemView::AnchorPosition position,
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool for_drop) {
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Point screen_loc;
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  views::View::ConvertPointToScreen(button, &screen_loc);
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Subtract 1 from the height to make the popup flush with the button border.
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect bounds(screen_loc.x(), screen_loc.y(), button->width(),
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   button->height() - 1);
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for_drop_ = for_drop;
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_->GetBookmarkModel()->AddObserver(this);
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The constructor creates the initial menu and that is all we should have
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // at this point.
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(node_to_menu_map_.size() == 1);
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (for_drop) {
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    menu_->RunMenuForDropAt(parent_, bounds, position);
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    menu_->RunMenuAt(parent_, button, bounds, position, false);
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete this;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkMenuController::Cancel() {
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  menu_->Cancel();
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstd::wstring BookmarkMenuController::GetTooltipText(
9272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int id, const gfx::Point& screen_loc) {
9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end());
9472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  const BookmarkNode* node = menu_id_to_node_map_[id];
96dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (node->type() == BookmarkNode::URL)
97dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return BookmarkBarView::CreateToolTipForURLAndTitle(
98dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        screen_loc, node->GetURL(), UTF16ToWide(node->GetTitle()), profile_);
99dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return std::wstring();
10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BookmarkMenuController::IsTriggerableEvent(const views::MouseEvent& e) {
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return event_utils::IsPossibleDispositionEvent(e);
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkMenuController::ExecuteCommand(int id, int mouse_event_flags) {
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(page_navigator_);
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end());
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* node = menu_id_to_node_map_[id];
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<const BookmarkNode*> selection;
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  selection.push_back(node);
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WindowOpenDisposition initial_disposition =
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      event_utils::DispositionFromEventFlags(mouse_event_flags);
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bookmark_utils::OpenAll(parent_, profile_, page_navigator_, selection,
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          initial_disposition);
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BookmarkMenuController::GetDropFormats(
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      MenuItemView* menu,
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int* formats,
12472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      std::set<ui::OSExchangeData::CustomFormat>* custom_formats) {
12572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  *formats = ui::OSExchangeData::URL;
126201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  custom_formats->insert(BookmarkNodeData::GetBookmarkCustomFormat());
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BookmarkMenuController::AreDropTypesRequired(MenuItemView* menu) {
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BookmarkMenuController::CanDrop(MenuItemView* menu,
13572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                     const ui::OSExchangeData& data) {
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Only accept drops of 1 node, which is the case for all data dragged from
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // bookmark bar and menus.
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!drop_data_.Read(data) || drop_data_.elements.size() != 1 ||
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      !profile_->GetPrefs()->GetBoolean(prefs::kEditBookmarksEnabled))
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (drop_data_.has_single_url())
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* drag_node = drop_data_.GetFirstNode(profile_);
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!drag_node) {
148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Dragging a folder from another profile, always accept.
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Drag originated from same profile and is not a URL. Only accept it if
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the dragged node is not a parent of the node menu represents.
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()];
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(drop_node);
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (drop_node && drop_node != drag_node)
157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    drop_node = drop_node->parent();
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return (drop_node == NULL);
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BookmarkMenuController::GetDropOperation(
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MenuItemView* item,
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const views::DropTargetEvent& event,
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DropPosition* position) {
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Should only get here if we have drop data.
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(drop_data_.is_valid());
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* node = menu_id_to_node_map_[item->GetCommand()];
169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const BookmarkNode* drop_parent = node->parent();
170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int index_to_drop_at = drop_parent->GetIndexOf(node);
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (*position == DROP_AFTER) {
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    index_to_drop_at++;
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (*position == DROP_ON) {
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drop_parent = node;
175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    index_to_drop_at = node->child_count();
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(drop_parent);
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return bookmark_utils::BookmarkDropOperation(
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      profile_, event, drop_data_, drop_parent, index_to_drop_at);
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BookmarkMenuController::OnPerformDrop(MenuItemView* menu,
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          DropPosition position,
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const views::DropTargetEvent& event) {
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()];
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(drop_node);
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkModel* model = profile_->GetBookmarkModel();
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(model);
189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const BookmarkNode* drop_parent = drop_node->parent();
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(drop_parent);
191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int index_to_drop_at = drop_parent->GetIndexOf(drop_node);
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (position == DROP_AFTER) {
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    index_to_drop_at++;
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (position == DROP_ON) {
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(drop_node->is_folder());
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drop_parent = drop_node;
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    index_to_drop_at = drop_node->child_count();
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int result = bookmark_utils::PerformBookmarkDrop(
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      profile_, drop_data_, drop_parent, index_to_drop_at);
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (for_drop_)
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete this;
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BookmarkMenuController::ShowContextMenu(MenuItemView* source,
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             int id,
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             const gfx::Point& p,
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             bool is_mouse_gesture) {
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end());
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<const BookmarkNode*> nodes;
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  nodes.push_back(menu_id_to_node_map_[id]);
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  context_menu_.reset(
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new BookmarkContextMenu(
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          parent_,
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          profile_,
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          page_navigator_,
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          nodes[0]->parent(),
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          nodes));
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  context_menu_->set_observer(this);
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  context_menu_->RunMenuAt(p);
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  context_menu_.reset(NULL);
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkMenuController::DropMenuClosed(MenuItemView* menu) {
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete this;
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BookmarkMenuController::CanDrag(MenuItemView* menu) {
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkMenuController::WriteDragData(MenuItemView* sender,
23672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                           ui::OSExchangeData* data) {
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(sender && data);
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UserMetrics::RecordAction(UserMetricsAction("BookmarkBar_DragFromFolder"),
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            profile_);
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
242201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  BookmarkNodeData drag_data(menu_id_to_node_map_[sender->GetCommand()]);
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drag_data.Write(profile_, data);
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BookmarkMenuController::GetDragOperations(MenuItemView* sender) {
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return bookmark_utils::BookmarkDragOperation(profile_,
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      menu_id_to_node_map_[sender->GetCommand()]);
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochviews::MenuItemView* BookmarkMenuController::GetSiblingMenu(
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    views::MenuItemView* menu,
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const gfx::Point& screen_point,
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    views::MenuItemView::AnchorPosition* anchor,
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool* has_mnemonics,
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    views::MenuButton** button) {
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!bookmark_bar_ || for_drop_)
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Point bookmark_bar_loc(screen_point);
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  views::View::ConvertPointToView(NULL, bookmark_bar_, &bookmark_bar_loc);
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int start_index;
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* node =
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bookmark_bar_->GetNodeForButtonAt(bookmark_bar_loc, &start_index);
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!node || !node->is_folder())
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MenuItemView* alt_menu = node_to_menu_map_[node];
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!alt_menu)
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    alt_menu = CreateMenu(node, start_index);
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  menu_ = alt_menu;
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *button = bookmark_bar_->GetMenuButtonForNode(node);
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bookmark_bar_->GetAnchorPositionAndStartIndexForButton(
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *button, anchor, &start_index);
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *has_mnemonics = false;
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return alt_menu;
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint BookmarkMenuController::GetMaxWidthForMenu() {
2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return kMaxMenuWidth;
2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkMenuController::BookmarkModelChanged() {
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  menu_->Cancel();
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BookmarkMenuController::BookmarkNodeFaviconLoaded(
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BookmarkModel* model, const BookmarkNode* node) {
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NodeToMenuIDMap::iterator menu_pair = node_to_menu_id_map_.find(node);
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (menu_pair == node_to_menu_id_map_.end())
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;  // We're not showing a menu item for the node.
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Iterate through the menus looking for the menu containing node.
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (NodeToMenuMap::iterator i = node_to_menu_map_.begin();
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != node_to_menu_map_.end(); ++i) {
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MenuItemView* menu_item = i->second->GetMenuItemByID(menu_pair->second);
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (menu_item) {
299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      menu_item->SetIcon(model->GetFavicon(node));
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkMenuController::WillRemoveBookmarks(
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::vector<const BookmarkNode*>& bookmarks) {
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::set<MenuItemView*> removed_menus;
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WillRemoveBookmarksImpl(bookmarks, &removed_menus);
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  STLDeleteElements(&removed_menus);
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkMenuController::DidRemoveBookmarks() {
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_->GetBookmarkModel()->AddObserver(this);
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochMenuItemView* BookmarkMenuController::CreateMenu(const BookmarkNode* parent,
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                 int start_child_index) {
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MenuItemView* menu = new MenuItemView(this);
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  menu->SetCommand(next_menu_id_++);
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  menu_id_to_node_map_[menu->GetCommand()] = parent;
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  menu->set_has_icons(true);
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BuildMenu(parent, start_child_index, menu, &next_menu_id_);
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  node_to_menu_map_[parent] = menu;
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return menu;
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkMenuController::BuildMenu(const BookmarkNode* parent,
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       int start_child_index,
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       MenuItemView* menu,
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       int* next_menu_id) {
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!parent->child_count() ||
334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         start_child_index < parent->child_count());
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (int i = start_child_index; i < parent->child_count(); ++i) {
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* node = parent->GetChild(i);
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int id = *next_menu_id;
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*next_menu_id)++;
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (node->is_url()) {
341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SkBitmap icon = profile_->GetBookmarkModel()->GetFavicon(node);
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (icon.width() == 0) {
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        icon = *ResourceBundle::GetSharedInstance().
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            GetBitmapNamed(IDR_DEFAULT_FAVICON);
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
3463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      menu->AppendMenuItemWithIcon(id, UTF16ToWide(node->GetTitle()), icon);
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      node_to_menu_id_map_[node] = id;
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (node->is_folder()) {
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SkBitmap* folder_icon = ResourceBundle::GetSharedInstance().
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          GetBitmapNamed(IDR_BOOKMARK_BAR_FOLDER);
3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      MenuItemView* submenu = menu->AppendSubMenuWithIcon(id,
3523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          UTF16ToWide(node->GetTitle()), *folder_icon);
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      node_to_menu_id_map_[node] = id;
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      BuildMenu(node, 0, submenu, next_menu_id);
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    menu_id_to_node_map_[id] = node;
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBookmarkMenuController::~BookmarkMenuController() {
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_->GetBookmarkModel()->RemoveObserver(this);
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (observer_)
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    observer_->BookmarkMenuDeleted(this);
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  STLDeleteValues(&node_to_menu_map_);
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochMenuItemView* BookmarkMenuController::GetMenuByID(int id) {
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (NodeToMenuMap::const_iterator i = node_to_menu_map_.begin();
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != node_to_menu_map_.end(); ++i) {
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MenuItemView* menu = i->second->GetMenuItemByID(id);
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (menu)
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return menu;
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return NULL;
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BookmarkMenuController::WillRemoveBookmarksImpl(
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const std::vector<const BookmarkNode*>& bookmarks,
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::set<views::MenuItemView*>* removed_menus) {
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Remove the observer so that when the remove happens we don't prematurely
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // cancel the menu.
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_->GetBookmarkModel()->RemoveObserver(this);
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Remove the menu items.
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::set<MenuItemView*> changed_parent_menus;
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<const BookmarkNode*>::const_iterator i = bookmarks.begin();
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != bookmarks.end(); ++i) {
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NodeToMenuIDMap::iterator node_to_menu = node_to_menu_id_map_.find(*i);
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (node_to_menu != node_to_menu_id_map_.end()) {
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      MenuItemView* menu = GetMenuByID(node_to_menu->second);
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DCHECK(menu);  // If there an entry in node_to_menu_id_map_, there should
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     // be a menu.
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      removed_menus->insert(menu);
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      changed_parent_menus.insert(menu->GetParentMenuItem());
39772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      menu->parent()->RemoveChildView(menu);
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      node_to_menu_id_map_.erase(node_to_menu);
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // All the bookmarks in |bookmarks| should have the same parent. It's possible
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to support different parents, but this would need to prune any nodes whose
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // parent has been removed. As all nodes currently have the same parent, there
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // is the DCHECK.
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(changed_parent_menus.size() <= 1);
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::set<MenuItemView*>::const_iterator i = changed_parent_menus.begin();
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != changed_parent_menus.end(); ++i) {
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*i)->ChildrenChanged();
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Remove any descendants of the removed nodes in node_to_menu_id_map_.
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (NodeToMenuIDMap::iterator i = node_to_menu_id_map_.begin();
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       i != node_to_menu_id_map_.end(); ) {
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool ancestor_removed = false;
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (std::vector<const BookmarkNode*>::const_iterator j = bookmarks.begin();
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         j != bookmarks.end(); ++j) {
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (i->first->HasAncestor(*j)) {
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ancestor_removed = true;
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (ancestor_removed) {
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      node_to_menu_id_map_.erase(i++);
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++i;
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
431