Chromium Code Reviews| 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/run_loop.h" | 7 #include "base/run_loop.h" |
| 8 #include "base/strings/utf_string_conversions.h" | 8 #include "base/strings/utf_string_conversions.h" |
| 9 #include "ui/events/event_handler.h" | 9 #include "ui/events/event_handler.h" |
| 10 #include "ui/events/null_event_targeter.h" | 10 #include "ui/events/null_event_targeter.h" |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 39 | 39 |
| 40 class TestMenuItemView : public MenuItemView { | 40 class TestMenuItemView : public MenuItemView { |
| 41 public: | 41 public: |
| 42 TestMenuItemView() : MenuItemView(nullptr) {} | 42 TestMenuItemView() : MenuItemView(nullptr) {} |
| 43 ~TestMenuItemView() override {} | 43 ~TestMenuItemView() override {} |
| 44 | 44 |
| 45 private: | 45 private: |
| 46 DISALLOW_COPY_AND_ASSIGN(TestMenuItemView); | 46 DISALLOW_COPY_AND_ASSIGN(TestMenuItemView); |
| 47 }; | 47 }; |
| 48 | 48 |
| 49 class SubmenuViewShown : public SubmenuView { | |
| 50 public: | |
| 51 SubmenuViewShown(MenuItemView* parent) : SubmenuView(parent) {} | |
| 52 ~SubmenuViewShown() override {} | |
| 53 bool IsShowing() override { return true; } | |
| 54 | |
| 55 private: | |
| 56 DISALLOW_COPY_AND_ASSIGN(SubmenuViewShown); | |
| 57 }; | |
| 58 | |
| 59 class TestMenuItemViewShown : public MenuItemView { | |
| 60 public: | |
| 61 TestMenuItemViewShown() : MenuItemView(nullptr) {} | |
|
sadrul
2015/07/15 19:21:52
Can it set |submenu_| here? Would that allow not m
varkha
2015/07/15 19:51:34
It is probably possible but the way CreateSubmenu
varkha
2015/07/16 16:32:33
I did that in Patch Set #4. Please see if you like
| |
| 62 ~TestMenuItemViewShown() override {} | |
| 63 SubmenuView* CreateSubmenu() override { return new SubmenuViewShown(this); } | |
| 64 | |
| 65 private: | |
| 66 DISALLOW_COPY_AND_ASSIGN(TestMenuItemViewShown); | |
| 67 }; | |
| 68 | |
| 49 class TestPlatformEventSource : public ui::PlatformEventSource { | 69 class TestPlatformEventSource : public ui::PlatformEventSource { |
| 50 public: | 70 public: |
| 51 TestPlatformEventSource() { | 71 TestPlatformEventSource() { |
| 52 #if defined(USE_X11) | 72 #if defined(USE_X11) |
| 53 ui::DeviceDataManagerX11::CreateInstance(); | 73 ui::DeviceDataManagerX11::CreateInstance(); |
| 54 #endif | 74 #endif |
| 55 } | 75 } |
| 56 ~TestPlatformEventSource() override {} | 76 ~TestPlatformEventSource() override {} |
| 57 | 77 |
| 58 uint32_t Dispatch(const ui::PlatformEvent& event) { | 78 uint32_t Dispatch(const ui::PlatformEvent& event) { |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 163 #endif | 183 #endif |
| 164 return widget.Pass(); | 184 return widget.Pass(); |
| 165 } | 185 } |
| 166 | 186 |
| 167 const MenuItemView* pending_state_item() const { | 187 const MenuItemView* pending_state_item() const { |
| 168 return controller_->pending_state_.item; | 188 return controller_->pending_state_.item; |
| 169 } | 189 } |
| 170 | 190 |
| 171 void SetPendingStateItem(MenuItemView* item) { | 191 void SetPendingStateItem(MenuItemView* item) { |
| 172 controller_->pending_state_.item = item; | 192 controller_->pending_state_.item = item; |
| 193 controller_->pending_state_.submenu_open = true; | |
| 173 } | 194 } |
| 174 | 195 |
| 175 void ResetSelection() { | 196 void ResetSelection() { |
| 176 controller_->SetSelection(nullptr, | 197 controller_->SetSelection(nullptr, |
| 177 MenuController::SELECTION_EXIT | | 198 MenuController::SELECTION_EXIT | |
| 178 MenuController::SELECTION_UPDATE_IMMEDIATELY); | 199 MenuController::SELECTION_UPDATE_IMMEDIATELY); |
| 179 } | 200 } |
| 180 | 201 |
| 181 void IncrementSelection(int delta) { | 202 void IncrementSelection(int delta) { |
| 182 controller_->IncrementSelection(delta); | 203 controller_->IncrementSelection(delta); |
| 183 } | 204 } |
| 184 | 205 |
| 185 MenuItemView* FindFirstSelectableMenuItem(MenuItemView* parent) { | 206 MenuItemView* FindInitialSelectableMenuItem(MenuItemView* parent, int delta) { |
| 186 return controller_->FindFirstSelectableMenuItem(parent); | 207 return controller_->FindInitialSelectableMenuItem(parent, delta); |
| 187 } | 208 } |
| 188 | 209 |
| 189 MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent, | 210 MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent, |
| 190 int index, | 211 int index, |
| 191 int delta) { | 212 int delta) { |
| 192 return controller_->FindNextSelectableMenuItem(parent, index, delta); | 213 return controller_->FindNextSelectableMenuItem(parent, index, delta); |
| 193 } | 214 } |
| 194 void SetupMenu(views::Widget* owner, views::MenuItemView* item) { | 215 void SetupMenu(views::Widget* owner, views::MenuItemView* item) { |
| 195 ResetMenuController(); | 216 ResetMenuController(); |
| 196 controller_ = new MenuController(nullptr, true, nullptr); | 217 controller_ = new MenuController(nullptr, true, nullptr); |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 368 base::Unretained(this), MenuController::EXIT_OUTERMOST)); | 389 base::Unretained(this), MenuController::EXIT_OUTERMOST)); |
| 369 | 390 |
| 370 RunMenu(owner.get()); | 391 RunMenu(owner.get()); |
| 371 EXPECT_EQ(0, test_event_handler.outstanding_touches()); | 392 EXPECT_EQ(0, test_event_handler.outstanding_touches()); |
| 372 | 393 |
| 373 owner->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler( | 394 owner->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler( |
| 374 &test_event_handler); | 395 &test_event_handler); |
| 375 } | 396 } |
| 376 #endif // defined(USE_X11) | 397 #endif // defined(USE_X11) |
| 377 | 398 |
| 378 TEST_F(MenuControllerTest, FirstSelectedItem) { | 399 TEST_F(MenuControllerTest, InitialSelectedItem) { |
| 379 scoped_ptr<Widget> owner(CreateOwnerWidget()); | 400 scoped_ptr<Widget> owner(CreateOwnerWidget()); |
| 380 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView); | 401 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView); |
| 381 menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One")); | 402 menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One")); |
| 382 menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two")); | 403 menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two")); |
| 383 // Disabling the item "One" gets it skipped when a menu is first opened. | 404 menu_item->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three")); |
| 384 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false); | |
| 385 | |
| 386 SetupMenu(owner.get(), menu_item.get()); | 405 SetupMenu(owner.get(), menu_item.get()); |
| 387 | 406 |
| 388 // First selectable item should be item "Two". | 407 // Leave items "Two" and "Three" enabled. |
| 389 MenuItemView* first_selectable = FindFirstSelectableMenuItem(menu_item.get()); | 408 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false); |
| 409 // The first selectable item should be item "Two". | |
| 410 MenuItemView* first_selectable = | |
| 411 FindInitialSelectableMenuItem(menu_item.get(), 1); | |
| 412 ASSERT_NE(nullptr, first_selectable); | |
| 390 EXPECT_EQ(2, first_selectable->GetCommand()); | 413 EXPECT_EQ(2, first_selectable->GetCommand()); |
| 414 // The last selectable item should be item "Three". | |
| 415 MenuItemView* last_selectable = | |
| 416 FindInitialSelectableMenuItem(menu_item.get(), -1); | |
| 417 ASSERT_NE(nullptr, last_selectable); | |
| 418 EXPECT_EQ(3, last_selectable->GetCommand()); | |
| 419 | |
| 420 // Leave items "One" and "Two" enabled. | |
| 421 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true); | |
| 422 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true); | |
| 423 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); | |
| 424 // The first selectable item should be item "One". | |
| 425 first_selectable = FindInitialSelectableMenuItem(menu_item.get(), 1); | |
| 426 ASSERT_NE(nullptr, first_selectable); | |
| 427 EXPECT_EQ(1, first_selectable->GetCommand()); | |
| 428 // The last selectable item should be item "Two". | |
| 429 last_selectable = FindInitialSelectableMenuItem(menu_item.get(), -1); | |
| 430 ASSERT_NE(nullptr, last_selectable); | |
| 431 EXPECT_EQ(2, last_selectable->GetCommand()); | |
| 432 | |
| 433 // Leave only a single item "One" enabled. | |
| 434 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true); | |
| 435 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false); | |
| 436 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); | |
| 437 // The first selectable item should be item "One". | |
| 438 first_selectable = FindInitialSelectableMenuItem(menu_item.get(), 1); | |
| 439 ASSERT_NE(nullptr, first_selectable); | |
| 440 EXPECT_EQ(1, first_selectable->GetCommand()); | |
| 441 // The last selectable item should be item "One". | |
| 442 last_selectable = FindInitialSelectableMenuItem(menu_item.get(), -1); | |
| 443 ASSERT_NE(nullptr, last_selectable); | |
| 444 EXPECT_EQ(1, last_selectable->GetCommand()); | |
| 445 | |
| 446 // Leave only a single item "Three" enabled. | |
| 447 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false); | |
| 448 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false); | |
| 449 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(true); | |
| 450 // The first selectable item should be item "Three". | |
| 451 first_selectable = FindInitialSelectableMenuItem(menu_item.get(), 1); | |
| 452 ASSERT_NE(nullptr, first_selectable); | |
| 453 EXPECT_EQ(3, first_selectable->GetCommand()); | |
| 454 // The last selectable item should be item "Three". | |
| 455 last_selectable = FindInitialSelectableMenuItem(menu_item.get(), -1); | |
| 456 ASSERT_NE(nullptr, last_selectable); | |
| 457 EXPECT_EQ(3, last_selectable->GetCommand()); | |
| 458 | |
| 459 // Leave only a single item ("Two") selected. It should be the first and the | |
| 460 // last selectable item. | |
| 461 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false); | |
| 462 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true); | |
| 463 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); | |
| 464 first_selectable = FindInitialSelectableMenuItem(menu_item.get(), 1); | |
| 465 ASSERT_NE(nullptr, first_selectable); | |
| 466 EXPECT_EQ(2, first_selectable->GetCommand()); | |
| 467 last_selectable = FindInitialSelectableMenuItem(menu_item.get(), -1); | |
| 468 ASSERT_NE(nullptr, last_selectable); | |
| 469 EXPECT_EQ(2, last_selectable->GetCommand()); | |
| 391 | 470 |
| 392 // There should be no next or previous selectable item since there is only a | 471 // There should be no next or previous selectable item since there is only a |
| 393 // single enabled item in the menu. | 472 // single enabled item in the menu. |
| 394 SetPendingStateItem(first_selectable); | |
| 395 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item.get(), 1, 1)); | 473 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item.get(), 1, 1)); |
| 396 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item.get(), 1, -1)); | 474 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item.get(), 1, -1)); |
| 397 | 475 |
| 398 // Clear references in menu controller to the menu item that is going away. | 476 // Clear references in menu controller to the menu item that is going away. |
| 399 ResetSelection(); | 477 ResetSelection(); |
| 400 } | 478 } |
| 401 | 479 |
| 402 TEST_F(MenuControllerTest, NextSelectedItem) { | 480 TEST_F(MenuControllerTest, NextSelectedItem) { |
| 403 scoped_ptr<Widget> owner(CreateOwnerWidget()); | 481 scoped_ptr<Widget> owner(CreateOwnerWidget()); |
| 404 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView); | 482 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 438 EXPECT_EQ(2, pending_state_item()->GetCommand()); | 516 EXPECT_EQ(2, pending_state_item()->GetCommand()); |
| 439 | 517 |
| 440 // Select previous item. | 518 // Select previous item. |
| 441 IncrementSelection(-1); | 519 IncrementSelection(-1); |
| 442 EXPECT_EQ(1, pending_state_item()->GetCommand()); | 520 EXPECT_EQ(1, pending_state_item()->GetCommand()); |
| 443 | 521 |
| 444 // Clear references in menu controller to the menu item that is going away. | 522 // Clear references in menu controller to the menu item that is going away. |
| 445 ResetSelection(); | 523 ResetSelection(); |
| 446 } | 524 } |
| 447 | 525 |
| 526 TEST_F(MenuControllerTest, NextSelectedItemUp) { | |
| 527 scoped_ptr<Widget> owner(CreateOwnerWidget()); | |
| 528 scoped_ptr<TestMenuItemViewShown> menu_item(new TestMenuItemViewShown); | |
| 529 menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One")); | |
| 530 menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two")); | |
| 531 menu_item->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three")); | |
| 532 menu_item->AppendMenuItemWithLabel(4, base::ASCIIToUTF16("Four")); | |
| 533 // Disabling the item "Four" gets it skipped when using keyboard to navigate. | |
| 534 menu_item->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false); | |
| 535 | |
| 536 SetupMenu(owner.get(), menu_item.get()); | |
| 537 | |
| 538 // Fake initial root item selection and submenu showing. | |
| 539 SetPendingStateItem(menu_item.get()); | |
| 540 EXPECT_EQ(0, pending_state_item()->GetCommand()); | |
| 541 | |
| 542 // Move up and select a previous (in our case the last enabled) item. | |
| 543 IncrementSelection(-1); | |
| 544 EXPECT_EQ(3, pending_state_item()->GetCommand()); | |
| 545 } | |
| 546 | |
| 448 } // namespace views | 547 } // namespace views |
| OLD | NEW |