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::RemoveTrailingSeparators() {
144 while (!items_
.empty() && items_
.back().type
== TYPE_SEPARATOR
)
149 void SimpleMenuModel::AddButtonItem(int command_id
,
150 ButtonMenuItemModel
* model
) {
151 Item item
= { command_id
, base::string16(), base::string16(),
152 base::string16(), gfx::Image(), TYPE_BUTTON_ITEM
, -1, NULL
,
153 model
, NORMAL_SEPARATOR
};
157 void SimpleMenuModel::AddSubMenu(int command_id
,
158 const base::string16
& label
,
160 Item item
= { command_id
, label
, base::string16(), base::string16(),
161 gfx::Image(), TYPE_SUBMENU
, -1, model
, NULL
, NORMAL_SEPARATOR
};
165 void SimpleMenuModel::AddSubMenuWithStringId(int command_id
,
166 int string_id
, MenuModel
* model
) {
167 AddSubMenu(command_id
, l10n_util::GetStringUTF16(string_id
), model
);
170 void SimpleMenuModel::InsertItemAt(int index
,
172 const base::string16
& label
) {
173 Item item
= { command_id
, label
, base::string16(), base::string16(),
174 gfx::Image(), TYPE_COMMAND
, -1, NULL
, NULL
, NORMAL_SEPARATOR
};
175 InsertItemAtIndex(item
, index
);
178 void SimpleMenuModel::InsertItemWithStringIdAt(
179 int index
, int command_id
, int string_id
) {
180 InsertItemAt(index
, command_id
, l10n_util::GetStringUTF16(string_id
));
183 void SimpleMenuModel::InsertSeparatorAt(int index
,
184 MenuSeparatorType separator_type
) {
185 #if !defined(USE_AURA)
186 if (separator_type
!= NORMAL_SEPARATOR
) {
190 Item item
= { kSeparatorId
, base::string16(), base::string16(),
191 base::string16(), gfx::Image(), TYPE_SEPARATOR
, -1, NULL
, NULL
,
193 InsertItemAtIndex(item
, index
);
196 void SimpleMenuModel::InsertCheckItemAt(int index
,
198 const base::string16
& label
) {
199 Item item
= { command_id
, label
, base::string16(), base::string16(),
200 gfx::Image(), TYPE_CHECK
, -1, NULL
, NULL
, NORMAL_SEPARATOR
};
201 InsertItemAtIndex(item
, index
);
204 void SimpleMenuModel::InsertCheckItemWithStringIdAt(
205 int index
, int command_id
, int string_id
) {
206 InsertCheckItemAt(index
, command_id
, l10n_util::GetStringUTF16(string_id
));
209 void SimpleMenuModel::InsertRadioItemAt(int index
,
211 const base::string16
& label
,
213 Item item
= { command_id
, label
, base::string16(), base::string16(),
214 gfx::Image(), TYPE_RADIO
, group_id
, NULL
, NULL
,
216 InsertItemAtIndex(item
, index
);
219 void SimpleMenuModel::InsertRadioItemWithStringIdAt(
220 int index
, int command_id
, int string_id
, int group_id
) {
222 index
, command_id
, l10n_util::GetStringUTF16(string_id
), group_id
);
225 void SimpleMenuModel::InsertSubMenuAt(int index
,
227 const base::string16
& label
,
229 Item item
= { command_id
, label
, base::string16(), base::string16(),
230 gfx::Image(), TYPE_SUBMENU
, -1, model
, NULL
,
232 InsertItemAtIndex(item
, index
);
235 void SimpleMenuModel::InsertSubMenuWithStringIdAt(
236 int index
, int command_id
, int string_id
, MenuModel
* model
) {
237 InsertSubMenuAt(index
, command_id
, l10n_util::GetStringUTF16(string_id
),
241 void SimpleMenuModel::RemoveItemAt(int index
) {
242 items_
.erase(items_
.begin() + ValidateItemIndex(index
));
246 void SimpleMenuModel::SetIcon(int index
, const gfx::Image
& icon
) {
247 items_
[ValidateItemIndex(index
)].icon
= icon
;
251 void SimpleMenuModel::SetSublabel(int index
, const base::string16
& sublabel
) {
252 items_
[ValidateItemIndex(index
)].sublabel
= sublabel
;
256 void SimpleMenuModel::SetMinorText(int index
,
257 const base::string16
& minor_text
) {
258 items_
[ValidateItemIndex(index
)].minor_text
= minor_text
;
261 void SimpleMenuModel::Clear() {
266 int SimpleMenuModel::GetIndexOfCommandId(int command_id
) {
267 for (ItemVector::iterator i
= items_
.begin(); i
!= items_
.end(); ++i
) {
268 if (i
->command_id
== command_id
)
269 return static_cast<int>(std::distance(items_
.begin(), i
));
274 ////////////////////////////////////////////////////////////////////////////////
275 // SimpleMenuModel, MenuModel implementation:
277 bool SimpleMenuModel::HasIcons() const {
278 for (ItemVector::const_iterator i
= items_
.begin(); i
!= items_
.end(); ++i
) {
279 if (!i
->icon
.IsEmpty())
286 int SimpleMenuModel::GetItemCount() const {
287 return static_cast<int>(items_
.size());
290 MenuModel::ItemType
SimpleMenuModel::GetTypeAt(int index
) const {
291 return items_
[ValidateItemIndex(index
)].type
;
294 ui::MenuSeparatorType
SimpleMenuModel::GetSeparatorTypeAt(int index
) const {
295 return items_
[ValidateItemIndex(index
)].separator_type
;
298 int SimpleMenuModel::GetCommandIdAt(int index
) const {
299 return items_
[ValidateItemIndex(index
)].command_id
;
302 base::string16
SimpleMenuModel::GetLabelAt(int index
) const {
303 if (IsItemDynamicAt(index
))
304 return delegate_
->GetLabelForCommandId(GetCommandIdAt(index
));
305 return items_
[ValidateItemIndex(index
)].label
;
308 base::string16
SimpleMenuModel::GetSublabelAt(int index
) const {
309 if (IsItemDynamicAt(index
))
310 return delegate_
->GetSublabelForCommandId(GetCommandIdAt(index
));
311 return items_
[ValidateItemIndex(index
)].sublabel
;
314 base::string16
SimpleMenuModel::GetMinorTextAt(int index
) const {
315 if (IsItemDynamicAt(index
))
316 return delegate_
->GetMinorTextForCommandId(GetCommandIdAt(index
));
317 return items_
[ValidateItemIndex(index
)].minor_text
;
320 bool SimpleMenuModel::IsItemDynamicAt(int index
) const {
322 return delegate_
->IsItemForCommandIdDynamic(GetCommandIdAt(index
));
326 bool SimpleMenuModel::GetAcceleratorAt(int index
,
327 ui::Accelerator
* accelerator
) const {
329 return delegate_
->GetAcceleratorForCommandId(GetCommandIdAt(index
),
335 bool SimpleMenuModel::IsItemCheckedAt(int index
) const {
338 MenuModel::ItemType item_type
= GetTypeAt(index
);
339 return (item_type
== TYPE_CHECK
|| item_type
== TYPE_RADIO
) ?
340 delegate_
->IsCommandIdChecked(GetCommandIdAt(index
)) : false;
343 int SimpleMenuModel::GetGroupIdAt(int index
) const {
344 return items_
[ValidateItemIndex(index
)].group_id
;
347 bool SimpleMenuModel::GetIconAt(int index
, gfx::Image
* icon
) {
348 if (IsItemDynamicAt(index
))
349 return delegate_
->GetIconForCommandId(GetCommandIdAt(index
), icon
);
351 ValidateItemIndex(index
);
352 if (items_
[index
].icon
.IsEmpty())
355 *icon
= items_
[index
].icon
;
359 ButtonMenuItemModel
* SimpleMenuModel::GetButtonMenuItemAt(int index
) const {
360 return items_
[ValidateItemIndex(index
)].button_model
;
363 bool SimpleMenuModel::IsEnabledAt(int index
) const {
364 int command_id
= GetCommandIdAt(index
);
365 if (!delegate_
|| command_id
== kSeparatorId
|| GetButtonMenuItemAt(index
))
367 return delegate_
->IsCommandIdEnabled(command_id
);
370 bool SimpleMenuModel::IsVisibleAt(int index
) const {
371 int command_id
= GetCommandIdAt(index
);
372 if (!delegate_
|| command_id
== kSeparatorId
|| GetButtonMenuItemAt(index
))
374 return delegate_
->IsCommandIdVisible(command_id
);
377 void SimpleMenuModel::HighlightChangedTo(int index
) {
379 delegate_
->CommandIdHighlighted(GetCommandIdAt(index
));
382 void SimpleMenuModel::ActivatedAt(int index
) {
384 delegate_
->ExecuteCommand(GetCommandIdAt(index
), 0);
387 void SimpleMenuModel::ActivatedAt(int index
, int event_flags
) {
389 delegate_
->ExecuteCommand(GetCommandIdAt(index
), event_flags
);
392 MenuModel
* SimpleMenuModel::GetSubmenuModelAt(int index
) const {
393 return items_
[ValidateItemIndex(index
)].submenu
;
396 void SimpleMenuModel::MenuWillShow() {
398 delegate_
->MenuWillShow(this);
401 void SimpleMenuModel::MenuClosed() {
402 // Due to how menus work on the different platforms, ActivatedAt will be
403 // called after this. It's more convenient for the delegate to be called
404 // afterwards though, so post a task.
405 base::MessageLoop::current()->PostTask(
407 base::Bind(&SimpleMenuModel::OnMenuClosed
, method_factory_
.GetWeakPtr()));
410 void SimpleMenuModel::SetMenuModelDelegate(
411 ui::MenuModelDelegate
* menu_model_delegate
) {
412 menu_model_delegate_
= menu_model_delegate
;
415 MenuModelDelegate
* SimpleMenuModel::GetMenuModelDelegate() const {
416 return menu_model_delegate_
;
419 void SimpleMenuModel::OnMenuClosed() {
421 delegate_
->MenuClosed(this);
424 ////////////////////////////////////////////////////////////////////////////////
425 // SimpleMenuModel, Protected:
427 void SimpleMenuModel::MenuItemsChanged() {
430 ////////////////////////////////////////////////////////////////////////////////
431 // SimpleMenuModel, Private:
433 int SimpleMenuModel::ValidateItemIndex(int index
) const {
435 CHECK_LT(static_cast<size_t>(index
), items_
.size());
439 void SimpleMenuModel::AppendItem(const Item
& item
) {
441 items_
.push_back(item
);
445 void SimpleMenuModel::InsertItemAtIndex(const Item
& item
, int index
) {
447 items_
.insert(items_
.begin() + index
, item
);
451 void SimpleMenuModel::ValidateItem(const Item
& item
) {
453 if (item
.type
== TYPE_SEPARATOR
) {
454 DCHECK_EQ(item
.command_id
, kSeparatorId
);
456 DCHECK_GE(item
.command_id
, 0);