OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "views/controls/menu/menu_item_view.h" | 5 #include "views/controls/menu/menu_item_view.h" |
6 | 6 |
7 #include "base/i18n/case_conversion.h" | 7 #include "base/i18n/case_conversion.h" |
8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
10 #include "grit/ui_strings.h" | 10 #include "grit/ui_strings.h" |
11 #include "ui/base/accessibility/accessible_view_state.h" | 11 #include "ui/base/accessibility/accessible_view_state.h" |
12 #include "ui/base/l10n/l10n_util.h" | 12 #include "ui/base/l10n/l10n_util.h" |
13 #include "ui/base/models/menu_model.h" | 13 #include "ui/base/models/menu_model.h" |
14 #include "ui/gfx/canvas.h" | 14 #include "ui/gfx/canvas.h" |
15 #include "views/controls/button/menu_button.h" | 15 #include "views/controls/button/menu_button.h" |
16 #include "views/controls/button/text_button.h" | 16 #include "views/controls/button/text_button.h" |
17 #include "views/controls/menu/menu_config.h" | 17 #include "views/controls/menu/menu_config.h" |
18 #include "views/controls/menu/menu_controller.h" | 18 #include "views/controls/menu/menu_controller.h" |
19 #include "views/controls/menu/menu_separator.h" | 19 #include "views/controls/menu/menu_separator.h" |
20 #include "views/controls/menu/submenu_view.h" | 20 #include "views/controls/menu/submenu_view.h" |
21 | 21 |
22 #if defined(OS_WIN) | |
23 #include "base/win/win_util.h" | |
24 #endif | |
25 | |
26 namespace views { | 22 namespace views { |
27 | 23 |
28 namespace { | 24 namespace { |
29 | 25 |
30 // EmptyMenuMenuItem --------------------------------------------------------- | 26 // EmptyMenuMenuItem --------------------------------------------------------- |
31 | 27 |
32 // EmptyMenuMenuItem is used when a menu has no menu items. EmptyMenuMenuItem | 28 // EmptyMenuMenuItem is used when a menu has no menu items. EmptyMenuMenuItem |
33 // is itself a MenuItemView, but it uses a different ID so that it isn't | 29 // is itself a MenuItemView, but it uses a different ID so that it isn't |
34 // identified as a MenuItemView. | 30 // identified as a MenuItemView. |
35 | 31 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 has_icons_(false), | 89 has_icons_(false), |
94 top_margin_(-1), | 90 top_margin_(-1), |
95 bottom_margin_(-1), | 91 bottom_margin_(-1), |
96 requested_menu_position_(POSITION_BEST_FIT), | 92 requested_menu_position_(POSITION_BEST_FIT), |
97 actual_menu_position_(requested_menu_position_) { | 93 actual_menu_position_(requested_menu_position_) { |
98 // NOTE: don't check the delegate for NULL, UpdateMenuPartSizes supplies a | 94 // NOTE: don't check the delegate for NULL, UpdateMenuPartSizes supplies a |
99 // NULL delegate. | 95 // NULL delegate. |
100 Init(NULL, 0, SUBMENU, delegate); | 96 Init(NULL, 0, SUBMENU, delegate); |
101 } | 97 } |
102 | 98 |
103 MenuItemView::~MenuItemView() { | |
104 // TODO(sky): ownership is bit wrong now. In particular if a nested message | |
105 // loop is running deletion can't be done, otherwise the stack gets | |
106 // thoroughly screwed. The destructor should be made private, and | |
107 // MenuController should be the only place handling deletion of the menu. | |
108 // (57890). | |
109 delete submenu_; | |
110 STLDeleteElements(&removed_items_); | |
111 } | |
112 | |
113 void MenuItemView::ChildPreferredSizeChanged(View* child) { | 99 void MenuItemView::ChildPreferredSizeChanged(View* child) { |
114 pref_size_.SetSize(0, 0); | 100 pref_size_.SetSize(0, 0); |
115 PreferredSizeChanged(); | 101 PreferredSizeChanged(); |
116 } | 102 } |
117 | 103 |
118 bool MenuItemView::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) { | 104 bool MenuItemView::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) { |
119 *tooltip = UTF16ToWideHack(tooltip_); | 105 *tooltip = UTF16ToWideHack(tooltip_); |
120 if (!tooltip->empty()) | 106 if (!tooltip->empty()) |
121 return true; | 107 return true; |
122 | 108 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 | 171 |
186 // Append accelerator text. | 172 // Append accelerator text. |
187 if (!accelerator_text.empty()) { | 173 if (!accelerator_text.empty()) { |
188 accessible_name.push_back(' '); | 174 accessible_name.push_back(' '); |
189 accessible_name.append(accelerator_text); | 175 accessible_name.append(accelerator_text); |
190 } | 176 } |
191 | 177 |
192 return accessible_name; | 178 return accessible_name; |
193 } | 179 } |
194 | 180 |
195 void MenuItemView::RunMenuAt(Widget* parent, | |
196 MenuButton* button, | |
197 const gfx::Rect& bounds, | |
198 AnchorPosition anchor, | |
199 bool has_mnemonics) { | |
200 // Show mnemonics if the button has focus or alt is pressed. | |
201 bool show_mnemonics = button ? button->HasFocus() : false; | |
202 #if defined(OS_WIN) | |
203 // We don't currently need this on gtk as showing the menu gives focus to the | |
204 // button first. | |
205 if (!show_mnemonics) | |
206 show_mnemonics = base::win::IsAltPressed(); | |
207 #endif | |
208 PrepareForRun(has_mnemonics, show_mnemonics); | |
209 int mouse_event_flags; | |
210 | |
211 MenuController* controller = MenuController::GetActiveInstance(); | |
212 if (controller && !controller->IsBlockingRun()) { | |
213 // A menu is already showing, but it isn't a blocking menu. Cancel it. | |
214 // We can get here during drag and drop if the user right clicks on the | |
215 // menu quickly after the drop. | |
216 controller->Cancel(MenuController::EXIT_ALL); | |
217 controller = NULL; | |
218 } | |
219 // TODO(sky): remove volatile, used in tracking 90860. | |
220 volatile bool owns_controller = false; | |
221 if (!controller) { | |
222 // No menus are showing, show one. | |
223 controller = new MenuController(true); | |
224 MenuController::SetActiveInstance(controller); | |
225 owns_controller = true; | |
226 } else { | |
227 // A menu is already showing, use the same controller. | |
228 | |
229 // Don't support blocking from within non-blocking. | |
230 DCHECK(controller->IsBlockingRun()); | |
231 } | |
232 | |
233 controller_ = controller; | |
234 | |
235 // Run the loop. | |
236 MenuItemView* result = | |
237 controller->Run(parent, button, this, bounds, anchor, &mouse_event_flags); | |
238 | |
239 RemoveEmptyMenus(); | |
240 | |
241 controller_ = NULL; | |
242 | |
243 if (owns_controller) { | |
244 // We created the controller and need to delete it. | |
245 if (MenuController::GetActiveInstance() == controller) | |
246 MenuController::SetActiveInstance(NULL); | |
247 delete controller; | |
248 } | |
249 // Make sure all the windows we created to show the menus have been | |
250 // destroyed. | |
251 DestroyAllMenuHosts(); | |
252 if (result && delegate_) | |
253 delegate_->ExecuteCommand(result->GetCommand(), mouse_event_flags); | |
254 } | |
255 | |
256 void MenuItemView::RunMenuForDropAt(Widget* parent, | |
257 const gfx::Rect& bounds, | |
258 AnchorPosition anchor) { | |
259 PrepareForRun(false, false); | |
260 | |
261 // If there is a menu, hide it so that only one menu is shown during dnd. | |
262 MenuController* current_controller = MenuController::GetActiveInstance(); | |
263 if (current_controller) { | |
264 current_controller->Cancel(MenuController::EXIT_ALL); | |
265 } | |
266 | |
267 // Always create a new controller for non-blocking. | |
268 controller_ = new MenuController(false); | |
269 | |
270 // Set the instance, that way it can be canceled by another menu. | |
271 MenuController::SetActiveInstance(controller_); | |
272 | |
273 controller_->Run(parent, NULL, this, bounds, anchor, NULL); | |
274 } | |
275 | |
276 void MenuItemView::Cancel() { | 181 void MenuItemView::Cancel() { |
277 if (controller_ && !canceled_) { | 182 if (controller_ && !canceled_) { |
278 canceled_ = true; | 183 canceled_ = true; |
279 controller_->Cancel(MenuController::EXIT_ALL); | 184 controller_->Cancel(MenuController::EXIT_ALL); |
280 } | 185 } |
281 } | 186 } |
282 | 187 |
283 MenuItemView* MenuItemView::AddMenuItemAt(int index, | 188 MenuItemView* MenuItemView::AddMenuItemAt(int index, |
284 int item_id, | 189 int item_id, |
285 const std::wstring& label, | 190 const std::wstring& label, |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
552 has_mnemonics_(false), | 457 has_mnemonics_(false), |
553 show_mnemonics_(false), | 458 show_mnemonics_(false), |
554 has_icons_(false), | 459 has_icons_(false), |
555 top_margin_(-1), | 460 top_margin_(-1), |
556 bottom_margin_(-1), | 461 bottom_margin_(-1), |
557 requested_menu_position_(POSITION_BEST_FIT), | 462 requested_menu_position_(POSITION_BEST_FIT), |
558 actual_menu_position_(requested_menu_position_) { | 463 actual_menu_position_(requested_menu_position_) { |
559 Init(parent, command, type, NULL); | 464 Init(parent, command, type, NULL); |
560 } | 465 } |
561 | 466 |
| 467 MenuItemView::~MenuItemView() { |
| 468 delete submenu_; |
| 469 STLDeleteElements(&removed_items_); |
| 470 } |
| 471 |
562 std::string MenuItemView::GetClassName() const { | 472 std::string MenuItemView::GetClassName() const { |
563 return kViewClassName; | 473 return kViewClassName; |
564 } | 474 } |
565 | 475 |
566 // Calculates all sizes that we can from the OS. | 476 // Calculates all sizes that we can from the OS. |
567 // | 477 // |
568 // This is invoked prior to Running a menu. | 478 // This is invoked prior to Running a menu. |
569 void MenuItemView::UpdateMenuPartSizes(bool has_icons) { | 479 void MenuItemView::UpdateMenuPartSizes(bool has_icons) { |
570 MenuConfig::Reset(); | 480 MenuConfig::Reset(); |
571 const MenuConfig& config = MenuConfig::instance(); | 481 const MenuConfig& config = MenuConfig::instance(); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
606 set_id(kMenuItemViewID); | 516 set_id(kMenuItemViewID); |
607 has_icons_ = false; | 517 has_icons_ = false; |
608 | 518 |
609 // Don't request enabled status from the root menu item as it is just | 519 // Don't request enabled status from the root menu item as it is just |
610 // a container for real items. EMPTY items will be disabled. | 520 // a container for real items. EMPTY items will be disabled. |
611 MenuDelegate* root_delegate = GetDelegate(); | 521 MenuDelegate* root_delegate = GetDelegate(); |
612 if (parent && type != EMPTY && root_delegate) | 522 if (parent && type != EMPTY && root_delegate) |
613 SetEnabled(root_delegate->IsCommandEnabled(command)); | 523 SetEnabled(root_delegate->IsCommandEnabled(command)); |
614 } | 524 } |
615 | 525 |
616 void MenuItemView::DropMenuClosed(bool notify_delegate) { | |
617 DCHECK(controller_); | |
618 DCHECK(!controller_->IsBlockingRun()); | |
619 if (MenuController::GetActiveInstance() == controller_) | |
620 MenuController::SetActiveInstance(NULL); | |
621 delete controller_; | |
622 controller_ = NULL; | |
623 | |
624 RemoveEmptyMenus(); | |
625 | |
626 if (notify_delegate && delegate_) { | |
627 // Our delegate is null when invoked from the destructor. | |
628 delegate_->DropMenuClosed(this); | |
629 } | |
630 // WARNING: its possible the delegate deleted us at this point. | |
631 } | |
632 | |
633 void MenuItemView::PrepareForRun(bool has_mnemonics, bool show_mnemonics) { | 526 void MenuItemView::PrepareForRun(bool has_mnemonics, bool show_mnemonics) { |
634 // Currently we only support showing the root. | 527 // Currently we only support showing the root. |
635 DCHECK(!parent_menu_item_); | 528 DCHECK(!parent_menu_item_); |
636 | 529 |
637 // Force us to have a submenu. | 530 // Force us to have a submenu. |
638 CreateSubmenu(); | 531 CreateSubmenu(); |
639 actual_menu_position_ = requested_menu_position_; | 532 actual_menu_position_ = requested_menu_position_; |
640 canceled_ = false; | 533 canceled_ = false; |
641 | 534 |
642 has_mnemonics_ = has_mnemonics; | 535 has_mnemonics_ = has_mnemonics; |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
796 return string16(); | 689 return string16(); |
797 } | 690 } |
798 | 691 |
799 Accelerator accelerator; | 692 Accelerator accelerator; |
800 return (GetDelegate() && | 693 return (GetDelegate() && |
801 GetDelegate()->GetAccelerator(GetCommand(), &accelerator)) ? | 694 GetDelegate()->GetAccelerator(GetCommand(), &accelerator)) ? |
802 accelerator.GetShortcutText() : string16(); | 695 accelerator.GetShortcutText() : string16(); |
803 } | 696 } |
804 | 697 |
805 } // namespace views | 698 } // namespace views |
OLD | NEW |