Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Side by Side Diff: ui/views/controls/menu/menu_controller_unittest.cc

Issue 2778383002: MenuController Do Not SetSelection to Empty Items on Drag (Closed)
Patch Set: Make logic readible Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/views/controls/menu/menu_controller.cc ('k') | ui/views/test/menu_test_utils.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/logging.h" 8 #include "base/logging.h"
9 #include "base/macros.h" 9 #include "base/macros.h"
10 #include "base/single_thread_task_runner.h" 10 #include "base/single_thread_task_runner.h"
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 public: 271 public:
272 TestMenuItemViewShown(MenuDelegate* delegate) : MenuItemView(delegate) { 272 TestMenuItemViewShown(MenuDelegate* delegate) : MenuItemView(delegate) {
273 submenu_ = new SubmenuViewShown(this); 273 submenu_ = new SubmenuViewShown(this);
274 } 274 }
275 ~TestMenuItemViewShown() override {} 275 ~TestMenuItemViewShown() override {}
276 276
277 void SetController(MenuController* controller) { 277 void SetController(MenuController* controller) {
278 set_controller(controller); 278 set_controller(controller);
279 } 279 }
280 280
281 void AddEmptyMenusForTest() { AddEmptyMenus(); }
282
281 private: 283 private:
282 DISALLOW_COPY_AND_ASSIGN(TestMenuItemViewShown); 284 DISALLOW_COPY_AND_ASSIGN(TestMenuItemViewShown);
283 }; 285 };
284 286
285 class MenuControllerTest : public ViewsTestBase { 287 class MenuControllerTest : public ViewsTestBase {
286 public: 288 public:
287 MenuControllerTest() : menu_controller_(nullptr) { 289 MenuControllerTest() : menu_controller_(nullptr) {
288 } 290 }
289 291
290 ~MenuControllerTest() override {} 292 ~MenuControllerTest() override {}
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 owner()->GetNativeWindow()->GetRootWindow(), 326 owner()->GetNativeWindow()->GetRootWindow(),
325 std::unique_ptr<ui::EventTargeter>(new ui::NullEventTargeter)); 327 std::unique_ptr<ui::EventTargeter>(new ui::NullEventTargeter));
326 event_generator_->PressKey(ui::VKEY_ESCAPE, 0); 328 event_generator_->PressKey(ui::VKEY_ESCAPE, 0);
327 EXPECT_EQ(MenuController::EXIT_NONE, menu_exit_type()); 329 EXPECT_EQ(MenuController::EXIT_NONE, menu_exit_type());
328 } 330 }
329 // Now that the targeter has been destroyed, expect to exit the menu 331 // Now that the targeter has been destroyed, expect to exit the menu
330 // normally when hitting escape. 332 // normally when hitting escape.
331 event_generator_->PressKey(ui::VKEY_ESCAPE, 0); 333 event_generator_->PressKey(ui::VKEY_ESCAPE, 0);
332 EXPECT_EQ(MenuController::EXIT_ALL, menu_exit_type()); 334 EXPECT_EQ(MenuController::EXIT_ALL, menu_exit_type());
333 } 335 }
336 #endif // defined(OS_LINUX) && defined(USE_X11
334 337
338 #if defined(USE_AURA)
335 // Verifies that a non-nested menu fully closes when receiving an escape key. 339 // Verifies that a non-nested menu fully closes when receiving an escape key.
336 void TestAsyncEscapeKey() { 340 void TestAsyncEscapeKey() {
337 ui::KeyEvent event(ui::EventType::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0); 341 ui::KeyEvent event(ui::EventType::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0);
338 menu_controller_->OnWillDispatchKeyEvent(&event); 342 menu_controller_->OnWillDispatchKeyEvent(&event);
339 EXPECT_EQ(MenuController::EXIT_ALL, menu_exit_type());
340 } 343 }
341 344
342 #endif // defined(OS_LINUX) && defined(USE_X11)
343
344 #if defined(USE_AURA)
345 // Verifies that an open menu receives a cancel event, and closes. 345 // Verifies that an open menu receives a cancel event, and closes.
346 void TestCancelEvent() { 346 void TestCancelEvent() {
347 EXPECT_EQ(MenuController::EXIT_NONE, menu_controller_->exit_type()); 347 EXPECT_EQ(MenuController::EXIT_NONE, menu_controller_->exit_type());
348 ui::CancelModeEvent cancel_event; 348 ui::CancelModeEvent cancel_event;
349 event_generator_->Dispatch(&cancel_event); 349 event_generator_->Dispatch(&cancel_event);
350 EXPECT_EQ(MenuController::EXIT_ALL, menu_controller_->exit_type()); 350 EXPECT_EQ(MenuController::EXIT_ALL, menu_controller_->exit_type());
351 } 351 }
352 #endif // defined(USE_AURA) 352 #endif // defined(USE_AURA)
353 353
354 // Verifies the state of the |menu_controller_| before destroying it. 354 // Verifies the state of the |menu_controller_| before destroying it.
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
452 &MenuControllerTest::DestroyMenuController, base::Unretained(this))); 452 &MenuControllerTest::DestroyMenuController, base::Unretained(this)));
453 menu_controller_->ExitAsyncRun(); 453 menu_controller_->ExitAsyncRun();
454 } 454 }
455 455
456 protected: 456 protected:
457 void SetPendingStateItem(MenuItemView* item) { 457 void SetPendingStateItem(MenuItemView* item) {
458 menu_controller_->pending_state_.item = item; 458 menu_controller_->pending_state_.item = item;
459 menu_controller_->pending_state_.submenu_open = true; 459 menu_controller_->pending_state_.submenu_open = true;
460 } 460 }
461 461
462 void SetState(MenuItemView* item) {
463 menu_controller_->state_.item = item;
464 menu_controller_->state_.submenu_open = true;
465 }
466
462 void ResetSelection() { 467 void ResetSelection() {
463 menu_controller_->SetSelection( 468 menu_controller_->SetSelection(
464 nullptr, 469 nullptr,
465 MenuController::SELECTION_EXIT | 470 MenuController::SELECTION_EXIT |
466 MenuController::SELECTION_UPDATE_IMMEDIATELY); 471 MenuController::SELECTION_UPDATE_IMMEDIATELY);
467 } 472 }
468 473
469 void IncrementSelection() { 474 void IncrementSelection() {
470 menu_controller_->IncrementSelection( 475 menu_controller_->IncrementSelection(
471 MenuController::INCREMENT_SELECTION_DOWN); 476 MenuController::INCREMENT_SELECTION_DOWN);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 menu_controller_->set_is_combobox(is_combobox); 542 menu_controller_->set_is_combobox(is_combobox);
538 } 543 }
539 544
540 void SetSelectionOnPointerDown(SubmenuView* source, 545 void SetSelectionOnPointerDown(SubmenuView* source,
541 const ui::LocatedEvent* event) { 546 const ui::LocatedEvent* event) {
542 menu_controller_->SetSelectionOnPointerDown(source, event); 547 menu_controller_->SetSelectionOnPointerDown(source, event);
543 } 548 }
544 549
545 // Note that coordinates of events passed to MenuController must be in that of 550 // Note that coordinates of events passed to MenuController must be in that of
546 // the MenuScrollViewContainer. 551 // the MenuScrollViewContainer.
552 void ProcessMousePressed(SubmenuView* source, const ui::MouseEvent& event) {
553 menu_controller_->OnMousePressed(source, event);
554 }
555
556 void ProcessMouseDragged(SubmenuView* source, const ui::MouseEvent& event) {
557 menu_controller_->OnMouseDragged(source, event);
558 }
559
547 void ProcessMouseMoved(SubmenuView* source, const ui::MouseEvent& event) { 560 void ProcessMouseMoved(SubmenuView* source, const ui::MouseEvent& event) {
548 menu_controller_->OnMouseMoved(source, event); 561 menu_controller_->OnMouseMoved(source, event);
549 } 562 }
550 563
564 void ProcessMouseReleased(SubmenuView* source, const ui::MouseEvent& event) {
565 menu_controller_->OnMouseReleased(source, event);
566 }
567
551 void RunMenu() { 568 void RunMenu() {
552 #if defined(USE_AURA) 569 #if defined(USE_AURA)
553 std::unique_ptr<MenuPreTargetHandler> menu_pre_target_handler( 570 std::unique_ptr<MenuPreTargetHandler> menu_pre_target_handler(
554 new MenuPreTargetHandler(menu_controller_, owner_.get())); 571 new MenuPreTargetHandler(menu_controller_, owner_.get()));
555 #endif 572 #endif
556 573
557 menu_controller_->message_loop_depth_++; 574 menu_controller_->message_loop_depth_++;
558 menu_controller_->RunMessageLoop(); 575 menu_controller_->RunMessageLoop();
559 menu_controller_->message_loop_depth_--; 576 menu_controller_->message_loop_depth_--;
560 } 577 }
(...skipping 13 matching lines...) Expand all
574 void StartDrag() { 591 void StartDrag() {
575 const gfx::Point location; 592 const gfx::Point location;
576 menu_controller_->state_.item = menu_item()->GetSubmenu()->GetMenuItemAt(0); 593 menu_controller_->state_.item = menu_item()->GetSubmenu()->GetMenuItemAt(0);
577 menu_controller_->StartDrag( 594 menu_controller_->StartDrag(
578 menu_item()->GetSubmenu()->GetMenuItemAt(0)->CreateSubmenu(), location); 595 menu_item()->GetSubmenu()->GetMenuItemAt(0)->CreateSubmenu(), location);
579 } 596 }
580 597
581 Widget* owner() { return owner_.get(); } 598 Widget* owner() { return owner_.get(); }
582 ui::test::EventGenerator* event_generator() { return event_generator_.get(); } 599 ui::test::EventGenerator* event_generator() { return event_generator_.get(); }
583 TestMenuItemViewShown* menu_item() { return menu_item_.get(); } 600 TestMenuItemViewShown* menu_item() { return menu_item_.get(); }
601 TestMenuDelegate* menu_delegate() { return menu_delegate_.get(); }
584 TestMenuControllerDelegate* menu_controller_delegate() { 602 TestMenuControllerDelegate* menu_controller_delegate() {
585 return menu_controller_delegate_.get(); 603 return menu_controller_delegate_.get();
586 } 604 }
587 MenuController* menu_controller() { return menu_controller_; } 605 MenuController* menu_controller() { return menu_controller_; }
588 const MenuItemView* pending_state_item() const { 606 const MenuItemView* pending_state_item() const {
589 return menu_controller_->pending_state_.item; 607 return menu_controller_->pending_state_.item;
590 } 608 }
591 MenuController::ExitType menu_exit_type() const { 609 MenuController::ExitType menu_exit_type() const {
592 return menu_controller_->exit_type_; 610 return menu_controller_->exit_type_;
593 } 611 }
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
668 menu_item_->SetController(menu_controller_); 686 menu_item_->SetController(menu_controller_);
669 } 687 }
670 688
671 // Not owned. 689 // Not owned.
672 DestructingTestViewsDelegate* test_views_delegate_; 690 DestructingTestViewsDelegate* test_views_delegate_;
673 691
674 std::unique_ptr<Widget> owner_; 692 std::unique_ptr<Widget> owner_;
675 std::unique_ptr<ui::test::EventGenerator> event_generator_; 693 std::unique_ptr<ui::test::EventGenerator> event_generator_;
676 std::unique_ptr<TestMenuItemViewShown> menu_item_; 694 std::unique_ptr<TestMenuItemViewShown> menu_item_;
677 std::unique_ptr<TestMenuControllerDelegate> menu_controller_delegate_; 695 std::unique_ptr<TestMenuControllerDelegate> menu_controller_delegate_;
678 std::unique_ptr<MenuDelegate> menu_delegate_; 696 std::unique_ptr<TestMenuDelegate> menu_delegate_;
679 MenuController* menu_controller_; 697 MenuController* menu_controller_;
680 TestMenuMessageLoop* test_message_loop_; 698 TestMenuMessageLoop* test_message_loop_;
681 699
682 DISALLOW_COPY_AND_ASSIGN(MenuControllerTest); 700 DISALLOW_COPY_AND_ASSIGN(MenuControllerTest);
683 }; 701 };
684 702
685 #if defined(OS_LINUX) && defined(USE_X11) 703 #if defined(OS_LINUX) && defined(USE_X11)
686 // Tests that an event targeter which blocks events will be honored by the menu 704 // Tests that an event targeter which blocks events will be honored by the menu
687 // event dispatcher. 705 // event dispatcher.
688 TEST_F(MenuControllerTest, EventTargeter) { 706 TEST_F(MenuControllerTest, EventTargeter) {
689 base::ThreadTaskRunnerHandle::Get()->PostTask( 707 base::ThreadTaskRunnerHandle::Get()->PostTask(
690 FROM_HERE, base::Bind(&MenuControllerTest::TestEventTargeter, 708 FROM_HERE, base::Bind(&MenuControllerTest::TestEventTargeter,
691 base::Unretained(this))); 709 base::Unretained(this)));
692 RunMenu(); 710 RunMenu();
693 } 711 }
694 712
695 // Tests that an non-nested menu receiving an escape key will fully shut. This 713 // Tests that an non-nested menu receiving an escape key will fully shut. This
696 // should not crash by attempting to retarget the key to an inner menu. 714 // should not crash by attempting to retarget the key to an inner menu.
697 TEST_F(MenuControllerTest, AsyncEscapeKey) { 715 TEST_F(MenuControllerTest, AsyncEscapeKey) {
698 menu_controller()->SetAsyncRun(true); 716 menu_controller()->SetAsyncRun(true);
699 TestAsyncEscapeKey(); 717 TestAsyncEscapeKey();
718 EXPECT_EQ(MenuController::EXIT_ALL, menu_exit_type());
700 } 719 }
701 720
702 #endif // defined(OS_LINUX) && defined(USE_X11) 721 #endif // defined(OS_LINUX) && defined(USE_X11)
703 722
704 #if defined(USE_X11) 723 #if defined(USE_X11)
705 // Tests that touch event ids are released correctly. See crbug.com/439051 for 724 // Tests that touch event ids are released correctly. See crbug.com/439051 for
706 // details. When the ids aren't managed correctly, we get stuck down touches. 725 // details. When the ids aren't managed correctly, we get stuck down touches.
707 TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) { 726 TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) {
708 TestEventHandler test_event_handler; 727 TestEventHandler test_event_handler;
709 owner()->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler( 728 owner()->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler(
(...skipping 853 matching lines...) Expand 10 before | Expand all | Expand 10 after
1563 controller->SetAsyncRun(true); 1582 controller->SetAsyncRun(true);
1564 1583
1565 int mouse_event_flags = 0; 1584 int mouse_event_flags = 0;
1566 MenuItemView* run_result = 1585 MenuItemView* run_result =
1567 controller->Run(owner(), nullptr, menu_item(), gfx::Rect(), 1586 controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
1568 MENU_ANCHOR_TOPLEFT, false, false, &mouse_event_flags); 1587 MENU_ANCHOR_TOPLEFT, false, false, &mouse_event_flags);
1569 EXPECT_EQ(run_result, nullptr); 1588 EXPECT_EQ(run_result, nullptr);
1570 TestDestroyedDuringViewsRelease(); 1589 TestDestroyedDuringViewsRelease();
1571 } 1590 }
1572 1591
1592 // Tests that when a context menu is opened above an empty menu item, and a
1593 // right-click occurs over the empty item, that the bottom menu is not hidden,
1594 // that a request to relaunch the context menu is received, and that
1595 // subsequently pressing ESC does not crash the browser.
1596 TEST_F(MenuControllerTest, RepostEventToEmptyMenuItem) {
1597 // Setup a submenu. Additionally hook up appropriate Widget and View
1598 // containers, with bounds, so that hit testing works.
1599 MenuController* controller = menu_controller();
1600 controller->SetAsyncRun(true);
1601 MenuItemView* base_menu = menu_item();
1602 base_menu->SetBounds(0, 0, 200, 200);
1603 SubmenuView* base_submenu = base_menu->GetSubmenu();
1604 base_submenu->SetBounds(0, 0, 200, 200);
1605 base_submenu->ShowAt(owner(), gfx::Rect(0, 0, 200, 200), false);
1606 GetMenuHost(base_submenu)
1607 ->SetContentsView(base_submenu->GetScrollViewContainer());
1608
1609 // Build the submenu to have an empty menu item. Additionally hook up
1610 // appropriate Widget and View containersm with counds, so that hit testing
1611 // works.
1612 std::unique_ptr<TestMenuDelegate> sub_menu_item_delegate =
1613 base::MakeUnique<TestMenuDelegate>();
1614 std::unique_ptr<TestMenuItemViewShown> sub_menu_item =
1615 base::MakeUnique<TestMenuItemViewShown>(sub_menu_item_delegate.get());
1616 sub_menu_item->AddEmptyMenusForTest();
1617 sub_menu_item->SetController(controller);
1618 sub_menu_item->SetBounds(0, 50, 50, 50);
1619 base_submenu->AddChildView(sub_menu_item.get());
1620 SubmenuView* sub_menu_view = sub_menu_item->GetSubmenu();
1621 sub_menu_view->SetBounds(0, 50, 50, 50);
1622 sub_menu_view->ShowAt(owner(), gfx::Rect(0, 50, 50, 50), false);
1623 GetMenuHost(sub_menu_view)
1624 ->SetContentsView(sub_menu_view->GetScrollViewContainer());
1625
1626 // Set that the last selection target was the item which launches the submenu,
1627 // as the empty item can never become a target.
1628 SetPendingStateItem(sub_menu_item.get());
1629
1630 // Nest a context menu.
1631 std::unique_ptr<TestMenuDelegate> nested_menu_delegate_1 =
1632 base::MakeUnique<TestMenuDelegate>();
1633 std::unique_ptr<TestMenuItemViewShown> nested_menu_item_1 =
1634 base::MakeUnique<TestMenuItemViewShown>(nested_menu_delegate_1.get());
1635 nested_menu_item_1->SetBounds(0, 0, 100, 100);
1636 nested_menu_item_1->SetController(controller);
1637 std::unique_ptr<TestMenuControllerDelegate> nested_controller_delegate_1 =
1638 base::MakeUnique<TestMenuControllerDelegate>();
1639 controller->AddNestedDelegate(nested_controller_delegate_1.get());
1640 int mouse_event_flags = 0;
1641 MenuItemView* run_result = controller->Run(
1642 owner(), nullptr, nested_menu_item_1.get(), gfx::Rect(150, 50, 100, 100),
1643 MENU_ANCHOR_TOPLEFT, true, false, &mouse_event_flags);
1644 EXPECT_EQ(run_result, nullptr);
1645
1646 SubmenuView* nested_menu_submenu = nested_menu_item_1->GetSubmenu();
1647 nested_menu_submenu->SetBounds(0, 0, 100, 100);
1648 nested_menu_submenu->ShowAt(owner(), gfx::Rect(0, 0, 100, 100), false);
1649 GetMenuHost(nested_menu_submenu)
1650 ->SetContentsView(nested_menu_submenu->GetScrollViewContainer());
1651
1652 // Press down outside of the context menu, and within the empty menu item.
1653 // This should close the first context menu.
1654 gfx::Point press_location(sub_menu_view->bounds().CenterPoint());
1655 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, press_location,
1656 press_location, ui::EventTimeForNow(),
1657 ui::EF_RIGHT_MOUSE_BUTTON, 0);
1658 ProcessMousePressed(nested_menu_submenu, press_event);
1659 EXPECT_EQ(nested_controller_delegate_1->on_menu_closed_called(), 1);
1660 EXPECT_EQ(menu_controller_delegate(), GetCurrentDelegate());
1661
1662 // While the current state is the menu item which launched the sub menu, cause
1663 // a drag in the empty menu item. This should not hide the menu.
1664 SetState(sub_menu_item.get());
1665 press_location.Offset(-5, 0);
1666 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, press_location,
1667 press_location, ui::EventTimeForNow(),
1668 ui::EF_RIGHT_MOUSE_BUTTON, 0);
1669 ProcessMouseDragged(sub_menu_view, drag_event);
1670 EXPECT_EQ(menu_delegate()->will_hide_menu_count(), 0);
1671
1672 // Release the mouse in the empty menu item, triggering a context menu
1673 // request.
1674 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, press_location,
1675 press_location, ui::EventTimeForNow(),
1676 ui::EF_RIGHT_MOUSE_BUTTON, 0);
1677 ProcessMouseReleased(sub_menu_view, release_event);
1678 EXPECT_EQ(sub_menu_item_delegate->show_context_menu_count(), 1);
1679 EXPECT_EQ(sub_menu_item_delegate->show_context_menu_source(),
1680 sub_menu_item.get());
1681
1682 // Nest a context menu.
1683 std::unique_ptr<TestMenuDelegate> nested_menu_delegate_2 =
1684 base::MakeUnique<TestMenuDelegate>();
1685 std::unique_ptr<TestMenuItemViewShown> nested_menu_item_2 =
1686 base::MakeUnique<TestMenuItemViewShown>(nested_menu_delegate_2.get());
1687 nested_menu_item_2->SetBounds(0, 0, 100, 100);
1688 nested_menu_item_2->SetController(controller);
1689
1690 std::unique_ptr<TestMenuControllerDelegate> nested_controller_delegate_2 =
1691 base::MakeUnique<TestMenuControllerDelegate>();
1692 controller->AddNestedDelegate(nested_controller_delegate_2.get());
1693 run_result = controller->Run(
1694 owner(), nullptr, nested_menu_item_2.get(), gfx::Rect(150, 50, 100, 100),
1695 MENU_ANCHOR_TOPLEFT, true, false, &mouse_event_flags);
1696 EXPECT_EQ(run_result, nullptr);
1697
1698 // The escapce key should only close the nested menu. SelectByChar should not
1699 // crash.
1700 TestAsyncEscapeKey();
1701 EXPECT_EQ(nested_controller_delegate_2->on_menu_closed_called(), 1);
1702 EXPECT_EQ(menu_controller_delegate(), GetCurrentDelegate());
1703 }
1704
1573 #endif // defined(USE_AURA) 1705 #endif // defined(USE_AURA)
1574 1706
1575 } // namespace test 1707 } // namespace test
1576 } // namespace views 1708 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/menu/menu_controller.cc ('k') | ui/views/test/menu_test_utils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698