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 21 using content::WebContents; 22 23 //////////////////////////////////////////////////////////////////////////////// 24 // RenderViewContextMenuViews, public: 25 26 RenderViewContextMenuViews::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 33 RenderViewContextMenuViews::~RenderViewContextMenuViews() { 34 } 35 36 // static 37 RenderViewContextMenuViews* RenderViewContextMenuViews::Create( 38 content::RenderFrameHost* render_frame_host, 39 const content::ContextMenuParams& params) { 40 return new RenderViewContextMenuViews(render_frame_host, params); 41 } 42 43 void 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 61 void RenderViewContextMenuViews::PlatformInit() { 62 menu_runner_.reset(new views::MenuRunner(&menu_model_)); 63 } 64 65 void RenderViewContextMenuViews::PlatformCancel() { 66 DCHECK(menu_runner_.get()); 67 menu_runner_->Cancel(); 68 } 69 70 bool 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 112 void 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 136 bool 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 153 bool 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 172 void 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 189 void 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