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/gfx/image/image.h" 11 #include "ui/views/controls/menu/submenu_view.h" 12 #include "ui/views/views_delegate.h" 13 14 namespace views { 15 16 MenuModelAdapter::MenuModelAdapter(ui::MenuModel* menu_model) 17 : menu_model_(menu_model), 18 triggerable_event_flags_(ui::EF_LEFT_MOUSE_BUTTON | 19 ui::EF_RIGHT_MOUSE_BUTTON) { 20 DCHECK(menu_model); 21 } 22 23 MenuModelAdapter::~MenuModelAdapter() { 24 } 25 26 void MenuModelAdapter::BuildMenu(MenuItemView* menu) { 27 DCHECK(menu); 28 29 // Clear the menu. 30 if (menu->HasSubmenu()) { 31 const int subitem_count = menu->GetSubmenu()->child_count(); 32 for (int i = 0; i < subitem_count; ++i) 33 menu->RemoveMenuItemAt(0); 34 } 35 36 // Leave entries in the map if the menu is being shown. This 37 // allows the map to find the menu model of submenus being closed 38 // so ui::MenuModel::MenuClosed() can be called. 39 if (!menu->GetMenuController()) 40 menu_map_.clear(); 41 menu_map_[menu] = menu_model_; 42 43 // Repopulate the menu. 44 BuildMenuImpl(menu, menu_model_); 45 menu->ChildrenChanged(); 46 } 47 48 MenuItemView* MenuModelAdapter::CreateMenu() { 49 MenuItemView* item = new MenuItemView(this); 50 BuildMenu(item); 51 return item; 52 } 53 54 // Static. 55 MenuItemView* MenuModelAdapter::AddMenuItemFromModelAt(ui::MenuModel* model, 56 int model_index, 57 MenuItemView* menu, 58 int menu_index, 59 int item_id) { 60 gfx::Image icon; 61 model->GetIconAt(model_index, &icon); 62 string16 label, sublabel, minor_text; 63 ui::MenuSeparatorType separator_style = ui::NORMAL_SEPARATOR; 64 MenuItemView::Type type; 65 ui::MenuModel::ItemType menu_type = model->GetTypeAt(model_index); 66 67 switch (menu_type) { 68 case ui::MenuModel::TYPE_COMMAND: 69 type = MenuItemView::NORMAL; 70 label = model->GetLabelAt(model_index); 71 sublabel = model->GetSublabelAt(model_index); 72 minor_text = model->GetMinorTextAt(model_index); 73 break; 74 case ui::MenuModel::TYPE_CHECK: 75 type = MenuItemView::CHECKBOX; 76 label = model->GetLabelAt(model_index); 77 sublabel = model->GetSublabelAt(model_index); 78 minor_text = model->GetMinorTextAt(model_index); 79 break; 80 case ui::MenuModel::TYPE_RADIO: 81 type = MenuItemView::RADIO; 82 label = model->GetLabelAt(model_index); 83 sublabel = model->GetSublabelAt(model_index); 84 minor_text = model->GetMinorTextAt(model_index); 85 break; 86 case ui::MenuModel::TYPE_SEPARATOR: 87 icon = gfx::Image(); 88 type = MenuItemView::SEPARATOR; 89 separator_style = model->GetSeparatorTypeAt(model_index); 90 break; 91 case ui::MenuModel::TYPE_SUBMENU: 92 type = MenuItemView::SUBMENU; 93 label = model->GetLabelAt(model_index); 94 sublabel = model->GetSublabelAt(model_index); 95 minor_text = model->GetMinorTextAt(model_index); 96 break; 97 default: 98 NOTREACHED(); 99 type = MenuItemView::NORMAL; 100 break; 101 } 102 103 return menu->AddMenuItemAt( 104 menu_index, 105 item_id, 106 label, 107 sublabel, 108 minor_text, 109 icon.IsEmpty() ? gfx::ImageSkia() : *icon.ToImageSkia(), 110 type, 111 separator_style); 112 } 113 114 // Static. 115 MenuItemView* MenuModelAdapter::AppendMenuItemFromModel(ui::MenuModel* model, 116 int model_index, 117 MenuItemView* menu, 118 int item_id) { 119 const int menu_index = menu->HasSubmenu() ? 120 menu->GetSubmenu()->child_count() : 0; 121 return AddMenuItemFromModelAt(model, model_index, menu, menu_index, item_id); 122 } 123 124 125 MenuItemView* MenuModelAdapter::AppendMenuItem(MenuItemView* menu, 126 ui::MenuModel* model, 127 int index) { 128 return AppendMenuItemFromModel(model, index, menu, 129 model->GetCommandIdAt(index)); 130 } 131 132 // MenuModelAdapter, MenuDelegate implementation: 133 134 void MenuModelAdapter::ExecuteCommand(int id) { 135 ui::MenuModel* model = menu_model_; 136 int index = 0; 137 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) { 138 model->ActivatedAt(index); 139 return; 140 } 141 142 NOTREACHED(); 143 } 144 145 void MenuModelAdapter::ExecuteCommand(int id, int mouse_event_flags) { 146 ui::MenuModel* model = menu_model_; 147 int index = 0; 148 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) { 149 model->ActivatedAt(index, mouse_event_flags); 150 return; 151 } 152 153 NOTREACHED(); 154 } 155 156 bool MenuModelAdapter::IsTriggerableEvent(MenuItemView* source, 157 const ui::Event& e) { 158 return e.type() == ui::ET_GESTURE_TAP || 159 e.type() == ui::ET_GESTURE_TAP_DOWN || 160 (e.IsMouseEvent() && (triggerable_event_flags_ & e.flags()) != 0); 161 } 162 163 bool MenuModelAdapter::GetAccelerator(int id, 164 ui::Accelerator* accelerator) { 165 ui::MenuModel* model = menu_model_; 166 int index = 0; 167 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) 168 return model->GetAcceleratorAt(index, accelerator); 169 170 NOTREACHED(); 171 return false; 172 } 173 174 string16 MenuModelAdapter::GetLabel(int id) const { 175 ui::MenuModel* model = menu_model_; 176 int index = 0; 177 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) 178 return model->GetLabelAt(index); 179 180 NOTREACHED(); 181 return string16(); 182 } 183 184 const gfx::Font* MenuModelAdapter::GetLabelFont(int id) const { 185 ui::MenuModel* model = menu_model_; 186 int index = 0; 187 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) { 188 const gfx::Font* font = model->GetLabelFontAt(index); 189 if (font) 190 return font; 191 } 192 193 // This line may be reached for the empty menu item. 194 return MenuDelegate::GetLabelFont(id); 195 } 196 197 bool MenuModelAdapter::IsCommandEnabled(int id) const { 198 ui::MenuModel* model = menu_model_; 199 int index = 0; 200 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) 201 return model->IsEnabledAt(index); 202 203 NOTREACHED(); 204 return false; 205 } 206 207 bool MenuModelAdapter::IsItemChecked(int id) const { 208 ui::MenuModel* model = menu_model_; 209 int index = 0; 210 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) 211 return model->IsItemCheckedAt(index); 212 213 NOTREACHED(); 214 return false; 215 } 216 217 void MenuModelAdapter::SelectionChanged(MenuItemView* menu) { 218 // Ignore selection of the root menu. 219 if (menu == menu->GetRootMenuItem()) 220 return; 221 222 const int id = menu->GetCommand(); 223 ui::MenuModel* model = menu_model_; 224 int index = 0; 225 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) { 226 model->HighlightChangedTo(index); 227 return; 228 } 229 230 NOTREACHED(); 231 } 232 233 void MenuModelAdapter::WillShowMenu(MenuItemView* menu) { 234 // Look up the menu model for this menu. 235 const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator = 236 menu_map_.find(menu); 237 if (map_iterator != menu_map_.end()) { 238 map_iterator->second->MenuWillShow(); 239 return; 240 } 241 242 NOTREACHED(); 243 } 244 245 void MenuModelAdapter::WillHideMenu(MenuItemView* menu) { 246 // Look up the menu model for this menu. 247 const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator = 248 menu_map_.find(menu); 249 if (map_iterator != menu_map_.end()) { 250 map_iterator->second->MenuClosed(); 251 return; 252 } 253 254 NOTREACHED(); 255 } 256 257 // MenuModelAdapter, private: 258 259 void MenuModelAdapter::BuildMenuImpl(MenuItemView* menu, ui::MenuModel* model) { 260 DCHECK(menu); 261 DCHECK(model); 262 bool has_icons = model->HasIcons(); 263 const int item_count = model->GetItemCount(); 264 for (int i = 0; i < item_count; ++i) { 265 MenuItemView* item = AppendMenuItem(menu, model, i); 266 267 if (item) 268 item->SetVisible(model->IsVisibleAt(i)); 269 270 if (model->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU) { 271 DCHECK(item); 272 DCHECK_EQ(MenuItemView::SUBMENU, item->GetType()); 273 ui::MenuModel* submodel = model->GetSubmenuModelAt(i); 274 DCHECK(submodel); 275 BuildMenuImpl(item, submodel); 276 has_icons = has_icons || item->has_icons(); 277 278 menu_map_[item] = submodel; 279 } 280 } 281 282 menu->set_has_icons(has_icons); 283 } 284 285 } // namespace views 286