15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model_factory.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/bookmarks/bookmark_drag_drop.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/bookmarks/bookmark_utils.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/event_utils.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/page_navigator.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/user_metrics.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ui_resources.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/dragdrop/os_exchange_data.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/window_open_disposition.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/button/menu_button.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_item_view.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/submenu_view.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::PageNavigator;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::UserMetricsAction;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using views::MenuItemView;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Max width of a menu. There does not appear to be an OS value for this, yet
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// both IE and FF restrict the max width of a menu.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxMenuWidth = 400;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkMenuDelegate::BookmarkMenuDelegate(Browser* browser,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           PageNavigator* navigator,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           views::Widget* parent,
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           int first_menu_id,
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           int max_menu_id)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : browser_(browser),
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_(browser->profile()),
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page_navigator_(navigator),
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_(parent),
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      menu_(NULL),
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for_drop_(false),
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_menu_item_(NULL),
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_menu_id_(first_menu_id),
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      min_menu_id_(first_menu_id),
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      max_menu_id_(max_menu_id),
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      real_delegate_(NULL),
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_mutating_model_(false),
5868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      location_(BOOKMARK_LAUNCH_LOCATION_NONE) {}
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkMenuDelegate::~BookmarkMenuDelegate() {
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  GetBookmarkModel()->RemoveObserver(this);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void BookmarkMenuDelegate::Init(views::MenuDelegate* real_delegate,
6568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                MenuItemView* parent,
6668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                const BookmarkNode* node,
6768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                int start_child_index,
6868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                ShowOptions show_options,
6968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                BookmarkLaunchLocation location) {
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  GetBookmarkModel()->AddObserver(this);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  real_delegate_ = real_delegate;
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  location_ = location;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parent_menu_item_ = parent;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int initial_count = parent->GetSubmenu() ?
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        parent->GetSubmenu()->GetMenuItemCount() : 0;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((start_child_index < node->child_count()) &&
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (initial_count > 0)) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent->AppendSeparator();
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BuildMenu(node, start_child_index, parent, &next_menu_id_);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (show_options == SHOW_PERMANENT_FOLDERS)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BuildMenusForPermanentNodes(parent, &next_menu_id_);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    menu_ = CreateMenu(node, start_child_index, show_options);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuDelegate::SetPageNavigator(PageNavigator* navigator) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  page_navigator_ = navigator;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (context_menu_.get())
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context_menu_->SetPageNavigator(navigator);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)BookmarkModel* BookmarkMenuDelegate::GetBookmarkModel() {
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return BookmarkModelFactory::GetForProfile(profile_);
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuDelegate::SetActiveMenu(const BookmarkNode* node,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         int start_index) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!parent_menu_item_);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node_to_menu_map_[node])
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CreateMenu(node, start_index, HIDE_PERMANENT_FOLDERS);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu_ = node_to_menu_map_[node];
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
107d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)base::string16 BookmarkMenuDelegate::GetTooltipText(
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int id,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Point& screen_loc) const {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuIDToNodeMap::const_iterator i = menu_id_to_node_map_.find(id);
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // When removing bookmarks it may be possible to end up here without a node.
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (i == menu_id_to_node_map_.end()) {
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK(is_mutating_model_);
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return base::string16();
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = i->second;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->is_url()) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return BookmarkBarView::CreateToolTipForURLAndTitle(
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        parent_, screen_loc, node->url(), node->GetTitle(), profile_);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return base::string16();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkMenuDelegate::IsTriggerableEvent(views::MenuItemView* menu,
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              const ui::Event& e) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return e.type() == ui::ET_GESTURE_TAP ||
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         e.type() == ui::ET_GESTURE_TAP_DOWN ||
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         event_utils::IsPossibleDispositionEvent(e);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuDelegate::ExecuteCommand(int id, int mouse_event_flags) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end());
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = menu_id_to_node_map_[id];
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<const BookmarkNode*> selection;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  selection.push_back(node);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome::OpenAll(parent_->GetNativeWindow(), page_navigator_, selection,
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  ui::DispositionFromEventFlags(mouse_event_flags),
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  profile_);
1420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  RecordBookmarkLaunch(node, location_);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarkMenuDelegate::ShouldExecuteCommandWithoutClosingMenu(
14668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    int id,
14768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const ui::Event& event) {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (event.flags() & ui::EF_LEFT_MOUSE_BUTTON) &&
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         ui::DispositionFromEventFlags(event.flags()) == NEW_BACKGROUND_TAB;
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkMenuDelegate::GetDropFormats(
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MenuItemView* menu,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int* formats,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::set<ui::OSExchangeData::CustomFormat>* custom_formats) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *formats = ui::OSExchangeData::URL;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  custom_formats->insert(BookmarkNodeData::GetBookmarkCustomFormat());
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkMenuDelegate::AreDropTypesRequired(MenuItemView* menu) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkMenuDelegate::CanDrop(MenuItemView* menu,
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const ui::OSExchangeData& data) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only accept drops of 1 node, which is the case for all data dragged from
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // bookmark bar and menus.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!drop_data_.Read(data) || drop_data_.elements.size() != 1 ||
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !profile_->GetPrefs()->GetBoolean(prefs::kEditBookmarksEnabled))
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (drop_data_.has_single_url())
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* drag_node = drop_data_.GetFirstNode(profile_);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!drag_node) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Dragging a folder from another profile, always accept.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Drag originated from same profile and is not a URL. Only accept it if
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the dragged node is not a parent of the node menu represents.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (menu_id_to_node_map_.find(menu->GetCommand()) ==
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      menu_id_to_node_map_.end()) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we don't know the menu assume its because we're embedded. We'll
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // figure out the real operation when GetDropOperation is invoked.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()];
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(drop_node);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (drop_node && drop_node != drag_node)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drop_node = drop_node->parent();
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (drop_node == NULL);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BookmarkMenuDelegate::GetDropOperation(
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MenuItemView* item,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::DropTargetEvent& event,
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::MenuDelegate::DropPosition* position) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Should only get here if we have drop data.
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(drop_data_.is_valid());
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = menu_id_to_node_map_[item->GetCommand()];
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* drop_parent = node->parent();
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index_to_drop_at = drop_parent->GetIndexOf(node);
2083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  BookmarkModel* model = GetBookmarkModel();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (*position) {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case views::MenuDelegate::DROP_AFTER:
2113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (node == model->other_node() || node == model->mobile_node()) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Dropping after these nodes makes no sense.
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *position = views::MenuDelegate::DROP_NONE;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index_to_drop_at++;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case views::MenuDelegate::DROP_BEFORE:
2193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (node == model->mobile_node()) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Dropping before this node makes no sense.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *position = views::MenuDelegate::DROP_NONE;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case views::MenuDelegate::DROP_ON:
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drop_parent = node;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index_to_drop_at = node->child_count();
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(drop_parent);
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return chrome::GetBookmarkDropOperation(profile_, event, drop_data_,
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          drop_parent, index_to_drop_at);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BookmarkMenuDelegate::OnPerformDrop(
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MenuItemView* menu,
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::MenuDelegate::DropPosition position,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::DropTargetEvent& event) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()];
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(drop_node);
2443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  BookmarkModel* model = GetBookmarkModel();
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(model);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* drop_parent = drop_node->parent();
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(drop_parent);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index_to_drop_at = drop_parent->GetIndexOf(drop_node);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (position) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case views::MenuDelegate::DROP_AFTER:
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index_to_drop_at++;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case views::MenuDelegate::DROP_ON:
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(drop_node->is_folder());
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drop_parent = drop_node;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index_to_drop_at = drop_node->child_count();
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case views::MenuDelegate::DROP_BEFORE:
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (drop_node == model->other_node() ||
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          drop_node == model->mobile_node()) {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // This can happen with SHOW_PERMANENT_FOLDERS.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        drop_parent = model->bookmark_bar_node();
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        index_to_drop_at = drop_parent->child_count();
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return chrome::DropBookmarks(profile_, drop_data_,
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               drop_parent, index_to_drop_at);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkMenuDelegate::ShowContextMenu(MenuItemView* source,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int id,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const gfx::Point& p,
2807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                           ui::MenuSourceType source_type) {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end());
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<const BookmarkNode*> nodes;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nodes.push_back(menu_id_to_node_map_[id]);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool close_on_delete = !parent_menu_item_ &&
2853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      (nodes[0]->parent() == GetBookmarkModel()->other_node() &&
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       nodes[0]->parent()->child_count() == 1);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  context_menu_.reset(
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new BookmarkContextMenu(
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          parent_,
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          browser_,
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          profile_,
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          page_navigator_,
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          nodes[0]->parent(),
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          nodes,
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          close_on_delete));
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  context_menu_->set_observer(this);
2977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  context_menu_->RunMenuAt(p, source_type);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  context_menu_.reset(NULL);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkMenuDelegate::CanDrag(MenuItemView* menu) {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = menu_id_to_node_map_[menu->GetCommand()];
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Don't let users drag the other folder.
3053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return node->parent() != GetBookmarkModel()->root_node();
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuDelegate::WriteDragData(MenuItemView* sender,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         ui::OSExchangeData* data) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(sender && data);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::RecordAction(UserMetricsAction("BookmarkBar_DragFromFolder"));
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkNodeData drag_data(menu_id_to_node_map_[sender->GetCommand()]);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_data.Write(profile_, data);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BookmarkMenuDelegate::GetDragOperations(MenuItemView* sender) {
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return chrome::GetBookmarkDragOperation(
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_, menu_id_to_node_map_[sender->GetCommand()]);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BookmarkMenuDelegate::GetMaxWidthForMenu(MenuItemView* menu) {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kMaxMenuWidth;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuDelegate::BookmarkModelChanged() {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuDelegate::BookmarkNodeFaviconChanged(
331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    BookmarkModel* model,
332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const BookmarkNode* node) {
333868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  NodeToMenuMap::iterator menu_pair = node_to_menu_map_.find(node);
334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (menu_pair == node_to_menu_map_.end())
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // We're not showing a menu item for the node.
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
337868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  menu_pair->second->SetIcon(model->GetFavicon(node).AsImageSkia());
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuDelegate::WillRemoveBookmarks(
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<const BookmarkNode*>& bookmarks) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!is_mutating_model_);
343868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  is_mutating_model_ = true;  // Set to false in DidRemoveBookmarks().
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove the observer so that when the remove happens we don't prematurely
346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // cancel the menu. The observer is added back in DidRemoveBookmarks().
3473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  GetBookmarkModel()->RemoveObserver(this);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove the menu items.
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<MenuItemView*> changed_parent_menus;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<const BookmarkNode*>::const_iterator i(bookmarks.begin());
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != bookmarks.end(); ++i) {
353868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    NodeToMenuMap::iterator node_to_menu = node_to_menu_map_.find(*i);
354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (node_to_menu != node_to_menu_map_.end()) {
355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      MenuItemView* menu = node_to_menu->second;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MenuItemView* parent = menu->GetParentMenuItem();
357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // |parent| is NULL when removing a root. This happens when right clicking
358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // to delete an empty folder.
359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (parent) {
360868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        changed_parent_menus.insert(parent);
361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        parent->RemoveMenuItemAt(menu->parent()->GetIndexOf(menu));
362868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
363868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      node_to_menu_map_.erase(node_to_menu);
364868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      menu_id_to_node_map_.erase(menu->GetCommand());
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // All the bookmarks in |bookmarks| should have the same parent. It's possible
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to support different parents, but this would need to prune any nodes whose
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // parent has been removed. As all nodes currently have the same parent, there
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is the DCHECK.
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(changed_parent_menus.size() <= 1);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
374868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Remove any descendants of the removed nodes in |node_to_menu_map_|.
375868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (NodeToMenuMap::iterator i(node_to_menu_map_.begin());
376868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       i != node_to_menu_map_.end(); ) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool ancestor_removed = false;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::vector<const BookmarkNode*>::const_iterator j(bookmarks.begin());
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         j != bookmarks.end(); ++j) {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (i->first->HasAncestor(*j)) {
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ancestor_removed = true;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
385868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (ancestor_removed) {
386868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      menu_id_to_node_map_.erase(i->second->GetCommand());
387868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      node_to_menu_map_.erase(i++);
388868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    } else {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++i;
390868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
392eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
393eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (std::set<MenuItemView*>::const_iterator i(changed_parent_menus.begin());
394eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       i != changed_parent_menus.end(); ++i)
395eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    (*i)->ChildrenChanged();
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuDelegate::DidRemoveBookmarks() {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Balances remove in WillRemoveBookmarksImpl.
4003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  GetBookmarkModel()->AddObserver(this);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(is_mutating_model_);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_mutating_model_ = false;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MenuItemView* BookmarkMenuDelegate::CreateMenu(const BookmarkNode* parent,
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               int start_child_index,
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               ShowOptions show_options) {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuItemView* menu = new MenuItemView(real_delegate_);
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->SetCommand(next_menu_id_++);
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu_id_to_node_map_[menu->GetCommand()] = parent;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->set_has_icons(true);
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BuildMenu(parent, start_child_index, menu, &next_menu_id_);
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (show_options == SHOW_PERMANENT_FOLDERS)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BuildMenusForPermanentNodes(menu, &next_menu_id_);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return menu;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuDelegate::BuildMenusForPermanentNodes(
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::MenuItemView* menu,
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int* next_menu_id) {
4213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  BookmarkModel* model = GetBookmarkModel();
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool added_separator = false;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BuildMenuForPermanentNode(model->other_node(), menu, next_menu_id,
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            &added_separator);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BuildMenuForPermanentNode(model->mobile_node(), menu, next_menu_id,
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            &added_separator);
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuDelegate::BuildMenuForPermanentNode(
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* node,
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MenuItemView* menu,
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int* next_menu_id,
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool* added_separator) {
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node->IsVisible() || node->GetTotalNodeCount() == 1)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // No children, don't create a menu.
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  int id = *next_menu_id;
4384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Don't create the submenu if its menu ID will be outside the range allowed.
4394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (IsOutsideMenuIdRange(id))
4404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
4414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  (*next_menu_id)++;
4424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!*added_separator) {
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *added_separator = true;
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    menu->AppendSeparator();
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
448d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
449d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  gfx::ImageSkia* folder_icon = rb->GetImageSkiaNamed(IDR_BOOKMARK_BAR_FOLDER);
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuItemView* submenu = menu->AppendSubMenuWithIcon(
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id, node->GetTitle(), *folder_icon);
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BuildMenu(node, 0, submenu, next_menu_id);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu_id_to_node_map_[id] = node;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuDelegate::BuildMenu(const BookmarkNode* parent,
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     int start_child_index,
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     MenuItemView* menu,
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     int* next_menu_id) {
460868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  node_to_menu_map_[parent] = menu;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(parent->empty() || start_child_index < parent->child_count());
462d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = start_child_index; i < parent->child_count(); ++i) {
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* node = parent->GetChild(i);
465868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const int id = *next_menu_id;
4664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Don't create the item if its menu ID will be outside the range allowed.
4674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (IsOutsideMenuIdRange(id))
4684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      break;
4694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*next_menu_id)++;
471868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
472868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    menu_id_to_node_map_[id] = node;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (node->is_url()) {
4743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      const gfx::Image& image = GetBookmarkModel()->GetFavicon(node);
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const gfx::ImageSkia* icon = image.IsEmpty() ?
476d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          rb->GetImageSkiaNamed(IDR_DEFAULT_FAVICON) : image.ToImageSkia();
477868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      node_to_menu_map_[node] =
478868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          menu->AppendMenuItemWithIcon(id, node->GetTitle(), *icon);
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (node->is_folder()) {
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::ImageSkia* folder_icon =
481d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          rb->GetImageSkiaNamed(IDR_BOOKMARK_BAR_FOLDER);
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MenuItemView* submenu = menu->AppendSubMenuWithIcon(
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          id, node->GetTitle(), *folder_icon);
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BuildMenu(node, 0, submenu, next_menu_id);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool BookmarkMenuDelegate::IsOutsideMenuIdRange(int menu_id) const {
4924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return menu_id < min_menu_id_ || menu_id > max_menu_id_;
4934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
494