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