| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "ui/views/controls/menu/menu_controller.h" | 5 #include "ui/views/controls/menu/menu_controller.h" |
| 6 | 6 |
| 7 #include "base/callback.h" | 7 #include "base/callback.h" |
| 8 #include "base/macros.h" | 8 #include "base/macros.h" |
| 9 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
| 10 #include "build/build_config.h" | 10 #include "build/build_config.h" |
| (...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 | 400 |
| 401 void SetIsCombobox(bool is_combobox) { | 401 void SetIsCombobox(bool is_combobox) { |
| 402 menu_controller_->set_is_combobox(is_combobox); | 402 menu_controller_->set_is_combobox(is_combobox); |
| 403 } | 403 } |
| 404 | 404 |
| 405 void SetSelectionOnPointerDown(SubmenuView* source, | 405 void SetSelectionOnPointerDown(SubmenuView* source, |
| 406 const ui::LocatedEvent* event) { | 406 const ui::LocatedEvent* event) { |
| 407 menu_controller_->SetSelectionOnPointerDown(source, event); | 407 menu_controller_->SetSelectionOnPointerDown(source, event); |
| 408 } | 408 } |
| 409 | 409 |
| 410 void UpdateSelection(View* view) { |
| 411 menu_controller_->SetSelection(menu_controller_->pending_state_.item, 0); |
| 412 } |
| 413 |
| 410 void RunMenu() { | 414 void RunMenu() { |
| 411 #if defined(USE_AURA) | 415 #if defined(USE_AURA) |
| 412 scoped_ptr<MenuKeyEventHandler> key_event_handler(new MenuKeyEventHandler); | 416 scoped_ptr<MenuKeyEventHandler> key_event_handler(new MenuKeyEventHandler); |
| 413 #endif | 417 #endif |
| 414 | 418 |
| 415 menu_controller_->message_loop_depth_++; | 419 menu_controller_->message_loop_depth_++; |
| 416 menu_controller_->RunMessageLoop(false); | 420 menu_controller_->RunMessageLoop(false); |
| 417 menu_controller_->message_loop_depth_--; | 421 menu_controller_->message_loop_depth_--; |
| 418 } | 422 } |
| 419 | 423 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 434 return menu_controller_delegate_.get(); | 438 return menu_controller_delegate_.get(); |
| 435 } | 439 } |
| 436 MenuController* menu_controller() { return menu_controller_; } | 440 MenuController* menu_controller() { return menu_controller_; } |
| 437 const MenuItemView* pending_state_item() const { | 441 const MenuItemView* pending_state_item() const { |
| 438 return menu_controller_->pending_state_.item; | 442 return menu_controller_->pending_state_.item; |
| 439 } | 443 } |
| 440 MenuController::ExitType menu_exit_type() const { | 444 MenuController::ExitType menu_exit_type() const { |
| 441 return menu_controller_->exit_type_; | 445 return menu_controller_->exit_type_; |
| 442 } | 446 } |
| 443 | 447 |
| 448 void AddButtonMenuItems() { |
| 449 MenuItemView* item_view = |
| 450 menu_item()->AppendMenuItemWithLabel(5, base::ASCIIToUTF16("Five")); |
| 451 for (int i = 0; i < 3; ++i) { |
| 452 LabelButton* button = |
| 453 new LabelButton(nullptr, base::ASCIIToUTF16("Label")); |
| 454 button->SetFocusable(true); |
| 455 item_view->AddChildView(button); |
| 456 } |
| 457 menu_item()->GetSubmenu()->ShowAt(owner(), menu_item()->bounds(), false); |
| 458 } |
| 459 |
| 444 private: | 460 private: |
| 445 void DestroyMenuController() { | 461 void DestroyMenuController() { |
| 446 if (!menu_controller_) | 462 if (!menu_controller_) |
| 447 return; | 463 return; |
| 448 | 464 |
| 449 if (!owner_->IsClosed()) | 465 if (!owner_->IsClosed()) |
| 450 owner_->RemoveObserver(menu_controller_); | 466 owner_->RemoveObserver(menu_controller_); |
| 451 | 467 |
| 452 menu_controller_->showing_ = false; | 468 menu_controller_->showing_ = false; |
| 453 menu_controller_->owner_ = nullptr; | 469 menu_controller_->owner_ = nullptr; |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 695 EXPECT_EQ(0, pending_state_item()->GetCommand()); | 711 EXPECT_EQ(0, pending_state_item()->GetCommand()); |
| 696 | 712 |
| 697 // Handle searching for 'f'; should find "Four". | 713 // Handle searching for 'f'; should find "Four". |
| 698 SelectByChar('f'); | 714 SelectByChar('f'); |
| 699 EXPECT_EQ(4, pending_state_item()->GetCommand()); | 715 EXPECT_EQ(4, pending_state_item()->GetCommand()); |
| 700 | 716 |
| 701 // Clear references in menu controller to the menu item that is going away. | 717 // Clear references in menu controller to the menu item that is going away. |
| 702 ResetSelection(); | 718 ResetSelection(); |
| 703 } | 719 } |
| 704 | 720 |
| 721 TEST_F(MenuControllerTest, SelectChildButtonView) { |
| 722 AddButtonMenuItems(); |
| 723 |
| 724 // Handle searching for 'f'; should find "Four". |
| 725 SelectByChar('f'); |
| 726 EXPECT_EQ(4, pending_state_item()->GetCommand()); |
| 727 |
| 728 View* buttons_view = menu_item()->GetSubmenu()->child_at(4); |
| 729 ASSERT_NE(nullptr, buttons_view); |
| 730 CustomButton* button1 = |
| 731 CustomButton::AsCustomButton(buttons_view->child_at(0)); |
| 732 ASSERT_NE(nullptr, button1); |
| 733 CustomButton* button2 = |
| 734 CustomButton::AsCustomButton(buttons_view->child_at(1)); |
| 735 ASSERT_NE(nullptr, button2); |
| 736 CustomButton* button3 = |
| 737 CustomButton::AsCustomButton(buttons_view->child_at(2)); |
| 738 ASSERT_NE(nullptr, button2); |
| 739 EXPECT_FALSE(button1->IsHotTracked()); |
| 740 EXPECT_FALSE(button2->IsHotTracked()); |
| 741 EXPECT_FALSE(button3->IsHotTracked()); |
| 742 |
| 743 // Move selection to |button1|. |
| 744 IncrementSelection(); |
| 745 EXPECT_EQ(5, pending_state_item()->GetCommand()); |
| 746 EXPECT_TRUE(button1->IsHotTracked()); |
| 747 EXPECT_FALSE(button2->IsHotTracked()); |
| 748 EXPECT_FALSE(button3->IsHotTracked()); |
| 749 |
| 750 // Move selection to |button2|. |
| 751 IncrementSelection(); |
| 752 EXPECT_EQ(5, pending_state_item()->GetCommand()); |
| 753 EXPECT_FALSE(button1->IsHotTracked()); |
| 754 EXPECT_TRUE(button2->IsHotTracked()); |
| 755 EXPECT_FALSE(button3->IsHotTracked()); |
| 756 |
| 757 // Move selection to |button3|. |
| 758 IncrementSelection(); |
| 759 EXPECT_EQ(5, pending_state_item()->GetCommand()); |
| 760 EXPECT_FALSE(button1->IsHotTracked()); |
| 761 EXPECT_FALSE(button2->IsHotTracked()); |
| 762 EXPECT_TRUE(button3->IsHotTracked()); |
| 763 |
| 764 // Externally set hot tracked to the first child button and update. |
| 765 button1->SetHotTracked(true); |
| 766 // Emulate a mouse move that would update menu controller selection. |
| 767 UpdateSelection(buttons_view); |
| 768 |
| 769 // Incrementing selection should move hot tracking to the second button (next |
| 770 // after the first button). |
| 771 IncrementSelection(); |
| 772 EXPECT_EQ(5, pending_state_item()->GetCommand()); |
| 773 EXPECT_FALSE(button1->IsHotTracked()); |
| 774 EXPECT_TRUE(button2->IsHotTracked()); |
| 775 EXPECT_FALSE(button3->IsHotTracked()); |
| 776 |
| 777 // Increment selection twice to wrap around. |
| 778 IncrementSelection(); |
| 779 IncrementSelection(); |
| 780 EXPECT_EQ(1, pending_state_item()->GetCommand()); |
| 781 |
| 782 // Clear references in menu controller to the menu item that is going away. |
| 783 ResetSelection(); |
| 784 } |
| 785 |
| 786 TEST_F(MenuControllerTest, DeleteChildButtonView) { |
| 787 AddButtonMenuItems(); |
| 788 |
| 789 // Handle searching for 'f'; should find "Four". |
| 790 SelectByChar('f'); |
| 791 EXPECT_EQ(4, pending_state_item()->GetCommand()); |
| 792 |
| 793 View* buttons_view = menu_item()->GetSubmenu()->child_at(4); |
| 794 ASSERT_NE(nullptr, buttons_view); |
| 795 CustomButton* button1 = |
| 796 CustomButton::AsCustomButton(buttons_view->child_at(0)); |
| 797 ASSERT_NE(nullptr, button1); |
| 798 CustomButton* button2 = |
| 799 CustomButton::AsCustomButton(buttons_view->child_at(1)); |
| 800 ASSERT_NE(nullptr, button2); |
| 801 CustomButton* button3 = |
| 802 CustomButton::AsCustomButton(buttons_view->child_at(2)); |
| 803 ASSERT_NE(nullptr, button2); |
| 804 EXPECT_FALSE(button1->IsHotTracked()); |
| 805 EXPECT_FALSE(button2->IsHotTracked()); |
| 806 EXPECT_FALSE(button3->IsHotTracked()); |
| 807 |
| 808 // Increment twice to move selection to |button2|. |
| 809 IncrementSelection(); |
| 810 IncrementSelection(); |
| 811 EXPECT_EQ(5, pending_state_item()->GetCommand()); |
| 812 EXPECT_FALSE(button1->IsHotTracked()); |
| 813 EXPECT_TRUE(button2->IsHotTracked()); |
| 814 EXPECT_FALSE(button3->IsHotTracked()); |
| 815 |
| 816 // Externally set hot tracked to the first child button and update. |
| 817 button1->SetHotTracked(true); |
| 818 // Delete |button2| while another child button view is hot-tracked. |
| 819 // This should update MenuController via ViewHierarchyChanged and reset |
| 820 // |hot_button_|. |
| 821 delete button2; |
| 822 // Emulate a mouse move that would update menu controller selection. |
| 823 // This should not crash. |
| 824 UpdateSelection(buttons_view); |
| 825 |
| 826 // Incrementing selection should now set hot-tracked item to |button3|. |
| 827 IncrementSelection(); |
| 828 EXPECT_EQ(5, pending_state_item()->GetCommand()); |
| 829 EXPECT_FALSE(button1->IsHotTracked()); |
| 830 EXPECT_TRUE(button3->IsHotTracked()); |
| 831 } |
| 832 |
| 705 // Tests that a menu opened asynchronously, will notify its | 833 // Tests that a menu opened asynchronously, will notify its |
| 706 // MenuControllerDelegate when Accept is called. | 834 // MenuControllerDelegate when Accept is called. |
| 707 TEST_F(MenuControllerTest, AsynchronousAccept) { | 835 TEST_F(MenuControllerTest, AsynchronousAccept) { |
| 708 MenuController* controller = menu_controller(); | 836 MenuController* controller = menu_controller(); |
| 709 controller->SetAsyncRun(true); | 837 controller->SetAsyncRun(true); |
| 710 | 838 |
| 711 int mouse_event_flags = 0; | 839 int mouse_event_flags = 0; |
| 712 MenuItemView* run_result = | 840 MenuItemView* run_result = |
| 713 controller->Run(owner(), nullptr, menu_item(), gfx::Rect(), | 841 controller->Run(owner(), nullptr, menu_item(), gfx::Rect(), |
| 714 MENU_ANCHOR_TOPLEFT, false, false, &mouse_event_flags); | 842 MENU_ANCHOR_TOPLEFT, false, false, &mouse_event_flags); |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 869 EXPECT_TRUE(IsAsyncRun()); | 997 EXPECT_TRUE(IsAsyncRun()); |
| 870 EXPECT_EQ(nested_delegate.get(), GetCurrentDelegate()); | 998 EXPECT_EQ(nested_delegate.get(), GetCurrentDelegate()); |
| 871 | 999 |
| 872 MenuItemView* item = menu_item(); | 1000 MenuItemView* item = menu_item(); |
| 873 int mouse_event_flags = 0; | 1001 int mouse_event_flags = 0; |
| 874 MenuItemView* run_result = | 1002 MenuItemView* run_result = |
| 875 controller->Run(owner(), nullptr, item, gfx::Rect(), MENU_ANCHOR_TOPLEFT, | 1003 controller->Run(owner(), nullptr, item, gfx::Rect(), MENU_ANCHOR_TOPLEFT, |
| 876 false, false, &mouse_event_flags); | 1004 false, false, &mouse_event_flags); |
| 877 EXPECT_EQ(run_result, nullptr); | 1005 EXPECT_EQ(run_result, nullptr); |
| 878 | 1006 |
| 879 // Show a sub menu to targert with a pointer selection. However have the event | 1007 // Show a sub menu to target with a pointer selection. However have the event |
| 880 // occur outside of the bounds of the entire menu. | 1008 // occur outside of the bounds of the entire menu. |
| 881 SubmenuView* sub_menu = item->GetSubmenu(); | 1009 SubmenuView* sub_menu = item->GetSubmenu(); |
| 882 sub_menu->ShowAt(owner(), item->bounds(), false); | 1010 sub_menu->ShowAt(owner(), item->bounds(), false); |
| 883 gfx::Point location(sub_menu->bounds().bottom_right()); | 1011 gfx::Point location(sub_menu->bounds().bottom_right()); |
| 884 location.Offset(1, 1); | 1012 location.Offset(1, 1); |
| 885 ui::MouseEvent event(ui::ET_MOUSE_PRESSED, location, location, | 1013 ui::MouseEvent event(ui::ET_MOUSE_PRESSED, location, location, |
| 886 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); | 1014 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); |
| 887 | 1015 |
| 888 // When attempting to select outside of all menus this should lead to a | 1016 // When attempting to select outside of all menus this should lead to a |
| 889 // shutdown. This should not crash while attempting to repost the event. | 1017 // shutdown. This should not crash while attempting to repost the event. |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 968 EXPECT_TRUE(IsAsyncRun()); | 1096 EXPECT_TRUE(IsAsyncRun()); |
| 969 EXPECT_EQ(nested_delegate.get(), GetCurrentDelegate()); | 1097 EXPECT_EQ(nested_delegate.get(), GetCurrentDelegate()); |
| 970 | 1098 |
| 971 MenuItemView* item = menu_item(); | 1099 MenuItemView* item = menu_item(); |
| 972 int mouse_event_flags = 0; | 1100 int mouse_event_flags = 0; |
| 973 MenuItemView* run_result = | 1101 MenuItemView* run_result = |
| 974 controller->Run(owner(), nullptr, item, gfx::Rect(), MENU_ANCHOR_TOPLEFT, | 1102 controller->Run(owner(), nullptr, item, gfx::Rect(), MENU_ANCHOR_TOPLEFT, |
| 975 false, false, &mouse_event_flags); | 1103 false, false, &mouse_event_flags); |
| 976 EXPECT_EQ(run_result, nullptr); | 1104 EXPECT_EQ(run_result, nullptr); |
| 977 | 1105 |
| 978 // Show a sub menu to targert with a pointer selection. However have the event | 1106 // Show a sub menu to target with a pointer selection. However have the event |
| 979 // occur outside of the bounds of the entire menu. | 1107 // occur outside of the bounds of the entire menu. |
| 980 SubmenuView* sub_menu = item->GetSubmenu(); | 1108 SubmenuView* sub_menu = item->GetSubmenu(); |
| 981 sub_menu->ShowAt(owner(), item->bounds(), true); | 1109 sub_menu->ShowAt(owner(), item->bounds(), true); |
| 982 gfx::Point location(sub_menu->bounds().bottom_right()); | 1110 gfx::Point location(sub_menu->bounds().bottom_right()); |
| 983 location.Offset(1, 1); | 1111 location.Offset(1, 1); |
| 984 ui::MouseEvent event(ui::ET_MOUSE_PRESSED, location, location, | 1112 ui::MouseEvent event(ui::ET_MOUSE_PRESSED, location, location, |
| 985 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); | 1113 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); |
| 986 | 1114 |
| 987 // This will lead to MenuController being deleted during the event repost. | 1115 // This will lead to MenuController being deleted during the event repost. |
| 988 // The remainder of this test, and TearDown should not crash. | 1116 // The remainder of this test, and TearDown should not crash. |
| 989 DestroyMenuControllerOnMenuClosed(nested_delegate.get()); | 1117 DestroyMenuControllerOnMenuClosed(nested_delegate.get()); |
| 990 // When attempting to select outside of all menus this should lead to a | 1118 // When attempting to select outside of all menus this should lead to a |
| 991 // shutdown. This should not crash while attempting to repost the event. | 1119 // shutdown. This should not crash while attempting to repost the event. |
| 992 SetSelectionOnPointerDown(sub_menu, &event); | 1120 SetSelectionOnPointerDown(sub_menu, &event); |
| 993 | 1121 |
| 994 // Close to remove observers before test TearDown | 1122 // Close to remove observers before test TearDown |
| 995 sub_menu->Close(); | 1123 sub_menu->Close(); |
| 996 EXPECT_EQ(1, nested_delegate->on_menu_closed_called()); | 1124 EXPECT_EQ(1, nested_delegate->on_menu_closed_called()); |
| 997 } | 1125 } |
| 998 | 1126 |
| 999 } // namespace test | 1127 } // namespace test |
| 1000 } // namespace views | 1128 } // namespace views |
| OLD | NEW |