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