render_view_context_menu_views.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.h"
6
7#include "base/logging.h"
8#include "base/strings/utf_string_conversions.h"
9#include "chrome/app/chrome_command_ids.h"
10#include "content/public/browser/render_view_host.h"
11#include "content/public/browser/render_widget_host_view.h"
12#include "content/public/browser/web_contents.h"
13#include "grit/generated_resources.h"
14#include "ui/base/accelerators/accelerator.h"
15#include "ui/base/l10n/l10n_util.h"
16#include "ui/events/keycodes/keyboard_codes.h"
17#include "ui/gfx/point.h"
18#include "ui/views/controls/menu/menu_item_view.h"
19#include "ui/views/controls/menu/menu_model_adapter.h"
20#include "ui/views/controls/menu/menu_runner.h"
21
22using content::WebContents;
23
24////////////////////////////////////////////////////////////////////////////////
25// RenderViewContextMenuViews, public:
26
27RenderViewContextMenuViews::RenderViewContextMenuViews(
28    content::RenderFrameHost* render_frame_host,
29    const content::ContextMenuParams& params)
30    : RenderViewContextMenu(render_frame_host, params),
31      bidi_submenu_model_(this),
32      menu_view_(NULL) {
33}
34
35RenderViewContextMenuViews::~RenderViewContextMenuViews() {
36}
37
38// static
39RenderViewContextMenuViews* RenderViewContextMenuViews::Create(
40    content::RenderFrameHost* render_frame_host,
41    const content::ContextMenuParams& params) {
42  return new RenderViewContextMenuViews(render_frame_host, params);
43}
44
45void RenderViewContextMenuViews::RunMenuAt(views::Widget* parent,
46                                           const gfx::Point& point,
47                                           ui::MenuSourceType type) {
48  views::MenuAnchorPosition anchor_position =
49      (type == ui::MENU_SOURCE_TOUCH || type == ui::MENU_SOURCE_TOUCH_EDIT_MENU)
50          ? views::MENU_ANCHOR_BOTTOMCENTER
51          : views::MENU_ANCHOR_TOPLEFT;
52
53  if (menu_runner_->RunMenuAt(
54          parent, NULL, gfx::Rect(point, gfx::Size()), anchor_position, type) ==
55      views::MenuRunner::MENU_DELETED)
56    return;
57}
58
59////////////////////////////////////////////////////////////////////////////////
60// RenderViewContextMenuViews, protected:
61
62void RenderViewContextMenuViews::PlatformInit() {
63  menu_adapter_.reset(new views::MenuModelAdapter(&menu_model_));
64  menu_view_ = menu_adapter_->CreateMenu();
65  menu_runner_.reset(new views::MenuRunner(
66      menu_view_,
67      views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
68}
69
70void RenderViewContextMenuViews::PlatformCancel() {
71  DCHECK(menu_runner_.get());
72  menu_runner_->Cancel();
73}
74
75bool RenderViewContextMenuViews::GetAcceleratorForCommandId(
76    int command_id,
77    ui::Accelerator* accel) {
78  // There are no formally defined accelerators we can query so we assume
79  // that Ctrl+C, Ctrl+V, Ctrl+X, Ctrl-A, etc do what they normally do.
80  switch (command_id) {
81    case IDC_CONTENT_CONTEXT_UNDO:
82      *accel = ui::Accelerator(ui::VKEY_Z, ui::EF_CONTROL_DOWN);
83      return true;
84
85    case IDC_CONTENT_CONTEXT_REDO:
86      // TODO(jcampan): should it be Ctrl-Y?
87      *accel = ui::Accelerator(ui::VKEY_Z,
88                               ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
89      return true;
90
91    case IDC_CONTENT_CONTEXT_CUT:
92      *accel = ui::Accelerator(ui::VKEY_X, ui::EF_CONTROL_DOWN);
93      return true;
94
95    case IDC_CONTENT_CONTEXT_COPY:
96      *accel = ui::Accelerator(ui::VKEY_C, ui::EF_CONTROL_DOWN);
97      return true;
98
99    case IDC_CONTENT_CONTEXT_PASTE:
100      *accel = ui::Accelerator(ui::VKEY_V, ui::EF_CONTROL_DOWN);
101      return true;
102
103    case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
104      *accel = ui::Accelerator(ui::VKEY_V,
105                               ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
106      return true;
107
108    case IDC_CONTENT_CONTEXT_SELECTALL:
109      *accel = ui::Accelerator(ui::VKEY_A, ui::EF_CONTROL_DOWN);
110      return true;
111
112    default:
113      return false;
114  }
115}
116
117void RenderViewContextMenuViews::ExecuteCommand(int command_id,
118                                                int event_flags) {
119  switch (command_id) {
120    case IDC_WRITING_DIRECTION_DEFAULT:
121      // WebKit's current behavior is for this menu item to always be disabled.
122      NOTREACHED();
123      break;
124
125    case IDC_WRITING_DIRECTION_RTL:
126    case IDC_WRITING_DIRECTION_LTR: {
127      content::RenderViewHost* view_host = GetRenderViewHost();
128      view_host->UpdateTextDirection((command_id == IDC_WRITING_DIRECTION_RTL) ?
129          blink::WebTextDirectionRightToLeft :
130          blink::WebTextDirectionLeftToRight);
131      view_host->NotifyTextDirection();
132      break;
133    }
134
135    default:
136      RenderViewContextMenu::ExecuteCommand(command_id, event_flags);
137      break;
138  }
139}
140
141bool RenderViewContextMenuViews::IsCommandIdChecked(int command_id) const {
142  switch (command_id) {
143    case IDC_WRITING_DIRECTION_DEFAULT:
144      return (params_.writing_direction_default &
145          blink::WebContextMenuData::CheckableMenuItemChecked) != 0;
146    case IDC_WRITING_DIRECTION_RTL:
147      return (params_.writing_direction_right_to_left &
148          blink::WebContextMenuData::CheckableMenuItemChecked) != 0;
149    case IDC_WRITING_DIRECTION_LTR:
150      return (params_.writing_direction_left_to_right &
151          blink::WebContextMenuData::CheckableMenuItemChecked) != 0;
152
153    default:
154      return RenderViewContextMenu::IsCommandIdChecked(command_id);
155  }
156}
157
158bool RenderViewContextMenuViews::IsCommandIdEnabled(int command_id) const {
159  switch (command_id) {
160    case IDC_WRITING_DIRECTION_MENU:
161      return true;
162    case IDC_WRITING_DIRECTION_DEFAULT:  // Provided to match OS defaults.
163      return params_.writing_direction_default &
164          blink::WebContextMenuData::CheckableMenuItemEnabled;
165    case IDC_WRITING_DIRECTION_RTL:
166      return params_.writing_direction_right_to_left &
167          blink::WebContextMenuData::CheckableMenuItemEnabled;
168    case IDC_WRITING_DIRECTION_LTR:
169      return params_.writing_direction_left_to_right &
170          blink::WebContextMenuData::CheckableMenuItemEnabled;
171
172    default:
173      return RenderViewContextMenu::IsCommandIdEnabled(command_id);
174  }
175}
176
177void RenderViewContextMenuViews::AppendPlatformEditableItems() {
178  bidi_submenu_model_.AddCheckItem(
179      IDC_WRITING_DIRECTION_DEFAULT,
180      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT));
181  bidi_submenu_model_.AddCheckItem(
182      IDC_WRITING_DIRECTION_LTR,
183      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR));
184  bidi_submenu_model_.AddCheckItem(
185      IDC_WRITING_DIRECTION_RTL,
186      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL));
187
188  menu_model_.AddSubMenu(
189      IDC_WRITING_DIRECTION_MENU,
190      l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_MENU),
191      &bidi_submenu_model_);
192}
193
194void RenderViewContextMenuViews::UpdateMenuItem(int command_id,
195                                                bool enabled,
196                                                bool hidden,
197                                                const base::string16& title) {
198  views::MenuItemView* item = menu_view_->GetMenuItemByID(command_id);
199  if (!item)
200    return;
201
202  item->SetEnabled(enabled);
203  item->SetTitle(title);
204  item->SetVisible(!hidden);
205
206  views::MenuItemView* parent = item->GetParentMenuItem();
207  if (!parent)
208    return;
209
210  parent->ChildrenChanged();
211}
212