Home | History | Annotate | Download | only in views
      1 // Copyright (c) 2012 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/wrench_menu.h"
      6 
      7 #include <algorithm>
      8 #include <cmath>
      9 #include <set>
     10 
     11 #include "base/strings/string_number_conversions.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "chrome/app/chrome_command_ids.h"
     14 #include "chrome/browser/bookmarks/bookmark_model.h"
     15 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
     16 #include "chrome/browser/chrome_notification_types.h"
     17 #include "chrome/browser/profiles/profile.h"
     18 #include "chrome/browser/search/search.h"
     19 #include "chrome/browser/ui/browser.h"
     20 #include "chrome/browser/ui/browser_window.h"
     21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     22 #include "chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h"
     23 #include "content/public/browser/host_zoom_map.h"
     24 #include "content/public/browser/notification_observer.h"
     25 #include "content/public/browser/notification_registrar.h"
     26 #include "content/public/browser/notification_source.h"
     27 #include "content/public/browser/notification_types.h"
     28 #include "content/public/browser/user_metrics.h"
     29 #include "content/public/browser/web_contents.h"
     30 #include "grit/chromium_strings.h"
     31 #include "grit/generated_resources.h"
     32 #include "grit/theme_resources.h"
     33 #include "third_party/skia/include/core/SkCanvas.h"
     34 #include "third_party/skia/include/core/SkPaint.h"
     35 #include "ui/base/l10n/l10n_util.h"
     36 #include "ui/base/layout.h"
     37 #include "ui/base/resource/resource_bundle.h"
     38 #include "ui/gfx/canvas.h"
     39 #include "ui/gfx/image/canvas_image_source.h"
     40 #include "ui/gfx/image/image.h"
     41 #include "ui/gfx/skia_util.h"
     42 #include "ui/gfx/text_utils.h"
     43 #include "ui/views/background.h"
     44 #include "ui/views/controls/button/image_button.h"
     45 #include "ui/views/controls/button/label_button.h"
     46 #include "ui/views/controls/button/menu_button.h"
     47 #include "ui/views/controls/label.h"
     48 #include "ui/views/controls/menu/menu_config.h"
     49 #include "ui/views/controls/menu/menu_item_view.h"
     50 #include "ui/views/controls/menu/menu_runner.h"
     51 #include "ui/views/controls/menu/menu_scroll_view_container.h"
     52 #include "ui/views/controls/menu/submenu_view.h"
     53 #include "ui/views/widget/widget.h"
     54 
     55 #if defined(USE_AURA)
     56 #include "ui/native_theme/native_theme_aura.h"
     57 #endif
     58 
     59 using content::HostZoomMap;
     60 using content::UserMetricsAction;
     61 using content::WebContents;
     62 using ui::MenuModel;
     63 using views::CustomButton;
     64 using views::ImageButton;
     65 using views::Label;
     66 using views::LabelButton;
     67 using views::MenuConfig;
     68 using views::MenuItemView;
     69 using views::View;
     70 
     71 namespace {
     72 
     73 // Colors used for buttons.
     74 const SkColor kEnabledTouchBackgroundColor = SkColorSetARGB(247, 255, 255, 255);
     75 const SkColor kHoverTouchBackgroundColor = SkColorSetARGB(247, 242, 242, 242);
     76 const SkColor kFocusedTouchBackgroundColor = SkColorSetARGB(247, 235, 235, 235);
     77 
     78 const SkColor kTouchButtonText = 0xff5a5a5a;
     79 
     80 // Horizontal padding on the edges of the buttons.
     81 const int kHorizontalPadding = 6;
     82 // Horizontal padding for a touch enabled menu.
     83 const int kHorizontalTouchPadding = 15;
     84 
     85 // Menu items which have embedded buttons should have this height in pixel.
     86 const int kMenuItemContainingButtonsHeight = 43;
     87 
     88 // Subclass of ImageButton whose preferred size includes the size of the border.
     89 class FullscreenButton : public ImageButton {
     90  public:
     91   explicit FullscreenButton(views::ButtonListener* listener)
     92       : ImageButton(listener) { }
     93 
     94   // Overridden from ImageButton.
     95   virtual gfx::Size GetPreferredSize() OVERRIDE {
     96     gfx::Size pref = ImageButton::GetPreferredSize();
     97     if (border()) {
     98       gfx::Insets insets = border()->GetInsets();
     99       pref.Enlarge(insets.width(), insets.height());
    100     }
    101     return pref;
    102   }
    103 
    104  private:
    105   DISALLOW_COPY_AND_ASSIGN(FullscreenButton);
    106 };
    107 
    108 // Border for buttons contained in the menu. This is only used for getting the
    109 // insets, the actual painting is done in MenuButtonBackground.
    110 class MenuButtonBorder : public views::Border {
    111  public:
    112   MenuButtonBorder(const MenuConfig& config, bool use_new_menu)
    113       : horizontal_padding_(use_new_menu ?
    114                             kHorizontalTouchPadding : kHorizontalPadding),
    115         insets_(config.item_top_margin, horizontal_padding_,
    116                 config.item_bottom_margin, horizontal_padding_) {
    117   }
    118 
    119   // Overridden from views::Border.
    120   virtual void Paint(const View& view, gfx::Canvas* canvas) OVERRIDE {
    121     // Painting of border is done in MenuButtonBackground.
    122   }
    123 
    124   virtual gfx::Insets GetInsets() const OVERRIDE {
    125     return insets_;
    126   }
    127 
    128  private:
    129   // The horizontal padding dependent on the layout.
    130   const int horizontal_padding_;
    131 
    132   const gfx::Insets insets_;
    133 
    134   DISALLOW_COPY_AND_ASSIGN(MenuButtonBorder);
    135 };
    136 
    137 // Combination border/background for the buttons contained in the menu. The
    138 // painting of the border/background is done here as TextButton does not always
    139 // paint the border.
    140 class MenuButtonBackground : public views::Background {
    141  public:
    142   enum ButtonType {
    143     LEFT_BUTTON,
    144     CENTER_BUTTON,
    145     RIGHT_BUTTON,
    146     SINGLE_BUTTON,
    147   };
    148 
    149   MenuButtonBackground(ButtonType type, bool use_new_menu)
    150       : type_(type),
    151         use_new_menu_(use_new_menu),
    152         left_button_(NULL),
    153         right_button_(NULL) {}
    154 
    155   // Used when the type is CENTER_BUTTON to determine if the left/right edge
    156   // needs to be rendered selected.
    157   void SetOtherButtons(CustomButton* left_button, CustomButton* right_button) {
    158     if (base::i18n::IsRTL()) {
    159       left_button_ = right_button;
    160       right_button_ = left_button;
    161     } else {
    162       left_button_ = left_button;
    163       right_button_ = right_button;
    164     }
    165   }
    166 
    167   // Overridden from views::Background.
    168   virtual void Paint(gfx::Canvas* canvas, View* view) const OVERRIDE {
    169     CustomButton::ButtonState state =
    170         (!strcmp(view->GetClassName(), views::Label::kViewClassName)) ?
    171         CustomButton::STATE_NORMAL : static_cast<CustomButton*>(view)->state();
    172     int w = view->width();
    173     int h = view->height();
    174 #if defined(USE_AURA)
    175     if (use_new_menu_ &&
    176         view->GetNativeTheme() == ui::NativeThemeAura::instance()) {
    177       // Normal buttons get a border drawn on the right side and the rest gets
    178       // filled in. The left button however does not get a line to combine
    179       // buttons.
    180       int border = 0;
    181       if (type_ != RIGHT_BUTTON) {
    182         border = 1;
    183         canvas->FillRect(gfx::Rect(0, 0, border, h),
    184                          BorderColor(view, CustomButton::STATE_NORMAL));
    185       }
    186       canvas->FillRect(gfx::Rect(border, 0, w - border, h),
    187                        touch_background_color(state));
    188       return;
    189     }
    190 #endif
    191     const SkColor background = BackgroundColor(view, state);
    192     const SkColor border = BorderColor(view, state);
    193     switch (TypeAdjustedForRTL()) {
    194       case LEFT_BUTTON:
    195         canvas->FillRect(gfx::Rect(1, 1, w, h - 2), background);
    196         canvas->FillRect(gfx::Rect(2, 0, w, 1), border);
    197         canvas->FillRect(gfx::Rect(1, 1, 1, 1), border);
    198         canvas->FillRect(gfx::Rect(0, 2, 1, h - 4), border);
    199         canvas->FillRect(gfx::Rect(1, h - 2, 1, 1), border);
    200         canvas->FillRect(gfx::Rect(2, h - 1, w, 1), border);
    201         break;
    202 
    203       case CENTER_BUTTON: {
    204         canvas->FillRect(gfx::Rect(1, 1, w - 2, h - 2), background);
    205         SkColor left_color = state != CustomButton::STATE_NORMAL ?
    206             border : BorderColor(view, left_button_->state());
    207         canvas->FillRect(gfx::Rect(0, 0, 1, h), left_color);
    208         canvas->FillRect(gfx::Rect(1, 0, w - 2, 1), border);
    209         canvas->FillRect(gfx::Rect(1, h - 1, w - 2, 1),
    210                          border);
    211         SkColor right_color = state != CustomButton::STATE_NORMAL ?
    212             border : BorderColor(view, right_button_->state());
    213         canvas->FillRect(gfx::Rect(w - 1, 0, 1, h), right_color);
    214         break;
    215       }
    216 
    217       case RIGHT_BUTTON:
    218         canvas->FillRect(gfx::Rect(0, 1, w - 1, h - 2), background);
    219         canvas->FillRect(gfx::Rect(0, 0, w - 2, 1), border);
    220         canvas->FillRect(gfx::Rect(w - 2, 1, 1, 1), border);
    221         canvas->FillRect(gfx::Rect(w - 1, 2, 1, h - 4), border);
    222         canvas->FillRect(gfx::Rect(w - 2, h - 2, 1, 1), border);
    223         canvas->FillRect(gfx::Rect(0, h - 1, w - 2, 1), border);
    224         break;
    225 
    226       case SINGLE_BUTTON:
    227         canvas->FillRect(gfx::Rect(1, 1, w - 2, h - 2), background);
    228         canvas->FillRect(gfx::Rect(2, 0, w - 4, 1), border);
    229         canvas->FillRect(gfx::Rect(1, 1, 1, 1), border);
    230         canvas->FillRect(gfx::Rect(0, 2, 1, h - 4), border);
    231         canvas->FillRect(gfx::Rect(1, h - 2, 1, 1), border);
    232         canvas->FillRect(gfx::Rect(2, h - 1, w - 4, 1), border);
    233         canvas->FillRect(gfx::Rect(w - 2, 1, 1, 1), border);
    234         canvas->FillRect(gfx::Rect(w - 1, 2, 1, h - 4), border);
    235         canvas->FillRect(gfx::Rect(w - 2, h - 2, 1, 1), border);
    236         break;
    237 
    238       default:
    239         NOTREACHED();
    240         break;
    241     }
    242   }
    243 
    244  private:
    245   static SkColor BorderColor(View* view, CustomButton::ButtonState state) {
    246     ui::NativeTheme* theme = view->GetNativeTheme();
    247     switch (state) {
    248       case CustomButton::STATE_HOVERED:
    249         return theme->GetSystemColor(
    250             ui::NativeTheme::kColorId_HoverMenuButtonBorderColor);
    251       case CustomButton::STATE_PRESSED:
    252         return theme->GetSystemColor(
    253             ui::NativeTheme::kColorId_FocusedMenuButtonBorderColor);
    254       default:
    255         return theme->GetSystemColor(
    256             ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor);
    257     }
    258   }
    259 
    260   static SkColor BackgroundColor(View* view, CustomButton::ButtonState state) {
    261     ui::NativeTheme* theme = view->GetNativeTheme();
    262     switch (state) {
    263       case CustomButton::STATE_HOVERED:
    264         return theme->GetSystemColor(
    265             ui::NativeTheme::kColorId_HoverMenuItemBackgroundColor);
    266       case CustomButton::STATE_PRESSED:
    267         return theme->GetSystemColor(
    268             ui::NativeTheme::kColorId_FocusedMenuItemBackgroundColor);
    269       default:
    270         return theme->GetSystemColor(
    271             ui::NativeTheme::kColorId_MenuBackgroundColor);
    272     }
    273   }
    274 
    275   static SkColor touch_background_color(CustomButton::ButtonState state) {
    276     switch (state) {
    277       case CustomButton::STATE_HOVERED: return kHoverTouchBackgroundColor;
    278       case CustomButton::STATE_PRESSED: return kFocusedTouchBackgroundColor;
    279       default:                          return kEnabledTouchBackgroundColor;
    280     }
    281   }
    282 
    283   ButtonType TypeAdjustedForRTL() const {
    284     if (!base::i18n::IsRTL())
    285       return type_;
    286 
    287     switch (type_) {
    288       case LEFT_BUTTON:   return RIGHT_BUTTON;
    289       case RIGHT_BUTTON:  return LEFT_BUTTON;
    290       default:            break;
    291     }
    292     return type_;
    293   }
    294 
    295   const ButtonType type_;
    296   const bool use_new_menu_;
    297 
    298   // See description above setter for details.
    299   CustomButton* left_button_;
    300   CustomButton* right_button_;
    301 
    302   DISALLOW_COPY_AND_ASSIGN(MenuButtonBackground);
    303 };
    304 
    305 string16 GetAccessibleNameForWrenchMenuItem(
    306       MenuModel* model, int item_index, int accessible_string_id) {
    307   string16 accessible_name = l10n_util::GetStringUTF16(accessible_string_id);
    308   string16 accelerator_text;
    309 
    310   ui::Accelerator menu_accelerator;
    311   if (model->GetAcceleratorAt(item_index, &menu_accelerator)) {
    312     accelerator_text =
    313         ui::Accelerator(menu_accelerator.key_code(),
    314                         menu_accelerator.modifiers()).GetShortcutText();
    315   }
    316 
    317   return MenuItemView::GetAccessibleNameForMenuItem(
    318       accessible_name, accelerator_text);
    319 }
    320 
    321 // WrenchMenuView is a view that can contain label buttons.
    322 class WrenchMenuView : public views::View,
    323                        public views::ButtonListener {
    324  public:
    325   WrenchMenuView(WrenchMenu* menu, MenuModel* menu_model)
    326       : menu_(menu),
    327         menu_model_(menu_model) {}
    328 
    329   // Overridden from views::View.
    330   virtual void SchedulePaintInRect(const gfx::Rect& r) OVERRIDE {
    331     // Normally when the mouse enters/exits a button the buttons invokes
    332     // SchedulePaint. As part of the button border (MenuButtonBackground) is
    333     // rendered by the button to the left/right of it SchedulePaint on the the
    334     // button may not be enough, so this forces a paint all.
    335     View::SchedulePaintInRect(gfx::Rect(size()));
    336   }
    337 
    338   LabelButton* CreateAndConfigureButton(int string_id,
    339                                        MenuButtonBackground::ButtonType type,
    340                                        int index,
    341                                        MenuButtonBackground** background) {
    342     return CreateButtonWithAccName(
    343       string_id, type, index, background, string_id);
    344   }
    345 
    346   LabelButton* CreateButtonWithAccName(int string_id,
    347                                        MenuButtonBackground::ButtonType type,
    348                                        int index,
    349                                        MenuButtonBackground** background,
    350                                        int acc_string_id) {
    351     LabelButton* button = new LabelButton(this, gfx::RemoveAcceleratorChar(
    352         l10n_util::GetStringUTF16(string_id), '&', NULL, NULL));
    353     button->SetAccessibleName(
    354         GetAccessibleNameForWrenchMenuItem(menu_model_, index, acc_string_id));
    355     button->set_focusable(true);
    356     button->set_request_focus_on_press(false);
    357     button->set_tag(index);
    358     button->SetEnabled(menu_model_->IsEnabledAt(index));
    359     MenuButtonBackground* bg =
    360         new MenuButtonBackground(type, menu_->use_new_menu());
    361     button->set_background(bg);
    362     const MenuConfig& menu_config = menu_->GetMenuConfig();
    363     button->SetTextColor(views::Button::STATE_NORMAL, menu_config.text_color);
    364     if (background)
    365       *background = bg;
    366     button->set_border(
    367         new MenuButtonBorder(menu_config, menu_->use_new_menu()));
    368     button->SetHorizontalAlignment(gfx::ALIGN_CENTER);
    369     button->SetFont(menu_config.font);
    370     AddChildView(button);
    371     return button;
    372   }
    373 
    374  protected:
    375   // Hosting WrenchMenu.
    376   WrenchMenu* menu_;
    377 
    378   // The menu model containing the increment/decrement/reset items.
    379   MenuModel* menu_model_;
    380 
    381  private:
    382   DISALLOW_COPY_AND_ASSIGN(WrenchMenuView);
    383 };
    384 
    385 class ButtonContainerMenuItemView : public MenuItemView {
    386  public:
    387   // Constructor for use with button containing menu items which have a
    388   // different height then normal items.
    389   ButtonContainerMenuItemView(MenuItemView* parent, int id, int height)
    390       : MenuItemView(parent, id, MenuItemView::NORMAL),
    391         height_(height) {
    392   };
    393 
    394   // Overridden from MenuItemView.
    395   virtual gfx::Size GetChildPreferredSize() OVERRIDE {
    396     gfx::Size size = MenuItemView::GetChildPreferredSize();
    397     // When there is a height override given, we need to deduct our spacing
    398     // above and below to get to the correct height to return here for the
    399     // child item.
    400     int height = height_ - GetTopMargin() - GetBottomMargin();
    401     if (height > size.height())
    402       size.set_height(height);
    403     return size;
    404   }
    405 
    406  private:
    407   int height_;
    408 
    409   DISALLOW_COPY_AND_ASSIGN(ButtonContainerMenuItemView);
    410 };
    411 
    412 }  // namespace
    413 
    414 // CutCopyPasteView ------------------------------------------------------------
    415 
    416 // CutCopyPasteView is the view containing the cut/copy/paste buttons.
    417 class WrenchMenu::CutCopyPasteView : public WrenchMenuView {
    418  public:
    419   CutCopyPasteView(WrenchMenu* menu,
    420                    MenuModel* menu_model,
    421                    const ui::NativeTheme* native_theme,
    422                    int cut_index,
    423                    int copy_index,
    424                    int paste_index)
    425       : WrenchMenuView(menu, menu_model) {
    426     LabelButton* cut = CreateAndConfigureButton(
    427         IDS_CUT, MenuButtonBackground::LEFT_BUTTON, cut_index, NULL);
    428 
    429     MenuButtonBackground* copy_background = NULL;
    430     LabelButton* copy = CreateAndConfigureButton(
    431         IDS_COPY, MenuButtonBackground::CENTER_BUTTON, copy_index,
    432         &copy_background);
    433 
    434     LabelButton* paste = CreateAndConfigureButton(
    435         IDS_PASTE,
    436         menu_->use_new_menu() && menu_->supports_new_separators_ ?
    437             MenuButtonBackground::CENTER_BUTTON :
    438             MenuButtonBackground::RIGHT_BUTTON,
    439         paste_index,
    440         NULL);
    441     if (menu_->use_new_menu()) {
    442       cut->SetTextColor(views::Button::STATE_NORMAL, kTouchButtonText);
    443       copy->SetTextColor(views::Button::STATE_NORMAL, kTouchButtonText);
    444       paste->SetTextColor(views::Button::STATE_NORMAL, kTouchButtonText);
    445     } else {
    446       SkColor text_color = native_theme->GetSystemColor(
    447           ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor);
    448       cut->SetTextColor(views::Button::STATE_NORMAL, text_color);
    449       copy->SetTextColor(views::Button::STATE_NORMAL, text_color);
    450       paste->SetTextColor(views::Button::STATE_NORMAL, text_color);
    451     }
    452     copy_background->SetOtherButtons(cut, paste);
    453   }
    454 
    455   // Overridden from View.
    456   virtual gfx::Size GetPreferredSize() OVERRIDE {
    457     // Returned height doesn't matter as MenuItemView forces everything to the
    458     // height of the menuitemview.
    459     return gfx::Size(GetMaxChildViewPreferredWidth() * child_count(), 0);
    460   }
    461 
    462   virtual void Layout() OVERRIDE {
    463     // All buttons are given the same width.
    464     int width = GetMaxChildViewPreferredWidth();
    465     for (int i = 0; i < child_count(); ++i)
    466       child_at(i)->SetBounds(i * width, 0, width, height());
    467   }
    468 
    469   // Overridden from ButtonListener.
    470   virtual void ButtonPressed(views::Button* sender,
    471                              const ui::Event& event) OVERRIDE {
    472     menu_->CancelAndEvaluate(menu_model_, sender->tag());
    473   }
    474 
    475  private:
    476   // Returns the max preferred width of all the children.
    477   int GetMaxChildViewPreferredWidth() {
    478     int width = 0;
    479     for (int i = 0; i < child_count(); ++i)
    480       width = std::max(width, child_at(i)->GetPreferredSize().width());
    481     return width;
    482   }
    483 
    484   DISALLOW_COPY_AND_ASSIGN(CutCopyPasteView);
    485 };
    486 
    487 // ZoomView --------------------------------------------------------------------
    488 
    489 // Padding between the increment buttons and the reset button.
    490 static const int kZoomPadding = 6;
    491 static const int kTouchZoomPadding = 14;
    492 
    493 // ZoomView contains the various zoom controls: two buttons to increase/decrease
    494 // the zoom, a label showing the current zoom percent, and a button to go
    495 // full-screen.
    496 class WrenchMenu::ZoomView : public WrenchMenuView {
    497  public:
    498   ZoomView(WrenchMenu* menu,
    499            MenuModel* menu_model,
    500            const ui::NativeTheme* native_theme,
    501            int decrement_index,
    502            int increment_index,
    503            int fullscreen_index)
    504       : WrenchMenuView(menu, menu_model),
    505         fullscreen_index_(fullscreen_index),
    506         zoom_callback_(base::Bind(&WrenchMenu::ZoomView::OnZoomLevelChanged,
    507                                   base::Unretained(this))),
    508         increment_button_(NULL),
    509         zoom_label_(NULL),
    510         decrement_button_(NULL),
    511         fullscreen_button_(NULL),
    512         zoom_label_width_(0) {
    513     HostZoomMap::GetForBrowserContext(
    514         menu_->browser_->profile())->AddZoomLevelChangedCallback(
    515             zoom_callback_);
    516 
    517     decrement_button_ = CreateButtonWithAccName(
    518         IDS_ZOOM_MINUS2, MenuButtonBackground::LEFT_BUTTON, decrement_index,
    519         NULL, IDS_ACCNAME_ZOOM_MINUS2);
    520 
    521     zoom_label_ = new Label(
    522         l10n_util::GetStringFUTF16Int(IDS_ZOOM_PERCENT, 100));
    523     zoom_label_->SetAutoColorReadabilityEnabled(false);
    524     zoom_label_->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
    525 
    526     MenuButtonBackground* center_bg = new MenuButtonBackground(
    527         menu_->use_new_menu() && menu_->supports_new_separators_ ?
    528             MenuButtonBackground::RIGHT_BUTTON :
    529             MenuButtonBackground::CENTER_BUTTON,
    530         menu_->use_new_menu());
    531     zoom_label_->set_background(center_bg);
    532     const MenuConfig& menu_config(menu->GetMenuConfig());
    533     zoom_label_->set_border(
    534         new MenuButtonBorder(menu_config, menu->use_new_menu()));
    535     zoom_label_->SetFont(menu_config.font);
    536 
    537     AddChildView(zoom_label_);
    538     zoom_label_width_ = MaxWidthForZoomLabel();
    539 
    540     increment_button_ = CreateButtonWithAccName(
    541         IDS_ZOOM_PLUS2, MenuButtonBackground::RIGHT_BUTTON, increment_index,
    542         NULL, IDS_ACCNAME_ZOOM_PLUS2);
    543 
    544     center_bg->SetOtherButtons(decrement_button_, increment_button_);
    545 
    546     fullscreen_button_ = new FullscreenButton(this);
    547     gfx::ImageSkia* full_screen_image =
    548         ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
    549             IDR_FULLSCREEN_MENU_BUTTON);
    550     fullscreen_button_->SetImage(ImageButton::STATE_NORMAL, full_screen_image);
    551     if (menu_->use_new_menu()) {
    552       zoom_label_->SetEnabledColor(kTouchButtonText);
    553       decrement_button_->SetTextColor(views::Button::STATE_NORMAL,
    554                                       kTouchButtonText);
    555       increment_button_->SetTextColor(views::Button::STATE_NORMAL,
    556                                       kTouchButtonText);
    557     } else {
    558       SkColor enabled_text_color = native_theme->GetSystemColor(
    559           ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor);
    560       zoom_label_->SetEnabledColor(enabled_text_color);
    561       decrement_button_->SetTextColor(views::Button::STATE_NORMAL,
    562                                       enabled_text_color);
    563       increment_button_->SetTextColor(views::Button::STATE_NORMAL,
    564                                       enabled_text_color);
    565       SkColor disabled_text_color = native_theme->GetSystemColor(
    566           ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor);
    567       decrement_button_->SetTextColor(views::Button::STATE_DISABLED,
    568                                       disabled_text_color);
    569       increment_button_->SetTextColor(views::Button::STATE_DISABLED,
    570                                       disabled_text_color);
    571     }
    572 
    573     fullscreen_button_->set_focusable(true);
    574     fullscreen_button_->set_request_focus_on_press(false);
    575     fullscreen_button_->set_tag(fullscreen_index);
    576     fullscreen_button_->SetImageAlignment(
    577         ImageButton::ALIGN_CENTER, ImageButton::ALIGN_MIDDLE);
    578     int horizontal_padding =
    579         menu_->use_new_menu() ? kHorizontalTouchPadding : kHorizontalPadding;
    580     fullscreen_button_->set_border(views::Border::CreateEmptyBorder(
    581         0, horizontal_padding, 0, horizontal_padding));
    582     fullscreen_button_->set_background(
    583         new MenuButtonBackground(MenuButtonBackground::SINGLE_BUTTON,
    584                                  menu_->use_new_menu()));
    585     fullscreen_button_->SetAccessibleName(
    586         GetAccessibleNameForWrenchMenuItem(
    587             menu_model, fullscreen_index, IDS_ACCNAME_FULLSCREEN));
    588     AddChildView(fullscreen_button_);
    589 
    590     UpdateZoomControls();
    591   }
    592 
    593   virtual ~ZoomView() {
    594     HostZoomMap::GetForBrowserContext(
    595         menu_->browser_->profile())->RemoveZoomLevelChangedCallback(
    596             zoom_callback_);
    597   }
    598 
    599   // Overridden from View.
    600   virtual gfx::Size GetPreferredSize() OVERRIDE {
    601     // The increment/decrement button are forced to the same width.
    602     int button_width = std::max(increment_button_->GetPreferredSize().width(),
    603                                 decrement_button_->GetPreferredSize().width());
    604     int zoom_padding = menu_->use_new_menu() ? kTouchZoomPadding : kZoomPadding;
    605     int fullscreen_width = fullscreen_button_->GetPreferredSize().width() +
    606                            zoom_padding;
    607     // Returned height doesn't matter as MenuItemView forces everything to the
    608     // height of the menuitemview. Note that we have overridden the height when
    609     // constructing the menu.
    610     return gfx::Size(button_width + zoom_label_width_ + button_width +
    611                      fullscreen_width, 0);
    612   }
    613 
    614   virtual void Layout() OVERRIDE {
    615     int x = 0;
    616     int button_width = std::max(increment_button_->GetPreferredSize().width(),
    617                                 decrement_button_->GetPreferredSize().width());
    618     gfx::Rect bounds(0, 0, button_width, height());
    619 
    620     decrement_button_->SetBoundsRect(bounds);
    621 
    622     x += bounds.width();
    623     bounds.set_x(x);
    624     bounds.set_width(zoom_label_width_);
    625     zoom_label_->SetBoundsRect(bounds);
    626 
    627     x += bounds.width();
    628     bounds.set_x(x);
    629     bounds.set_width(button_width);
    630     increment_button_->SetBoundsRect(bounds);
    631 
    632     x += bounds.width() + (menu_->use_new_menu() ? 0 : kZoomPadding);
    633     bounds.set_x(x);
    634     bounds.set_width(fullscreen_button_->GetPreferredSize().width() +
    635                      (menu_->use_new_menu() ? kTouchZoomPadding : 0));
    636     fullscreen_button_->SetBoundsRect(bounds);
    637   }
    638 
    639   // Overridden from ButtonListener.
    640   virtual void ButtonPressed(views::Button* sender,
    641                              const ui::Event& event) OVERRIDE {
    642     if (sender->tag() == fullscreen_index_) {
    643       menu_->CancelAndEvaluate(menu_model_, sender->tag());
    644     } else {
    645       // Zoom buttons don't close the menu.
    646       menu_model_->ActivatedAt(sender->tag());
    647     }
    648   }
    649 
    650  private:
    651   void OnZoomLevelChanged(const HostZoomMap::ZoomLevelChange& change) {
    652     UpdateZoomControls();
    653   }
    654 
    655   void UpdateZoomControls() {
    656     bool enable_increment = false;
    657     bool enable_decrement = false;
    658     WebContents* selected_tab =
    659         menu_->browser_->tab_strip_model()->GetActiveWebContents();
    660     int zoom = 100;
    661     if (selected_tab)
    662       zoom = selected_tab->GetZoomPercent(&enable_increment, &enable_decrement);
    663     increment_button_->SetEnabled(enable_increment);
    664     decrement_button_->SetEnabled(enable_decrement);
    665     zoom_label_->SetText(
    666         l10n_util::GetStringFUTF16Int(IDS_ZOOM_PERCENT, zoom));
    667 
    668     zoom_label_width_ = MaxWidthForZoomLabel();
    669   }
    670 
    671   // Calculates the max width the zoom string can be.
    672   int MaxWidthForZoomLabel() {
    673     gfx::Font font = zoom_label_->font();
    674     int border_width =
    675         zoom_label_->border() ? zoom_label_->border()->GetInsets().width() : 0;
    676 
    677     int max_w = 0;
    678 
    679     WebContents* selected_tab =
    680         menu_->browser_->tab_strip_model()->GetActiveWebContents();
    681     if (selected_tab) {
    682       int min_percent = selected_tab->GetMinimumZoomPercent();
    683       int max_percent = selected_tab->GetMaximumZoomPercent();
    684 
    685       int step = (max_percent - min_percent) / 10;
    686       for (int i = min_percent; i <= max_percent; i += step) {
    687         int w = font.GetStringWidth(
    688             l10n_util::GetStringFUTF16Int(IDS_ZOOM_PERCENT, i));
    689         max_w = std::max(w, max_w);
    690       }
    691     } else {
    692       max_w = font.GetStringWidth(
    693           l10n_util::GetStringFUTF16Int(IDS_ZOOM_PERCENT, 100));
    694     }
    695 
    696     return max_w + border_width;
    697   }
    698 
    699   // Index of the fullscreen menu item in the model.
    700   const int fullscreen_index_;
    701 
    702   content::HostZoomMap::ZoomLevelChangedCallback zoom_callback_;
    703   content::NotificationRegistrar registrar_;
    704 
    705   // Button for incrementing the zoom.
    706   LabelButton* increment_button_;
    707 
    708   // Label showing zoom as a percent.
    709   Label* zoom_label_;
    710 
    711   // Button for decrementing the zoom.
    712   LabelButton* decrement_button_;
    713 
    714   ImageButton* fullscreen_button_;
    715 
    716   // Width given to |zoom_label_|. This is the width at 100%.
    717   int zoom_label_width_;
    718 
    719   DISALLOW_COPY_AND_ASSIGN(ZoomView);
    720 };
    721 
    722 // RecentTabsMenuModelDelegate -------------------------------------------------
    723 
    724 // Provides the ui::MenuModelDelegate implementation for RecentTabsSubMenuModel
    725 // items.
    726 class WrenchMenu::RecentTabsMenuModelDelegate : public ui::MenuModelDelegate {
    727  public:
    728   RecentTabsMenuModelDelegate(ui::MenuModel* model,
    729                               views::MenuItemView* menu_item)
    730       : model_(model),
    731         menu_item_(menu_item) {
    732     model_->SetMenuModelDelegate(this);
    733   }
    734 
    735   virtual ~RecentTabsMenuModelDelegate() {
    736     model_->SetMenuModelDelegate(NULL);
    737   }
    738 
    739   // ui::MenuModelDelegate implementation:
    740   virtual void OnIconChanged(int index) OVERRIDE {
    741     // |index| specifies position in children items of |menu_item_| starting at
    742     // 0, its corresponding command id as used in the children menu item views
    743     // follows that of the parent menu item view |menu_item_|.
    744     int command_id = menu_item_->GetCommand() + 1 + index;
    745     views::MenuItemView* item = menu_item_->GetMenuItemByID(command_id);
    746     DCHECK(item);
    747     gfx::Image icon;
    748     if (model_->GetIconAt(index, &icon))
    749       item->SetIcon(*icon.ToImageSkia());
    750   }
    751 
    752   // Return the specific menu width of recent tab menu item if |command_id|
    753   // refers to one of recent tabs menu items, else return -1.
    754   int GetMaxWidthForMenu(MenuItemView* menu) {
    755     views::SubmenuView* submenu = menu_item_->GetSubmenu();
    756     if (!submenu)
    757       return -1;
    758     const int kMaxMenuItemWidth = 320;
    759     return menu->GetCommand() >= menu_item_->GetCommand() &&
    760         menu->GetCommand() <=
    761             menu_item_->GetCommand() + submenu->GetMenuItemCount() ?
    762         kMaxMenuItemWidth : -1;
    763   }
    764 
    765   const gfx::Font* GetLabelFontAt(int index) const {
    766     return model_->GetLabelFontAt(index);
    767   }
    768 
    769   bool GetForegroundColor(int command_id,
    770                           bool is_hovered,
    771                           SkColor* override_color) const {
    772     // The items for which we get a font, should be shown in black.
    773     if (GetLabelFontAt(command_id)) {
    774       *override_color = SK_ColorBLACK;
    775       return true;
    776     }
    777     return false;
    778   }
    779 
    780  private:
    781   ui::MenuModel* model_;
    782   views::MenuItemView* menu_item_;
    783 
    784   DISALLOW_COPY_AND_ASSIGN(RecentTabsMenuModelDelegate);
    785 };
    786 
    787 // WrenchMenu ------------------------------------------------------------------
    788 
    789 WrenchMenu::WrenchMenu(Browser* browser,
    790                        bool use_new_menu,
    791                        bool supports_new_separators)
    792     : root_(NULL),
    793       browser_(browser),
    794       selected_menu_model_(NULL),
    795       selected_index_(0),
    796       bookmark_menu_(NULL),
    797       feedback_menu_item_(NULL),
    798       first_bookmark_command_id_(0),
    799       first_recent_tabs_command_id_(-1),
    800       last_recent_tabs_command_id_(-1),
    801       use_new_menu_(use_new_menu),
    802       supports_new_separators_(supports_new_separators) {
    803   registrar_.Add(this, chrome::NOTIFICATION_GLOBAL_ERRORS_CHANGED,
    804                  content::Source<Profile>(browser_->profile()));
    805 }
    806 
    807 WrenchMenu::~WrenchMenu() {
    808   if (bookmark_menu_delegate_.get()) {
    809     BookmarkModel* model = BookmarkModelFactory::GetForProfile(
    810         browser_->profile());
    811     if (model)
    812       model->RemoveObserver(this);
    813   }
    814 }
    815 
    816 void WrenchMenu::Init(ui::MenuModel* model) {
    817   DCHECK(!root_);
    818   root_ = new MenuItemView(this);
    819   root_->set_has_icons(true);  // We have checks, radios and icons, set this
    820                                // so we get the taller menu style.
    821   int next_id = 1;
    822   PopulateMenu(root_, model, &next_id);
    823   first_bookmark_command_id_ = next_id + 1;
    824   menu_runner_.reset(new views::MenuRunner(root_));
    825 }
    826 
    827 void WrenchMenu::RunMenu(views::MenuButton* host) {
    828   gfx::Point screen_loc;
    829   views::View::ConvertPointToScreen(host, &screen_loc);
    830   gfx::Rect bounds(screen_loc, host->size());
    831   content::RecordAction(UserMetricsAction("ShowAppMenu"));
    832   if (menu_runner_->RunMenuAt(host->GetWidget(), host, bounds,
    833           MenuItemView::TOPRIGHT, ui::MENU_SOURCE_NONE,
    834           views::MenuRunner::HAS_MNEMONICS) ==
    835       views::MenuRunner::MENU_DELETED)
    836     return;
    837   if (bookmark_menu_delegate_.get()) {
    838     BookmarkModel* model = BookmarkModelFactory::GetForProfile(
    839         browser_->profile());
    840     if (model)
    841       model->RemoveObserver(this);
    842   }
    843   if (selected_menu_model_)
    844     selected_menu_model_->ActivatedAt(selected_index_);
    845 }
    846 
    847 bool WrenchMenu::IsShowing() {
    848   return menu_runner_.get() && menu_runner_->IsRunning();
    849 }
    850 
    851 const ui::NativeTheme* WrenchMenu::GetNativeTheme() const {
    852   views::Widget* browser_widget = views::Widget::GetWidgetForNativeView(
    853       browser_->window()->GetNativeWindow());
    854   DCHECK(browser_widget);
    855   return browser_widget->GetNativeTheme();
    856 }
    857 
    858 const views::MenuConfig& WrenchMenu::GetMenuConfig() const {
    859   return MenuConfig::instance(GetNativeTheme());
    860 }
    861 
    862 const gfx::Font* WrenchMenu::GetLabelFont(int index) const {
    863   if (is_recent_tabs_command(index)) {
    864     return recent_tabs_menu_model_delegate_->GetLabelFontAt(
    865         index - first_recent_tabs_command_id_);
    866   }
    867   return NULL;
    868 }
    869 
    870 bool WrenchMenu::GetForegroundColor(int command_id,
    871                                     bool is_hovered,
    872                                     SkColor* override_color) const {
    873   if (is_recent_tabs_command(command_id)) {
    874     return recent_tabs_menu_model_delegate_->GetForegroundColor(
    875         command_id - first_recent_tabs_command_id_,
    876         is_hovered,
    877         override_color);
    878   }
    879   return false;
    880 }
    881 
    882 string16 WrenchMenu::GetTooltipText(int id,
    883                                     const gfx::Point& p) const {
    884   return is_bookmark_command(id) ?
    885       bookmark_menu_delegate_->GetTooltipText(id, p) : string16();
    886 }
    887 
    888 bool WrenchMenu::IsTriggerableEvent(views::MenuItemView* menu,
    889                                     const ui::Event& e) {
    890   return is_bookmark_command(menu->GetCommand()) ?
    891       bookmark_menu_delegate_->IsTriggerableEvent(menu, e) :
    892       MenuDelegate::IsTriggerableEvent(menu, e);
    893 }
    894 
    895 bool WrenchMenu::GetDropFormats(
    896       MenuItemView* menu,
    897       int* formats,
    898       std::set<ui::OSExchangeData::CustomFormat>* custom_formats) {
    899   CreateBookmarkMenu();
    900   return bookmark_menu_delegate_.get() &&
    901       bookmark_menu_delegate_->GetDropFormats(menu, formats, custom_formats);
    902 }
    903 
    904 bool WrenchMenu::AreDropTypesRequired(MenuItemView* menu) {
    905   CreateBookmarkMenu();
    906   return bookmark_menu_delegate_.get() &&
    907       bookmark_menu_delegate_->AreDropTypesRequired(menu);
    908 }
    909 
    910 bool WrenchMenu::CanDrop(MenuItemView* menu,
    911                          const ui::OSExchangeData& data) {
    912   CreateBookmarkMenu();
    913   return bookmark_menu_delegate_.get() &&
    914       bookmark_menu_delegate_->CanDrop(menu, data);
    915 }
    916 
    917 int WrenchMenu::GetDropOperation(
    918     MenuItemView* item,
    919     const ui::DropTargetEvent& event,
    920     DropPosition* position) {
    921   return is_bookmark_command(item->GetCommand()) ?
    922       bookmark_menu_delegate_->GetDropOperation(item, event, position) :
    923       ui::DragDropTypes::DRAG_NONE;
    924 }
    925 
    926 int WrenchMenu::OnPerformDrop(MenuItemView* menu,
    927                               DropPosition position,
    928                               const ui::DropTargetEvent& event) {
    929   if (!is_bookmark_command(menu->GetCommand()))
    930     return ui::DragDropTypes::DRAG_NONE;
    931 
    932   int result = bookmark_menu_delegate_->OnPerformDrop(menu, position, event);
    933   return result;
    934 }
    935 
    936 bool WrenchMenu::ShowContextMenu(MenuItemView* source,
    937                                  int id,
    938                                  const gfx::Point& p,
    939                                  ui::MenuSourceType source_type) {
    940   return is_bookmark_command(id) ?
    941       bookmark_menu_delegate_->ShowContextMenu(source, id, p,
    942                                                source_type) :
    943       false;
    944 }
    945 
    946 bool WrenchMenu::CanDrag(MenuItemView* menu) {
    947   return is_bookmark_command(menu->GetCommand()) ?
    948       bookmark_menu_delegate_->CanDrag(menu) : false;
    949 }
    950 
    951 void WrenchMenu::WriteDragData(MenuItemView* sender,
    952                                ui::OSExchangeData* data) {
    953   DCHECK(is_bookmark_command(sender->GetCommand()));
    954   return bookmark_menu_delegate_->WriteDragData(sender, data);
    955 }
    956 
    957 int WrenchMenu::GetDragOperations(MenuItemView* sender) {
    958   return is_bookmark_command(sender->GetCommand()) ?
    959       bookmark_menu_delegate_->GetDragOperations(sender) :
    960       MenuDelegate::GetDragOperations(sender);
    961 }
    962 
    963 int WrenchMenu::GetMaxWidthForMenu(MenuItemView* menu) {
    964   if (is_bookmark_command(menu->GetCommand()))
    965     return bookmark_menu_delegate_->GetMaxWidthForMenu(menu);
    966   int max_width = -1;
    967   // If recent tabs menu is available, it will decide if |menu| is one of recent
    968   // tabs; if yes, it would return the menu width for recent tabs.
    969   // otherwise, it would return -1.
    970   if (recent_tabs_menu_model_delegate_.get())
    971     max_width = recent_tabs_menu_model_delegate_->GetMaxWidthForMenu(menu);
    972   if (max_width == -1)
    973     max_width = MenuDelegate::GetMaxWidthForMenu(menu);
    974   return max_width;
    975 }
    976 
    977 bool WrenchMenu::IsItemChecked(int id) const {
    978   if (is_bookmark_command(id))
    979     return false;
    980 
    981   const Entry& entry = id_to_entry_.find(id)->second;
    982   return entry.first->IsItemCheckedAt(entry.second);
    983 }
    984 
    985 bool WrenchMenu::IsCommandEnabled(int id) const {
    986   if (is_bookmark_command(id))
    987     return true;
    988 
    989   if (id == 0)
    990     return false;  // The root item.
    991 
    992   const Entry& entry = id_to_entry_.find(id)->second;
    993   int command_id = entry.first->GetCommandIdAt(entry.second);
    994   // The items representing the cut menu (cut/copy/paste) and zoom menu
    995   // (increment/decrement/reset) are always enabled. The child views of these
    996   // items enabled state updates appropriately.
    997   return command_id == IDC_CUT || command_id == IDC_ZOOM_MINUS ||
    998       entry.first->IsEnabledAt(entry.second);
    999 }
   1000 
   1001 void WrenchMenu::ExecuteCommand(int id, int mouse_event_flags) {
   1002   if (is_bookmark_command(id)) {
   1003     bookmark_menu_delegate_->ExecuteCommand(id, mouse_event_flags);
   1004     return;
   1005   }
   1006 
   1007   // Not a bookmark
   1008   const Entry& entry = id_to_entry_.find(id)->second;
   1009   int command_id = entry.first->GetCommandIdAt(entry.second);
   1010 
   1011   if (command_id == IDC_CUT || command_id == IDC_ZOOM_MINUS) {
   1012     // These items are represented by child views. If ExecuteCommand is invoked
   1013     // it means the user clicked on the area around the buttons and we should
   1014     // not do anyting.
   1015     return;
   1016   }
   1017 
   1018   return entry.first->ActivatedAt(entry.second, mouse_event_flags);
   1019 }
   1020 
   1021 bool WrenchMenu::GetAccelerator(int id, ui::Accelerator* accelerator) {
   1022   if (is_bookmark_command(id))
   1023     return false;
   1024   IDToEntry::iterator ix = id_to_entry_.find(id);
   1025   if (ix == id_to_entry_.end()) {
   1026     // There is no entry for this id.
   1027     return false;
   1028   }
   1029 
   1030   const Entry& entry = ix->second;
   1031   int command_id = entry.first->GetCommandIdAt(entry.second);
   1032   if (command_id == IDC_CUT || command_id == IDC_ZOOM_MINUS) {
   1033     // These have special child views; don't show the accelerator for them.
   1034     return false;
   1035   }
   1036 
   1037   ui::Accelerator menu_accelerator;
   1038   if (!entry.first->GetAcceleratorAt(entry.second, &menu_accelerator))
   1039     return false;
   1040 
   1041   *accelerator = ui::Accelerator(menu_accelerator.key_code(),
   1042                                  menu_accelerator.modifiers());
   1043   return true;
   1044 }
   1045 
   1046 void WrenchMenu::WillShowMenu(MenuItemView* menu) {
   1047   if (menu == bookmark_menu_)
   1048     CreateBookmarkMenu();
   1049 }
   1050 
   1051 void WrenchMenu::WillHideMenu(MenuItemView* menu) {
   1052   // Turns off the fade out animation of the wrench menus if
   1053   // |feedback_menu_item_| is selected.  This excludes the wrench menu itself
   1054   // from the snapshot in the feedback UI.
   1055   if (menu->HasSubmenu() && feedback_menu_item_ &&
   1056       feedback_menu_item_->IsSelected()) {
   1057     // It's okay to just turn off the animation and no to take care the
   1058     // animation back because the menu widget will be recreated next time
   1059     // it's opened. See ToolbarView::RunMenu() and Init() of this class.
   1060     menu->GetSubmenu()->GetWidget()->
   1061         SetVisibilityChangedAnimationsEnabled(false);
   1062   }
   1063 }
   1064 
   1065 void WrenchMenu::BookmarkModelChanged() {
   1066   DCHECK(bookmark_menu_delegate_.get());
   1067   if (!bookmark_menu_delegate_->is_mutating_model())
   1068     root_->Cancel();
   1069 }
   1070 
   1071 void WrenchMenu::Observe(int type,
   1072                          const content::NotificationSource& source,
   1073                          const content::NotificationDetails& details) {
   1074   switch (type) {
   1075     case chrome::NOTIFICATION_GLOBAL_ERRORS_CHANGED:
   1076       // A change in the global errors list can add or remove items from the
   1077       // menu. Close the menu to avoid have a stale menu on-screen.
   1078       root_->Cancel();
   1079       break;
   1080     default:
   1081       NOTREACHED();
   1082   }
   1083 }
   1084 
   1085 void WrenchMenu::PopulateMenu(MenuItemView* parent,
   1086                               MenuModel* model,
   1087                               int* next_id) {
   1088   for (int i = 0, max = model->GetItemCount(); i < max; ++i) {
   1089     // The button container menu items have a special height which we have to
   1090     // use instead of the normal height.
   1091     int height = 0;
   1092     if (use_new_menu_ &&
   1093         (model->GetCommandIdAt(i) == IDC_CUT ||
   1094          model->GetCommandIdAt(i) == IDC_ZOOM_MINUS))
   1095       height = kMenuItemContainingButtonsHeight;
   1096 
   1097     MenuItemView* item = AppendMenuItem(
   1098         parent, model, i, model->GetTypeAt(i), next_id, height);
   1099 
   1100     if (model->GetTypeAt(i) == MenuModel::TYPE_SUBMENU) {
   1101       bool is_recent_tabs_menu =
   1102           model->GetCommandIdAt(i) == IDC_RECENT_TABS_MENU;
   1103       if (is_recent_tabs_menu)
   1104         first_recent_tabs_command_id_ = *next_id;
   1105       PopulateMenu(item, model->GetSubmenuModelAt(i), next_id);
   1106       if (is_recent_tabs_menu)
   1107         last_recent_tabs_command_id_ = *next_id - 1;
   1108     }
   1109 
   1110     const ui::NativeTheme* native_theme = GetNativeTheme();
   1111 
   1112     switch (model->GetCommandIdAt(i)) {
   1113       case IDC_CUT:
   1114         DCHECK_EQ(MenuModel::TYPE_COMMAND, model->GetTypeAt(i));
   1115         DCHECK_LT(i + 2, max);
   1116         DCHECK_EQ(IDC_COPY, model->GetCommandIdAt(i + 1));
   1117         DCHECK_EQ(IDC_PASTE, model->GetCommandIdAt(i + 2));
   1118         item->SetTitle(l10n_util::GetStringUTF16(IDS_EDIT2));
   1119         item->AddChildView(new CutCopyPasteView(this, model, native_theme,
   1120                                                 i, i + 1, i + 2));
   1121         i += 2;
   1122         break;
   1123 
   1124       case IDC_ZOOM_MINUS:
   1125         DCHECK_EQ(MenuModel::TYPE_COMMAND, model->GetTypeAt(i));
   1126         DCHECK_EQ(IDC_ZOOM_PLUS, model->GetCommandIdAt(i + 1));
   1127         DCHECK_EQ(IDC_FULLSCREEN, model->GetCommandIdAt(i + 2));
   1128         item->SetTitle(l10n_util::GetStringUTF16(IDS_ZOOM_MENU2));
   1129         item->AddChildView(new ZoomView(this, model, native_theme,
   1130                                         i, i + 1, i + 2));
   1131         i += 2;
   1132         break;
   1133 
   1134       case IDC_BOOKMARKS_MENU:
   1135         DCHECK(!bookmark_menu_);
   1136         bookmark_menu_ = item;
   1137         break;
   1138 
   1139       case IDC_FEEDBACK:
   1140         DCHECK(!feedback_menu_item_);
   1141         feedback_menu_item_ = item;
   1142         break;
   1143 
   1144       case IDC_RECENT_TABS_MENU:
   1145         DCHECK(!recent_tabs_menu_model_delegate_.get());
   1146         recent_tabs_menu_model_delegate_.reset(
   1147             new RecentTabsMenuModelDelegate(model->GetSubmenuModelAt(i),
   1148                                             item));
   1149         break;
   1150 
   1151       default:
   1152         break;
   1153     }
   1154   }
   1155 }
   1156 
   1157 MenuItemView* WrenchMenu::AppendMenuItem(MenuItemView* parent,
   1158                                          MenuModel* model,
   1159                                          int index,
   1160                                          MenuModel::ItemType menu_type,
   1161                                          int* next_id,
   1162                                          int height) {
   1163   int id = (*next_id)++;
   1164 
   1165   id_to_entry_[id].first = model;
   1166   id_to_entry_[id].second = index;
   1167 
   1168   MenuItemView* menu_item = NULL;
   1169   if (height > 0) {
   1170     // For menu items with a special menu height we use our special class to be
   1171     // able to modify the item height.
   1172     menu_item = new ButtonContainerMenuItemView(parent, id, height);
   1173     parent->GetSubmenu()->AddChildView(menu_item);
   1174   } else {
   1175     // For all other cases we use the more generic way to add menu items.
   1176     menu_item = parent->AppendMenuItemFromModel(model, index, id);
   1177   }
   1178 
   1179   if (menu_item) {
   1180     // Flush all buttons to the right side of the menu for the new menu type.
   1181     menu_item->set_use_right_margin(!use_new_menu_);
   1182     menu_item->SetVisible(model->IsVisibleAt(index));
   1183 
   1184     if (menu_type == MenuModel::TYPE_COMMAND && model->HasIcons()) {
   1185       gfx::Image icon;
   1186       if (model->GetIconAt(index, &icon))
   1187         menu_item->SetIcon(*icon.ToImageSkia());
   1188     }
   1189   }
   1190 
   1191   return menu_item;
   1192 }
   1193 
   1194 void WrenchMenu::CancelAndEvaluate(MenuModel* model, int index) {
   1195   selected_menu_model_ = model;
   1196   selected_index_ = index;
   1197   root_->Cancel();
   1198 }
   1199 
   1200 void WrenchMenu::CreateBookmarkMenu() {
   1201   if (bookmark_menu_delegate_.get())
   1202     return;  // Already created the menu.
   1203 
   1204   BookmarkModel* model =
   1205       BookmarkModelFactory::GetForProfile(browser_->profile());
   1206   if (!model->loaded())
   1207     return;
   1208 
   1209   model->AddObserver(this);
   1210 
   1211   // TODO(oshima): Replace with views only API.
   1212   views::Widget* parent = views::Widget::GetWidgetForNativeWindow(
   1213       browser_->window()->GetNativeWindow());
   1214   bookmark_menu_delegate_.reset(
   1215       new BookmarkMenuDelegate(browser_,
   1216                                browser_,
   1217                                parent,
   1218                                first_bookmark_command_id_));
   1219   bookmark_menu_delegate_->Init(
   1220       this, bookmark_menu_, model->bookmark_bar_node(), 0,
   1221       BookmarkMenuDelegate::SHOW_PERMANENT_FOLDERS,
   1222       bookmark_utils::LAUNCH_WRENCH_MENU);
   1223 }
   1224