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