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.
5 #include "chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.h"
7 #include "base/logging.h"
8 #include "base/strings/string16.h"
9 #include "chrome/app/chrome_command_ids.h"
10 #include "chrome/grit/generated_resources.h"
11 #include "components/renderer_context_menu/views/toolkit_delegate_views.h"
12 #include "content/public/browser/render_view_host.h"
13 #include "content/public/browser/render_widget_host_view.h"
14 #include "content/public/browser/web_contents.h"
15 #include "ui/aura/client/screen_position_client.h"
16 #include "ui/aura/window.h"
17 #include "ui/base/accelerators/accelerator.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/events/keycodes/keyboard_codes.h"
20 #include "ui/views/widget/widget.h"
22 using content::WebContents;
24 ////////////////////////////////////////////////////////////////////////////////
25 // RenderViewContextMenuViews, public:
27 RenderViewContextMenuViews::RenderViewContextMenuViews(
28 content::RenderFrameHost* render_frame_host,
29 const content::ContextMenuParams& params)
30 : RenderViewContextMenu(render_frame_host, params),
31 bidi_submenu_model_(this) {
32 scoped_ptr<ToolkitDelegate> delegate(new ToolkitDelegateViews);
33 set_toolkit_delegate(delegate.Pass());
36 RenderViewContextMenuViews::~RenderViewContextMenuViews() {
40 RenderViewContextMenuViews* RenderViewContextMenuViews::Create(
41 content::RenderFrameHost* render_frame_host,
42 const content::ContextMenuParams& params) {
43 return new RenderViewContextMenuViews(render_frame_host, params);
46 void RenderViewContextMenuViews::RunMenuAt(views::Widget* parent,
47 const gfx::Point& point,
48 ui::MenuSourceType type) {
49 static_cast<ToolkitDelegateViews*>(toolkit_delegate())->
50 RunMenuAt(parent, point, type);
53 ////////////////////////////////////////////////////////////////////////////////
54 // RenderViewContextMenuViews, protected:
56 bool RenderViewContextMenuViews::GetAcceleratorForCommandId(
58 ui::Accelerator* accel) {
59 // There are no formally defined accelerators we can query so we assume
60 // that Ctrl+C, Ctrl+V, Ctrl+X, Ctrl-A, etc do what they normally do.
62 case IDC_CONTENT_CONTEXT_UNDO:
63 *accel = ui::Accelerator(ui::VKEY_Z, ui::EF_CONTROL_DOWN);
66 case IDC_CONTENT_CONTEXT_REDO:
67 // TODO(jcampan): should it be Ctrl-Y?
68 *accel = ui::Accelerator(ui::VKEY_Z,
69 ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
72 case IDC_CONTENT_CONTEXT_CUT:
73 *accel = ui::Accelerator(ui::VKEY_X, ui::EF_CONTROL_DOWN);
76 case IDC_CONTENT_CONTEXT_COPY:
77 *accel = ui::Accelerator(ui::VKEY_C, ui::EF_CONTROL_DOWN);
80 case IDC_CONTENT_CONTEXT_PASTE:
81 *accel = ui::Accelerator(ui::VKEY_V, ui::EF_CONTROL_DOWN);
84 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
85 *accel = ui::Accelerator(ui::VKEY_V,
86 ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
89 case IDC_CONTENT_CONTEXT_SELECTALL:
90 *accel = ui::Accelerator(ui::VKEY_A, ui::EF_CONTROL_DOWN);
98 void RenderViewContextMenuViews::ExecuteCommand(int command_id,
100 switch (command_id) {
101 case IDC_WRITING_DIRECTION_DEFAULT:
102 // WebKit's current behavior is for this menu item to always be disabled.
106 case IDC_WRITING_DIRECTION_RTL:
107 case IDC_WRITING_DIRECTION_LTR: {
108 content::RenderViewHost* view_host = GetRenderViewHost();
109 view_host->UpdateTextDirection((command_id == IDC_WRITING_DIRECTION_RTL) ?
110 blink::WebTextDirectionRightToLeft :
111 blink::WebTextDirectionLeftToRight);
112 view_host->NotifyTextDirection();
117 RenderViewContextMenu::ExecuteCommand(command_id, event_flags);
122 bool RenderViewContextMenuViews::IsCommandIdChecked(int command_id) const {
123 switch (command_id) {
124 case IDC_WRITING_DIRECTION_DEFAULT:
125 return (params_.writing_direction_default &
126 blink::WebContextMenuData::CheckableMenuItemChecked) != 0;
127 case IDC_WRITING_DIRECTION_RTL:
128 return (params_.writing_direction_right_to_left &
129 blink::WebContextMenuData::CheckableMenuItemChecked) != 0;
130 case IDC_WRITING_DIRECTION_LTR:
131 return (params_.writing_direction_left_to_right &
132 blink::WebContextMenuData::CheckableMenuItemChecked) != 0;
135 return RenderViewContextMenu::IsCommandIdChecked(command_id);
139 bool RenderViewContextMenuViews::IsCommandIdEnabled(int command_id) const {
140 switch (command_id) {
141 case IDC_WRITING_DIRECTION_MENU:
143 case IDC_WRITING_DIRECTION_DEFAULT: // Provided to match OS defaults.
144 return params_.writing_direction_default &
145 blink::WebContextMenuData::CheckableMenuItemEnabled;
146 case IDC_WRITING_DIRECTION_RTL:
147 return params_.writing_direction_right_to_left &
148 blink::WebContextMenuData::CheckableMenuItemEnabled;
149 case IDC_WRITING_DIRECTION_LTR:
150 return params_.writing_direction_left_to_right &
151 blink::WebContextMenuData::CheckableMenuItemEnabled;
154 return RenderViewContextMenu::IsCommandIdEnabled(command_id);
158 void RenderViewContextMenuViews::AppendPlatformEditableItems() {
159 bidi_submenu_model_.AddCheckItem(
160 IDC_WRITING_DIRECTION_DEFAULT,
161 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT));
162 bidi_submenu_model_.AddCheckItem(
163 IDC_WRITING_DIRECTION_LTR,
164 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR));
165 bidi_submenu_model_.AddCheckItem(
166 IDC_WRITING_DIRECTION_RTL,
167 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL));
169 menu_model_.AddSubMenu(
170 IDC_WRITING_DIRECTION_MENU,
171 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_MENU),
172 &bidi_submenu_model_);
175 void RenderViewContextMenuViews::Show() {
176 // Menus need a Widget to work. If we're not the active tab we won't
177 // necessarily be in a widget.
178 views::Widget* top_level_widget = GetTopLevelWidget();
179 if (!top_level_widget)
182 // Don't show empty menus.
183 if (menu_model().GetItemCount() == 0)
186 gfx::Point screen_point(params().x, params().y);
188 // Convert from target window coordinates to root window coordinates.
189 aura::Window* target_window = GetActiveNativeView();
190 aura::Window* root_window = target_window->GetRootWindow();
191 aura::client::ScreenPositionClient* screen_position_client =
192 aura::client::GetScreenPositionClient(root_window);
193 if (screen_position_client) {
194 screen_position_client->ConvertPointToScreen(target_window, &screen_point);
196 // Enable recursive tasks on the message loop so we can get updates while
197 // the context menu is being displayed.
198 base::MessageLoop::ScopedNestableTaskAllower allow(
199 base::MessageLoop::current());
200 RunMenuAt(top_level_widget, screen_point, params().source_type);
203 views::Widget* RenderViewContextMenuViews::GetTopLevelWidget() {
204 return views::Widget::GetTopLevelWidgetForNativeView(GetActiveNativeView());
207 aura::Window* RenderViewContextMenuViews::GetActiveNativeView() {
208 WebContents* web_contents =
209 WebContents::FromRenderFrameHost(GetRenderFrameHost());
211 LOG(ERROR) << "RenderViewContextMenuViews::Show, couldn't find WebContents";
214 return web_contents->GetFullscreenRenderWidgetHostView()
215 ? web_contents->GetFullscreenRenderWidgetHostView()
217 : web_contents->GetNativeView();