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