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.
5 #include "ui/views/controls/menu/menu_model_adapter.h"
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"
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) {
24 MenuModelAdapter::~MenuModelAdapter() {
27 void MenuModelAdapter::BuildMenu(MenuItemView* 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);
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())
42 menu_map_[menu] = menu_model_;
44 // Repopulate the menu.
45 BuildMenuImpl(menu, menu_model_);
46 menu->ChildrenChanged();
49 MenuItemView* MenuModelAdapter::CreateMenu() {
50 MenuItemView* item = new MenuItemView(this);
56 MenuItemView* MenuModelAdapter::AddMenuItemFromModelAt(ui::MenuModel* model,
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);
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);
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);
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);
87 case ui::MenuModel::TYPE_SEPARATOR:
89 type = MenuItemView::SEPARATOR;
90 separator_style = model->GetSeparatorTypeAt(model_index);
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);
100 type = MenuItemView::NORMAL;
104 return menu->AddMenuItemAt(
110 icon.IsEmpty() ? gfx::ImageSkia() : *icon.ToImageSkia(),
116 MenuItemView* MenuModelAdapter::AppendMenuItemFromModel(ui::MenuModel* model,
120 const int menu_index = menu->HasSubmenu() ?
121 menu->GetSubmenu()->child_count() : 0;
122 return AddMenuItemFromModelAt(model, model_index, menu, menu_index, item_id);
126 MenuItemView* MenuModelAdapter::AppendMenuItem(MenuItemView* menu,
127 ui::MenuModel* model,
129 return AppendMenuItemFromModel(model, index, menu,
130 model->GetCommandIdAt(index));
133 // MenuModelAdapter, MenuDelegate implementation:
135 void MenuModelAdapter::ExecuteCommand(int id) {
136 ui::MenuModel* model = menu_model_;
138 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
139 model->ActivatedAt(index);
146 void MenuModelAdapter::ExecuteCommand(int id, int mouse_event_flags) {
147 ui::MenuModel* model = menu_model_;
149 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
150 model->ActivatedAt(index, mouse_event_flags);
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);
164 bool MenuModelAdapter::GetAccelerator(int id,
165 ui::Accelerator* accelerator) const {
166 ui::MenuModel* model = menu_model_;
168 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
169 return model->GetAcceleratorAt(index, accelerator);
175 base::string16 MenuModelAdapter::GetLabel(int id) const {
176 ui::MenuModel* model = menu_model_;
178 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
179 return model->GetLabelAt(index);
182 return base::string16();
185 const gfx::FontList* MenuModelAdapter::GetLabelFontList(int id) const {
186 ui::MenuModel* model = menu_model_;
188 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
189 const gfx::FontList* font_list = model->GetLabelFontListAt(index);
194 // This line may be reached for the empty menu item.
195 return MenuDelegate::GetLabelFontList(id);
198 bool MenuModelAdapter::IsCommandEnabled(int id) const {
199 ui::MenuModel* model = menu_model_;
201 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
202 return model->IsEnabledAt(index);
208 bool MenuModelAdapter::IsItemChecked(int id) const {
209 ui::MenuModel* model = menu_model_;
211 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
212 return model->IsItemCheckedAt(index);
218 void MenuModelAdapter::SelectionChanged(MenuItemView* menu) {
219 // Ignore selection of the root menu.
220 if (menu == menu->GetRootMenuItem())
223 const int id = menu->GetCommand();
224 ui::MenuModel* model = menu_model_;
226 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
227 model->HighlightChangedTo(index);
234 void MenuModelAdapter::WillShowMenu(MenuItemView* menu) {
235 // Look up the menu model for this menu.
236 const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator =
237 menu_map_.find(menu);
238 if (map_iterator != menu_map_.end()) {
239 map_iterator->second->MenuWillShow();
246 void MenuModelAdapter::WillHideMenu(MenuItemView* menu) {
247 // Look up the menu model for this menu.
248 const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator =
249 menu_map_.find(menu);
250 if (map_iterator != menu_map_.end()) {
251 map_iterator->second->MenuClosed();
258 // MenuModelAdapter, private:
260 void MenuModelAdapter::BuildMenuImpl(MenuItemView* menu, ui::MenuModel* model) {
263 bool has_icons = model->HasIcons();
264 const int item_count = model->GetItemCount();
265 for (int i = 0; i < item_count; ++i) {
266 MenuItemView* item = AppendMenuItem(menu, model, i);
269 item->SetVisible(model->IsVisibleAt(i));
271 if (model->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU) {
273 DCHECK_EQ(MenuItemView::SUBMENU, item->GetType());
274 ui::MenuModel* submodel = model->GetSubmenuModelAt(i);
276 BuildMenuImpl(item, submodel);
277 has_icons = has_icons || item->has_icons();
279 menu_map_[item] = submodel;
283 menu->set_has_icons(has_icons);