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