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/base/models/simple_menu_model.h"
8 #include "base/message_loop/message_loop.h"
9 #include "ui/base/l10n/l10n_util.h"
10 #include "ui/gfx/image/image.h"
14 const int kSeparatorId
= -1;
16 struct SimpleMenuModel::Item
{
19 base::string16 sublabel
;
20 base::string16 minor_text
;
25 ButtonMenuItemModel
* button_model
;
26 MenuSeparatorType separator_type
;
29 ////////////////////////////////////////////////////////////////////////////////
30 // SimpleMenuModel::Delegate, public:
32 bool SimpleMenuModel::Delegate::IsCommandIdVisible(int command_id
) const {
36 bool SimpleMenuModel::Delegate::IsItemForCommandIdDynamic(
37 int command_id
) const {
41 base::string16
SimpleMenuModel::Delegate::GetLabelForCommandId(
42 int command_id
) const {
43 return base::string16();
46 base::string16
SimpleMenuModel::Delegate::GetSublabelForCommandId(
47 int command_id
) const {
48 return base::string16();
51 base::string16
SimpleMenuModel::Delegate::GetMinorTextForCommandId(
52 int command_id
) const {
53 return base::string16();
56 bool SimpleMenuModel::Delegate::GetIconForCommandId(
57 int command_id
, gfx::Image
* image_skia
) const {
61 void SimpleMenuModel::Delegate::CommandIdHighlighted(int command_id
) {
64 void SimpleMenuModel::Delegate::ExecuteCommand(
65 int command_id
, int event_flags
) {
66 ExecuteCommand(command_id
, event_flags
);
69 void SimpleMenuModel::Delegate::MenuWillShow(SimpleMenuModel
* /*source*/) {
72 void SimpleMenuModel::Delegate::MenuClosed(SimpleMenuModel
* /*source*/) {
75 ////////////////////////////////////////////////////////////////////////////////
76 // SimpleMenuModel, public:
78 SimpleMenuModel::SimpleMenuModel(Delegate
* delegate
)
79 : delegate_(delegate
),
80 menu_model_delegate_(NULL
),
81 method_factory_(this) {
84 SimpleMenuModel::~SimpleMenuModel() {
87 void SimpleMenuModel::AddItem(int command_id
, const base::string16
& label
) {
88 Item item
= { command_id
, label
, base::string16(), base::string16(),
89 gfx::Image(), TYPE_COMMAND
, -1, NULL
, NULL
, NORMAL_SEPARATOR
};
93 void SimpleMenuModel::AddItemWithStringId(int command_id
, int string_id
) {
94 AddItem(command_id
, l10n_util::GetStringUTF16(string_id
));
97 void SimpleMenuModel::AddCheckItem(int command_id
,
98 const base::string16
& label
) {
99 Item item
= { command_id
, label
, base::string16(), base::string16(),
100 gfx::Image(), TYPE_CHECK
, -1, NULL
, NULL
, NORMAL_SEPARATOR
};
104 void SimpleMenuModel::AddCheckItemWithStringId(int command_id
, int string_id
) {
105 AddCheckItem(command_id
, l10n_util::GetStringUTF16(string_id
));
108 void SimpleMenuModel::AddRadioItem(int command_id
,
109 const base::string16
& label
,
111 Item item
= { command_id
, label
, base::string16(), base::string16(),
112 gfx::Image(), TYPE_RADIO
, group_id
, NULL
, NULL
,
117 void SimpleMenuModel::AddRadioItemWithStringId(int command_id
, int string_id
,
119 AddRadioItem(command_id
, l10n_util::GetStringUTF16(string_id
), group_id
);
122 void SimpleMenuModel::AddSeparator(MenuSeparatorType separator_type
) {
123 if (items_
.empty()) {
124 if (separator_type
== NORMAL_SEPARATOR
) {
127 DCHECK_EQ(SPACING_SEPARATOR
, separator_type
);
128 } else if (items_
.back().type
== TYPE_SEPARATOR
) {
129 DCHECK_EQ(NORMAL_SEPARATOR
, separator_type
);
130 DCHECK_EQ(NORMAL_SEPARATOR
, items_
.back().separator_type
);
133 #if !defined(USE_AURA)
134 if (separator_type
== SPACING_SEPARATOR
)
137 Item item
= { kSeparatorId
, base::string16(), base::string16(),
138 base::string16(), gfx::Image(), TYPE_SEPARATOR
, -1, NULL
, NULL
,
143 void SimpleMenuModel::AddButtonItem(int command_id
,
144 ButtonMenuItemModel
* model
) {
145 Item item
= { command_id
, base::string16(), base::string16(),
146 base::string16(), gfx::Image(), TYPE_BUTTON_ITEM
, -1, NULL
,
147 model
, NORMAL_SEPARATOR
};
151 void SimpleMenuModel::AddSubMenu(int command_id
,
152 const base::string16
& label
,
154 Item item
= { command_id
, label
, base::string16(), base::string16(),
155 gfx::Image(), TYPE_SUBMENU
, -1, model
, NULL
, NORMAL_SEPARATOR
};
159 void SimpleMenuModel::AddSubMenuWithStringId(int command_id
,
160 int string_id
, MenuModel
* model
) {
161 AddSubMenu(command_id
, l10n_util::GetStringUTF16(string_id
), model
);
164 void SimpleMenuModel::InsertItemAt(int index
,
166 const base::string16
& label
) {
167 Item item
= { command_id
, label
, base::string16(), base::string16(),
168 gfx::Image(), TYPE_COMMAND
, -1, NULL
, NULL
, NORMAL_SEPARATOR
};
169 InsertItemAtIndex(item
, index
);
172 void SimpleMenuModel::InsertItemWithStringIdAt(
173 int index
, int command_id
, int string_id
) {
174 InsertItemAt(index
, command_id
, l10n_util::GetStringUTF16(string_id
));
177 void SimpleMenuModel::InsertSeparatorAt(int index
,
178 MenuSeparatorType separator_type
) {
179 #if !defined(USE_AURA)
180 if (separator_type
!= NORMAL_SEPARATOR
) {
184 Item item
= { kSeparatorId
, base::string16(), base::string16(),
185 base::string16(), gfx::Image(), TYPE_SEPARATOR
, -1, NULL
, NULL
,
187 InsertItemAtIndex(item
, index
);
190 void SimpleMenuModel::InsertCheckItemAt(int index
,
192 const base::string16
& label
) {
193 Item item
= { command_id
, label
, base::string16(), base::string16(),
194 gfx::Image(), TYPE_CHECK
, -1, NULL
, NULL
, NORMAL_SEPARATOR
};
195 InsertItemAtIndex(item
, index
);
198 void SimpleMenuModel::InsertCheckItemWithStringIdAt(
199 int index
, int command_id
, int string_id
) {
200 InsertCheckItemAt(index
, command_id
, l10n_util::GetStringUTF16(string_id
));
203 void SimpleMenuModel::InsertRadioItemAt(int index
,
205 const base::string16
& label
,
207 Item item
= { command_id
, label
, base::string16(), base::string16(),
208 gfx::Image(), TYPE_RADIO
, group_id
, NULL
, NULL
,
210 InsertItemAtIndex(item
, index
);
213 void SimpleMenuModel::InsertRadioItemWithStringIdAt(
214 int index
, int command_id
, int string_id
, int group_id
) {
216 index
, command_id
, l10n_util::GetStringUTF16(string_id
), group_id
);
219 void SimpleMenuModel::InsertSubMenuAt(int index
,
221 const base::string16
& label
,
223 Item item
= { command_id
, label
, base::string16(), base::string16(),
224 gfx::Image(), TYPE_SUBMENU
, -1, model
, NULL
,
226 InsertItemAtIndex(item
, index
);
229 void SimpleMenuModel::InsertSubMenuWithStringIdAt(
230 int index
, int command_id
, int string_id
, MenuModel
* model
) {
231 InsertSubMenuAt(index
, command_id
, l10n_util::GetStringUTF16(string_id
),
235 void SimpleMenuModel::RemoveItemAt(int index
) {
236 items_
.erase(items_
.begin() + ValidateItemIndex(index
));
240 void SimpleMenuModel::SetIcon(int index
, const gfx::Image
& icon
) {
241 items_
[ValidateItemIndex(index
)].icon
= icon
;
245 void SimpleMenuModel::SetSublabel(int index
, const base::string16
& sublabel
) {
246 items_
[ValidateItemIndex(index
)].sublabel
= sublabel
;
250 void SimpleMenuModel::SetMinorText(int index
,
251 const base::string16
& minor_text
) {
252 items_
[ValidateItemIndex(index
)].minor_text
= minor_text
;
255 void SimpleMenuModel::Clear() {
260 int SimpleMenuModel::GetIndexOfCommandId(int command_id
) {
261 for (ItemVector::iterator i
= items_
.begin(); i
!= items_
.end(); ++i
) {
262 if (i
->command_id
== command_id
)
263 return static_cast<int>(std::distance(items_
.begin(), i
));
268 ////////////////////////////////////////////////////////////////////////////////
269 // SimpleMenuModel, MenuModel implementation:
271 bool SimpleMenuModel::HasIcons() const {
272 for (ItemVector::const_iterator i
= items_
.begin(); i
!= items_
.end(); ++i
) {
273 if (!i
->icon
.IsEmpty())
280 int SimpleMenuModel::GetItemCount() const {
281 return static_cast<int>(items_
.size());
284 MenuModel::ItemType
SimpleMenuModel::GetTypeAt(int index
) const {
285 return items_
[ValidateItemIndex(index
)].type
;
288 ui::MenuSeparatorType
SimpleMenuModel::GetSeparatorTypeAt(int index
) const {
289 return items_
[ValidateItemIndex(index
)].separator_type
;
292 int SimpleMenuModel::GetCommandIdAt(int index
) const {
293 return items_
[ValidateItemIndex(index
)].command_id
;
296 base::string16
SimpleMenuModel::GetLabelAt(int index
) const {
297 if (IsItemDynamicAt(index
))
298 return delegate_
->GetLabelForCommandId(GetCommandIdAt(index
));
299 return items_
[ValidateItemIndex(index
)].label
;
302 base::string16
SimpleMenuModel::GetSublabelAt(int index
) const {
303 if (IsItemDynamicAt(index
))
304 return delegate_
->GetSublabelForCommandId(GetCommandIdAt(index
));
305 return items_
[ValidateItemIndex(index
)].sublabel
;
308 base::string16
SimpleMenuModel::GetMinorTextAt(int index
) const {
309 if (IsItemDynamicAt(index
))
310 return delegate_
->GetMinorTextForCommandId(GetCommandIdAt(index
));
311 return items_
[ValidateItemIndex(index
)].minor_text
;
314 bool SimpleMenuModel::IsItemDynamicAt(int index
) const {
316 return delegate_
->IsItemForCommandIdDynamic(GetCommandIdAt(index
));
320 bool SimpleMenuModel::GetAcceleratorAt(int index
,
321 ui::Accelerator
* accelerator
) const {
323 return delegate_
->GetAcceleratorForCommandId(GetCommandIdAt(index
),
329 bool SimpleMenuModel::IsItemCheckedAt(int index
) const {
332 MenuModel::ItemType item_type
= GetTypeAt(index
);
333 return (item_type
== TYPE_CHECK
|| item_type
== TYPE_RADIO
) ?
334 delegate_
->IsCommandIdChecked(GetCommandIdAt(index
)) : false;
337 int SimpleMenuModel::GetGroupIdAt(int index
) const {
338 return items_
[ValidateItemIndex(index
)].group_id
;
341 bool SimpleMenuModel::GetIconAt(int index
, gfx::Image
* icon
) {
342 if (IsItemDynamicAt(index
))
343 return delegate_
->GetIconForCommandId(GetCommandIdAt(index
), icon
);
345 ValidateItemIndex(index
);
346 if (items_
[index
].icon
.IsEmpty())
349 *icon
= items_
[index
].icon
;
353 ButtonMenuItemModel
* SimpleMenuModel::GetButtonMenuItemAt(int index
) const {
354 return items_
[ValidateItemIndex(index
)].button_model
;
357 bool SimpleMenuModel::IsEnabledAt(int index
) const {
358 int command_id
= GetCommandIdAt(index
);
359 if (!delegate_
|| command_id
== kSeparatorId
|| GetButtonMenuItemAt(index
))
361 return delegate_
->IsCommandIdEnabled(command_id
);
364 bool SimpleMenuModel::IsVisibleAt(int index
) const {
365 int command_id
= GetCommandIdAt(index
);
366 if (!delegate_
|| command_id
== kSeparatorId
|| GetButtonMenuItemAt(index
))
368 return delegate_
->IsCommandIdVisible(command_id
);
371 void SimpleMenuModel::HighlightChangedTo(int index
) {
373 delegate_
->CommandIdHighlighted(GetCommandIdAt(index
));
376 void SimpleMenuModel::ActivatedAt(int index
) {
378 delegate_
->ExecuteCommand(GetCommandIdAt(index
), 0);
381 void SimpleMenuModel::ActivatedAt(int index
, int event_flags
) {
383 delegate_
->ExecuteCommand(GetCommandIdAt(index
), event_flags
);
386 MenuModel
* SimpleMenuModel::GetSubmenuModelAt(int index
) const {
387 return items_
[ValidateItemIndex(index
)].submenu
;
390 void SimpleMenuModel::MenuWillShow() {
392 delegate_
->MenuWillShow(this);
395 void SimpleMenuModel::MenuClosed() {
396 // Due to how menus work on the different platforms, ActivatedAt will be
397 // called after this. It's more convenient for the delegate to be called
398 // afterwards though, so post a task.
399 base::MessageLoop::current()->PostTask(
401 base::Bind(&SimpleMenuModel::OnMenuClosed
, method_factory_
.GetWeakPtr()));
404 void SimpleMenuModel::SetMenuModelDelegate(
405 ui::MenuModelDelegate
* menu_model_delegate
) {
406 menu_model_delegate_
= menu_model_delegate
;
409 MenuModelDelegate
* SimpleMenuModel::GetMenuModelDelegate() const {
410 return menu_model_delegate_
;
413 void SimpleMenuModel::OnMenuClosed() {
415 delegate_
->MenuClosed(this);
418 ////////////////////////////////////////////////////////////////////////////////
419 // SimpleMenuModel, Protected:
421 void SimpleMenuModel::MenuItemsChanged() {
424 ////////////////////////////////////////////////////////////////////////////////
425 // SimpleMenuModel, Private:
427 int SimpleMenuModel::ValidateItemIndex(int index
) const {
429 CHECK_LT(static_cast<size_t>(index
), items_
.size());
433 void SimpleMenuModel::AppendItem(const Item
& item
) {
435 items_
.push_back(item
);
439 void SimpleMenuModel::InsertItemAtIndex(const Item
& item
, int index
) {
441 items_
.insert(items_
.begin() + index
, item
);
445 void SimpleMenuModel::ValidateItem(const Item
& item
) {
447 if (item
.type
== TYPE_SEPARATOR
) {
448 DCHECK_EQ(item
.command_id
, kSeparatorId
);
450 DCHECK_GE(item
.command_id
, 0);