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::MenuWillShow(SimpleMenuModel
* /*source*/) {
67 void SimpleMenuModel::Delegate::MenuClosed(SimpleMenuModel
* /*source*/) {
70 ////////////////////////////////////////////////////////////////////////////////
71 // SimpleMenuModel, public:
73 SimpleMenuModel::SimpleMenuModel(Delegate
* delegate
)
74 : delegate_(delegate
),
75 menu_model_delegate_(NULL
),
76 method_factory_(this) {
79 SimpleMenuModel::~SimpleMenuModel() {
82 void SimpleMenuModel::AddItem(int command_id
, const base::string16
& label
) {
83 Item item
= { command_id
, label
, base::string16(), base::string16(),
84 gfx::Image(), TYPE_COMMAND
, -1, NULL
, NULL
, NORMAL_SEPARATOR
};
88 void SimpleMenuModel::AddItemWithStringId(int command_id
, int string_id
) {
89 AddItem(command_id
, l10n_util::GetStringUTF16(string_id
));
92 void SimpleMenuModel::AddCheckItem(int command_id
,
93 const base::string16
& label
) {
94 Item item
= { command_id
, label
, base::string16(), base::string16(),
95 gfx::Image(), TYPE_CHECK
, -1, NULL
, NULL
, NORMAL_SEPARATOR
};
99 void SimpleMenuModel::AddCheckItemWithStringId(int command_id
, int string_id
) {
100 AddCheckItem(command_id
, l10n_util::GetStringUTF16(string_id
));
103 void SimpleMenuModel::AddRadioItem(int command_id
,
104 const base::string16
& label
,
106 Item item
= { command_id
, label
, base::string16(), base::string16(),
107 gfx::Image(), TYPE_RADIO
, group_id
, NULL
, NULL
,
112 void SimpleMenuModel::AddRadioItemWithStringId(int command_id
, int string_id
,
114 AddRadioItem(command_id
, l10n_util::GetStringUTF16(string_id
), group_id
);
117 void SimpleMenuModel::AddSeparator(MenuSeparatorType separator_type
) {
118 if (items_
.empty()) {
119 if (separator_type
== NORMAL_SEPARATOR
) {
122 DCHECK_EQ(SPACING_SEPARATOR
, separator_type
);
123 } else if (items_
.back().type
== TYPE_SEPARATOR
) {
124 DCHECK_EQ(NORMAL_SEPARATOR
, separator_type
);
125 DCHECK_EQ(NORMAL_SEPARATOR
, items_
.back().separator_type
);
128 #if !defined(USE_AURA)
129 if (separator_type
== SPACING_SEPARATOR
)
132 Item item
= { kSeparatorId
, base::string16(), base::string16(),
133 base::string16(), gfx::Image(), TYPE_SEPARATOR
, -1, NULL
, NULL
,
138 void SimpleMenuModel::AddButtonItem(int command_id
,
139 ButtonMenuItemModel
* model
) {
140 Item item
= { command_id
, base::string16(), base::string16(),
141 base::string16(), gfx::Image(), TYPE_BUTTON_ITEM
, -1, NULL
,
142 model
, NORMAL_SEPARATOR
};
146 void SimpleMenuModel::AddSubMenu(int command_id
,
147 const base::string16
& label
,
149 Item item
= { command_id
, label
, base::string16(), base::string16(),
150 gfx::Image(), TYPE_SUBMENU
, -1, model
, NULL
, NORMAL_SEPARATOR
};
154 void SimpleMenuModel::AddSubMenuWithStringId(int command_id
,
155 int string_id
, MenuModel
* model
) {
156 AddSubMenu(command_id
, l10n_util::GetStringUTF16(string_id
), model
);
159 void SimpleMenuModel::InsertItemAt(int index
,
161 const base::string16
& label
) {
162 Item item
= { command_id
, label
, base::string16(), base::string16(),
163 gfx::Image(), TYPE_COMMAND
, -1, NULL
, NULL
, NORMAL_SEPARATOR
};
164 InsertItemAtIndex(item
, index
);
167 void SimpleMenuModel::InsertItemWithStringIdAt(
168 int index
, int command_id
, int string_id
) {
169 InsertItemAt(index
, command_id
, l10n_util::GetStringUTF16(string_id
));
172 void SimpleMenuModel::InsertSeparatorAt(int index
,
173 MenuSeparatorType separator_type
) {
174 #if !defined(USE_AURA)
175 if (separator_type
!= NORMAL_SEPARATOR
) {
179 Item item
= { kSeparatorId
, base::string16(), base::string16(),
180 base::string16(), gfx::Image(), TYPE_SEPARATOR
, -1, NULL
, NULL
,
182 InsertItemAtIndex(item
, index
);
185 void SimpleMenuModel::InsertCheckItemAt(int index
,
187 const base::string16
& label
) {
188 Item item
= { command_id
, label
, base::string16(), base::string16(),
189 gfx::Image(), TYPE_CHECK
, -1, NULL
, NULL
, NORMAL_SEPARATOR
};
190 InsertItemAtIndex(item
, index
);
193 void SimpleMenuModel::InsertCheckItemWithStringIdAt(
194 int index
, int command_id
, int string_id
) {
195 InsertCheckItemAt(index
, command_id
, l10n_util::GetStringUTF16(string_id
));
198 void SimpleMenuModel::InsertRadioItemAt(int index
,
200 const base::string16
& label
,
202 Item item
= { command_id
, label
, base::string16(), base::string16(),
203 gfx::Image(), TYPE_RADIO
, group_id
, NULL
, NULL
,
205 InsertItemAtIndex(item
, index
);
208 void SimpleMenuModel::InsertRadioItemWithStringIdAt(
209 int index
, int command_id
, int string_id
, int group_id
) {
211 index
, command_id
, l10n_util::GetStringUTF16(string_id
), group_id
);
214 void SimpleMenuModel::InsertSubMenuAt(int index
,
216 const base::string16
& label
,
218 Item item
= { command_id
, label
, base::string16(), base::string16(),
219 gfx::Image(), TYPE_SUBMENU
, -1, model
, NULL
,
221 InsertItemAtIndex(item
, index
);
224 void SimpleMenuModel::InsertSubMenuWithStringIdAt(
225 int index
, int command_id
, int string_id
, MenuModel
* model
) {
226 InsertSubMenuAt(index
, command_id
, l10n_util::GetStringUTF16(string_id
),
230 void SimpleMenuModel::RemoveItemAt(int index
) {
231 items_
.erase(items_
.begin() + ValidateItemIndex(index
));
235 void SimpleMenuModel::SetIcon(int index
, const gfx::Image
& icon
) {
236 items_
[ValidateItemIndex(index
)].icon
= icon
;
240 void SimpleMenuModel::SetSublabel(int index
, const base::string16
& sublabel
) {
241 items_
[ValidateItemIndex(index
)].sublabel
= sublabel
;
245 void SimpleMenuModel::SetMinorText(int index
,
246 const base::string16
& minor_text
) {
247 items_
[ValidateItemIndex(index
)].minor_text
= minor_text
;
250 void SimpleMenuModel::Clear() {
255 int SimpleMenuModel::GetIndexOfCommandId(int command_id
) {
256 for (ItemVector::iterator i
= items_
.begin(); i
!= items_
.end(); ++i
) {
257 if (i
->command_id
== command_id
)
258 return static_cast<int>(std::distance(items_
.begin(), i
));
263 ////////////////////////////////////////////////////////////////////////////////
264 // SimpleMenuModel, MenuModel implementation:
266 bool SimpleMenuModel::HasIcons() const {
267 for (ItemVector::const_iterator i
= items_
.begin(); i
!= items_
.end(); ++i
) {
268 if (!i
->icon
.IsEmpty())
275 int SimpleMenuModel::GetItemCount() const {
276 return static_cast<int>(items_
.size());
279 MenuModel::ItemType
SimpleMenuModel::GetTypeAt(int index
) const {
280 return items_
[ValidateItemIndex(index
)].type
;
283 ui::MenuSeparatorType
SimpleMenuModel::GetSeparatorTypeAt(int index
) const {
284 return items_
[ValidateItemIndex(index
)].separator_type
;
287 int SimpleMenuModel::GetCommandIdAt(int index
) const {
288 return items_
[ValidateItemIndex(index
)].command_id
;
291 base::string16
SimpleMenuModel::GetLabelAt(int index
) const {
292 if (IsItemDynamicAt(index
))
293 return delegate_
->GetLabelForCommandId(GetCommandIdAt(index
));
294 return items_
[ValidateItemIndex(index
)].label
;
297 base::string16
SimpleMenuModel::GetSublabelAt(int index
) const {
298 if (IsItemDynamicAt(index
))
299 return delegate_
->GetSublabelForCommandId(GetCommandIdAt(index
));
300 return items_
[ValidateItemIndex(index
)].sublabel
;
303 base::string16
SimpleMenuModel::GetMinorTextAt(int index
) const {
304 if (IsItemDynamicAt(index
))
305 return delegate_
->GetMinorTextForCommandId(GetCommandIdAt(index
));
306 return items_
[ValidateItemIndex(index
)].minor_text
;
309 bool SimpleMenuModel::IsItemDynamicAt(int index
) const {
311 return delegate_
->IsItemForCommandIdDynamic(GetCommandIdAt(index
));
315 bool SimpleMenuModel::GetAcceleratorAt(int index
,
316 ui::Accelerator
* accelerator
) const {
318 return delegate_
->GetAcceleratorForCommandId(GetCommandIdAt(index
),
324 bool SimpleMenuModel::IsItemCheckedAt(int index
) const {
327 MenuModel::ItemType item_type
= GetTypeAt(index
);
328 return (item_type
== TYPE_CHECK
|| item_type
== TYPE_RADIO
) ?
329 delegate_
->IsCommandIdChecked(GetCommandIdAt(index
)) : false;
332 int SimpleMenuModel::GetGroupIdAt(int index
) const {
333 return items_
[ValidateItemIndex(index
)].group_id
;
336 bool SimpleMenuModel::GetIconAt(int index
, gfx::Image
* icon
) {
337 if (IsItemDynamicAt(index
))
338 return delegate_
->GetIconForCommandId(GetCommandIdAt(index
), icon
);
340 ValidateItemIndex(index
);
341 if (items_
[index
].icon
.IsEmpty())
344 *icon
= items_
[index
].icon
;
348 ButtonMenuItemModel
* SimpleMenuModel::GetButtonMenuItemAt(int index
) const {
349 return items_
[ValidateItemIndex(index
)].button_model
;
352 bool SimpleMenuModel::IsEnabledAt(int index
) const {
353 int command_id
= GetCommandIdAt(index
);
354 if (!delegate_
|| command_id
== kSeparatorId
|| GetButtonMenuItemAt(index
))
356 return delegate_
->IsCommandIdEnabled(command_id
);
359 bool SimpleMenuModel::IsVisibleAt(int index
) const {
360 int command_id
= GetCommandIdAt(index
);
361 if (!delegate_
|| command_id
== kSeparatorId
|| GetButtonMenuItemAt(index
))
363 return delegate_
->IsCommandIdVisible(command_id
);
366 void SimpleMenuModel::HighlightChangedTo(int index
) {
368 delegate_
->CommandIdHighlighted(GetCommandIdAt(index
));
371 void SimpleMenuModel::ActivatedAt(int index
) {
373 delegate_
->ExecuteCommand(GetCommandIdAt(index
), 0);
376 void SimpleMenuModel::ActivatedAt(int index
, int event_flags
) {
378 delegate_
->ExecuteCommand(GetCommandIdAt(index
), event_flags
);
381 MenuModel
* SimpleMenuModel::GetSubmenuModelAt(int index
) const {
382 return items_
[ValidateItemIndex(index
)].submenu
;
385 void SimpleMenuModel::MenuWillShow() {
387 delegate_
->MenuWillShow(this);
390 void SimpleMenuModel::MenuClosed() {
391 // Due to how menus work on the different platforms, ActivatedAt will be
392 // called after this. It's more convenient for the delegate to be called
393 // afterwards though, so post a task.
394 base::MessageLoop::current()->PostTask(
396 base::Bind(&SimpleMenuModel::OnMenuClosed
, method_factory_
.GetWeakPtr()));
399 void SimpleMenuModel::SetMenuModelDelegate(
400 ui::MenuModelDelegate
* menu_model_delegate
) {
401 menu_model_delegate_
= menu_model_delegate
;
404 MenuModelDelegate
* SimpleMenuModel::GetMenuModelDelegate() const {
405 return menu_model_delegate_
;
408 void SimpleMenuModel::OnMenuClosed() {
410 delegate_
->MenuClosed(this);
413 ////////////////////////////////////////////////////////////////////////////////
414 // SimpleMenuModel, Protected:
416 void SimpleMenuModel::MenuItemsChanged() {
419 ////////////////////////////////////////////////////////////////////////////////
420 // SimpleMenuModel, Private:
422 int SimpleMenuModel::ValidateItemIndex(int index
) const {
424 CHECK_LT(static_cast<size_t>(index
), items_
.size());
428 void SimpleMenuModel::AppendItem(const Item
& item
) {
430 items_
.push_back(item
);
434 void SimpleMenuModel::InsertItemAtIndex(const Item
& item
, int index
) {
436 items_
.insert(items_
.begin() + index
, item
);
440 void SimpleMenuModel::ValidateItem(const Item
& item
) {
442 if (item
.type
== TYPE_SEPARATOR
) {
443 DCHECK_EQ(item
.command_id
, kSeparatorId
);
445 DCHECK_GE(item
.command_id
, 0);