Home | History | Annotate | Download | only in renderer_context_menu
      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