Home | History | Annotate | Download | only in menu
      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 "ui/views/controls/menu/menu_model_adapter.h"
      6 
      7 #include "base/logging.h"
      8 #include "ui/base/l10n/l10n_util.h"
      9 #include "ui/base/models/menu_model.h"
     10 #include "ui/views/controls/menu/submenu_view.h"
     11 #include "ui/views/views_delegate.h"
     12 
     13 namespace views {
     14 
     15 MenuModelAdapter::MenuModelAdapter(ui::MenuModel* menu_model)
     16     : menu_model_(menu_model),
     17       triggerable_event_flags_(ui::EF_LEFT_MOUSE_BUTTON |
     18                                ui::EF_RIGHT_MOUSE_BUTTON) {
     19   DCHECK(menu_model);
     20 }
     21 
     22 MenuModelAdapter::~MenuModelAdapter() {
     23 }
     24 
     25 void MenuModelAdapter::BuildMenu(MenuItemView* menu) {
     26   DCHECK(menu);
     27 
     28   // Clear the menu.
     29   if (menu->HasSubmenu()) {
     30     const int subitem_count = menu->GetSubmenu()->child_count();
     31     for (int i = 0; i < subitem_count; ++i)
     32       menu->RemoveMenuItemAt(0);
     33   }
     34 
     35   // Leave entries in the map if the menu is being shown.  This
     36   // allows the map to find the menu model of submenus being closed
     37   // so ui::MenuModel::MenuClosed() can be called.
     38   if (!menu->GetMenuController())
     39     menu_map_.clear();
     40   menu_map_[menu] = menu_model_;
     41 
     42   // Repopulate the menu.
     43   BuildMenuImpl(menu, menu_model_);
     44   menu->ChildrenChanged();
     45 }
     46 
     47 MenuItemView* MenuModelAdapter::CreateMenu() {
     48   MenuItemView* item = new MenuItemView(this);
     49   BuildMenu(item);
     50   return item;
     51 }
     52 
     53 MenuItemView* MenuModelAdapter::AppendMenuItem(MenuItemView* menu,
     54                                                ui::MenuModel* model,
     55                                                int index) {
     56   return menu->AppendMenuItemFromModel(model, index,
     57                                        model->GetCommandIdAt(index));
     58 }
     59 
     60 // MenuModelAdapter, MenuDelegate implementation:
     61 
     62 void MenuModelAdapter::ExecuteCommand(int id) {
     63   ui::MenuModel* model = menu_model_;
     64   int index = 0;
     65   if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
     66     model->ActivatedAt(index);
     67     return;
     68   }
     69 
     70   NOTREACHED();
     71 }
     72 
     73 void MenuModelAdapter::ExecuteCommand(int id, int mouse_event_flags) {
     74   ui::MenuModel* model = menu_model_;
     75   int index = 0;
     76   if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
     77     model->ActivatedAt(index, mouse_event_flags);
     78     return;
     79   }
     80 
     81   NOTREACHED();
     82 }
     83 
     84 bool MenuModelAdapter::IsTriggerableEvent(MenuItemView* source,
     85                                           const ui::Event& e) {
     86   return e.type() == ui::ET_GESTURE_TAP ||
     87          e.type() == ui::ET_GESTURE_TAP_DOWN ||
     88          (e.IsMouseEvent() && (triggerable_event_flags_ & e.flags()) != 0);
     89 }
     90 
     91 bool MenuModelAdapter::GetAccelerator(int id,
     92                                       ui::Accelerator* accelerator) {
     93   ui::MenuModel* model = menu_model_;
     94   int index = 0;
     95   if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
     96     return model->GetAcceleratorAt(index, accelerator);
     97 
     98   NOTREACHED();
     99   return false;
    100 }
    101 
    102 string16 MenuModelAdapter::GetLabel(int id) const {
    103   ui::MenuModel* model = menu_model_;
    104   int index = 0;
    105   if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
    106     return model->GetLabelAt(index);
    107 
    108   NOTREACHED();
    109   return string16();
    110 }
    111 
    112 const gfx::Font* MenuModelAdapter::GetLabelFont(int id) const {
    113   ui::MenuModel* model = menu_model_;
    114   int index = 0;
    115   if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
    116     const gfx::Font* font = model->GetLabelFontAt(index);
    117     if (font)
    118       return font;
    119   }
    120 
    121   // This line may be reached for the empty menu item.
    122   return MenuDelegate::GetLabelFont(id);
    123 }
    124 
    125 bool MenuModelAdapter::IsCommandEnabled(int id) const {
    126   ui::MenuModel* model = menu_model_;
    127   int index = 0;
    128   if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
    129     return model->IsEnabledAt(index);
    130 
    131   NOTREACHED();
    132   return false;
    133 }
    134 
    135 bool MenuModelAdapter::IsItemChecked(int id) const {
    136   ui::MenuModel* model = menu_model_;
    137   int index = 0;
    138   if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
    139     return model->IsItemCheckedAt(index);
    140 
    141   NOTREACHED();
    142   return false;
    143 }
    144 
    145 void MenuModelAdapter::SelectionChanged(MenuItemView* menu) {
    146   // Ignore selection of the root menu.
    147   if (menu == menu->GetRootMenuItem())
    148     return;
    149 
    150   const int id = menu->GetCommand();
    151   ui::MenuModel* model = menu_model_;
    152   int index = 0;
    153   if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
    154     model->HighlightChangedTo(index);
    155     return;
    156   }
    157 
    158   NOTREACHED();
    159 }
    160 
    161 void MenuModelAdapter::WillShowMenu(MenuItemView* menu) {
    162   // Look up the menu model for this menu.
    163   const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator =
    164       menu_map_.find(menu);
    165   if (map_iterator != menu_map_.end()) {
    166     map_iterator->second->MenuWillShow();
    167     return;
    168   }
    169 
    170   NOTREACHED();
    171 }
    172 
    173 void MenuModelAdapter::WillHideMenu(MenuItemView* menu) {
    174   // Look up the menu model for this menu.
    175   const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator =
    176       menu_map_.find(menu);
    177   if (map_iterator != menu_map_.end()) {
    178     map_iterator->second->MenuClosed();
    179     return;
    180   }
    181 
    182   NOTREACHED();
    183 }
    184 
    185 // MenuModelAdapter, private:
    186 
    187 void MenuModelAdapter::BuildMenuImpl(MenuItemView* menu, ui::MenuModel* model) {
    188   DCHECK(menu);
    189   DCHECK(model);
    190   bool has_icons = model->HasIcons();
    191   const int item_count = model->GetItemCount();
    192   for (int i = 0; i < item_count; ++i) {
    193     MenuItemView* item = AppendMenuItem(menu, model, i);
    194 
    195     if (item)
    196       item->SetVisible(model->IsVisibleAt(i));
    197 
    198     if (model->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU) {
    199       DCHECK(item);
    200       DCHECK_EQ(MenuItemView::SUBMENU, item->GetType());
    201       ui::MenuModel* submodel = model->GetSubmenuModelAt(i);
    202       DCHECK(submodel);
    203       BuildMenuImpl(item, submodel);
    204       has_icons = has_icons || item->has_icons();
    205 
    206       menu_map_[item] = submodel;
    207     }
    208   }
    209 
    210   menu->set_has_icons(has_icons);
    211 }
    212 
    213 }  // namespace views
    214