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_controller_views.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
1068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_stats.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
12424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/ui/views/bookmarks/bookmark_menu_controller_observer.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_model.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/page_navigator.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/user_metrics.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/dragdrop/os_exchange_data.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/button/menu_button.h"
205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/views/controls/menu/menu_item_view.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_runner.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::UserMetricsAction;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::PageNavigator;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using views::MenuItemView;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkMenuController::BookmarkMenuController(Browser* browser,
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               PageNavigator* page_navigator,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               views::Widget* parent,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               const BookmarkNode* node,
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                               int start_child_index,
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                               bool for_drop)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : menu_delegate_(
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        new BookmarkMenuDelegate(browser, page_navigator, parent, 1,
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                 kint32max)),
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      node_(node),
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      observer_(NULL),
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      for_drop_(for_drop),
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark_bar_(NULL) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu_delegate_->Init(this, NULL, node, start_child_index,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       BookmarkMenuDelegate::HIDE_PERMANENT_FOLDERS,
4368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                       BOOKMARK_LAUNCH_LOCATION_BAR_SUBFOLDER);
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  menu_runner_.reset(new views::MenuRunner(
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      menu_delegate_->menu(), for_drop ? views::MenuRunner::FOR_DROP : 0));
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid BookmarkMenuController::RunMenuAt(BookmarkBarView* bookmark_bar) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_bar_ = bookmark_bar;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::MenuButton* menu_button = bookmark_bar_->GetMenuButtonForNode(node_);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(menu_button);
525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  views::MenuAnchorPosition anchor;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_bar_->GetAnchorPositionForButton(menu_button, &anchor);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point screen_loc;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View::ConvertPointToScreen(menu_button, &screen_loc);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Subtract 1 from the height to make the popup flush with the button border.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect bounds(screen_loc.x(), screen_loc.y(), menu_button->width(),
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   menu_button->height() - 1);
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  menu_delegate_->GetBookmarkModel()->AddObserver(this);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only delete ourself after the menu completes, so we can safely ignore
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the return value.
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ignore_result(menu_runner_->RunMenuAt(menu_delegate_->parent(),
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        menu_button,
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        bounds,
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        anchor,
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                        ui::MENU_SOURCE_NONE));
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!for_drop_)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete this;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuController::Cancel() {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu_delegate_->menu()->Cancel();
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MenuItemView* BookmarkMenuController::menu() const {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return menu_delegate_->menu();
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MenuItemView* BookmarkMenuController::context_menu() const {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return menu_delegate_->context_menu();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuController::SetPageNavigator(PageNavigator* navigator) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu_delegate_->SetPageNavigator(navigator);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 BookmarkMenuController::GetTooltipText(int id,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                const gfx::Point& p) const {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return menu_delegate_->GetTooltipText(id, p);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkMenuController::IsTriggerableEvent(views::MenuItemView* menu,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                const ui::Event& e) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return menu_delegate_->IsTriggerableEvent(menu, e);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuController::ExecuteCommand(int id, int mouse_event_flags) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu_delegate_->ExecuteCommand(id, mouse_event_flags);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarkMenuController::ShouldExecuteCommandWithoutClosingMenu(
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int id, const ui::Event& e) {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return menu_delegate_->ShouldExecuteCommandWithoutClosingMenu(id, e);
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkMenuController::GetDropFormats(
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MenuItemView* menu,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int* formats,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::set<ui::OSExchangeData::CustomFormat>* custom_formats) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return menu_delegate_->GetDropFormats(menu, formats, custom_formats);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkMenuController::AreDropTypesRequired(MenuItemView* menu) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return menu_delegate_->AreDropTypesRequired(menu);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkMenuController::CanDrop(MenuItemView* menu,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const ui::OSExchangeData& data) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return menu_delegate_->CanDrop(menu, data);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BookmarkMenuController::GetDropOperation(
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MenuItemView* item,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::DropTargetEvent& event,
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DropPosition* position) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return menu_delegate_->GetDropOperation(item, event, position);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BookmarkMenuController::OnPerformDrop(MenuItemView* menu,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          DropPosition position,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          const ui::DropTargetEvent& event) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = menu_delegate_->OnPerformDrop(menu, position, event);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (for_drop_)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete this;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkMenuController::ShowContextMenu(MenuItemView* source,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             int id,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const gfx::Point& p,
1417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                             ui::MenuSourceType source_type) {
1427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return menu_delegate_->ShowContextMenu(source, id, p, source_type);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuController::DropMenuClosed(MenuItemView* menu) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete this;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkMenuController::CanDrag(MenuItemView* menu) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return menu_delegate_->CanDrag(menu);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuController::WriteDragData(MenuItemView* sender,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           ui::OSExchangeData* data) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return menu_delegate_->WriteDragData(sender, data);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BookmarkMenuController::GetDragOperations(MenuItemView* sender) {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return menu_delegate_->GetDragOperations(sender);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)views::MenuItemView* BookmarkMenuController::GetSiblingMenu(
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::MenuItemView* menu,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Point& screen_point,
1655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    views::MenuAnchorPosition* anchor,
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool* has_mnemonics,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::MenuButton** button) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!bookmark_bar_ || for_drop_)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point bookmark_bar_loc(screen_point);
171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  views::View::ConvertPointFromScreen(bookmark_bar_, &bookmark_bar_loc);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int start_index;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = bookmark_bar_->GetNodeForButtonAtModelIndex(
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark_bar_loc, &start_index);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node || !node->is_folder())
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu_delegate_->SetActiveMenu(node, start_index);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *button = bookmark_bar_->GetMenuButtonForNode(node);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_bar_->GetAnchorPositionForButton(*button, anchor);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *has_mnemonics = false;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this->menu();
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BookmarkMenuController::GetMaxWidthForMenu(MenuItemView* view) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return menu_delegate_->GetMaxWidthForMenu(view);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkMenuController::BookmarkModelChanged() {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!menu_delegate_->is_mutating_model())
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    menu()->Cancel();
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkMenuController::~BookmarkMenuController() {
1953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  menu_delegate_->GetBookmarkModel()->RemoveObserver(this);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer_)
197424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    observer_->BookmarkMenuControllerDeleted(this);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
199