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

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

Issue 1230163004: Selects last item in a menu when pressing 'up' initially (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Selects last item in a menu when pressing 'up' initially (nits) Created 5 years, 5 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/controls/menu/menu_item_view.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/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 16 matching lines...) Expand all
27 #undef None 27 #undef None
28 #include "ui/events/devices/x11/device_data_manager_x11.h" 28 #include "ui/events/devices/x11/device_data_manager_x11.h"
29 #include "ui/events/test/events_test_utils_x11.h" 29 #include "ui/events/test/events_test_utils_x11.h"
30 #elif defined(USE_OZONE) 30 #elif defined(USE_OZONE)
31 #include "ui/events/event.h" 31 #include "ui/events/event.h"
32 #elif defined(OS_MACOSX) 32 #elif defined(OS_MACOSX)
33 #include "ui/events/test/event_generator.h" 33 #include "ui/events/test/event_generator.h"
34 #endif 34 #endif
35 35
36 namespace views { 36 namespace views {
37 namespace test {
37 38
38 namespace { 39 namespace {
39 40
40 class TestMenuItemView : public MenuItemView { 41 class TestMenuItemView : public MenuItemView {
41 public: 42 public:
42 TestMenuItemView() : MenuItemView(nullptr) {} 43 TestMenuItemView() : MenuItemView(nullptr) {}
43 ~TestMenuItemView() override {} 44 ~TestMenuItemView() override {}
44 45
45 private: 46 private:
46 DISALLOW_COPY_AND_ASSIGN(TestMenuItemView); 47 DISALLOW_COPY_AND_ASSIGN(TestMenuItemView);
47 }; 48 };
48 49
50 class SubmenuViewShown : public SubmenuView {
51 public:
52 SubmenuViewShown(MenuItemView* parent) : SubmenuView(parent) {}
53 ~SubmenuViewShown() override {}
54 bool IsShowing() override { return true; }
55
56 private:
57 DISALLOW_COPY_AND_ASSIGN(SubmenuViewShown);
58 };
59
49 class TestPlatformEventSource : public ui::PlatformEventSource { 60 class TestPlatformEventSource : public ui::PlatformEventSource {
50 public: 61 public:
51 TestPlatformEventSource() { 62 TestPlatformEventSource() {
52 #if defined(USE_X11) 63 #if defined(USE_X11)
53 ui::DeviceDataManagerX11::CreateInstance(); 64 ui::DeviceDataManagerX11::CreateInstance();
54 #endif 65 #endif
55 } 66 }
56 ~TestPlatformEventSource() override {} 67 ~TestPlatformEventSource() override {}
57 68
58 uint32_t Dispatch(const ui::PlatformEvent& event) { 69 uint32_t Dispatch(const ui::PlatformEvent& event) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 } 107 }
97 108
98 base::MessagePumpDispatcher* dispatcher_; 109 base::MessagePumpDispatcher* dispatcher_;
99 110
100 DISALLOW_COPY_AND_ASSIGN(TestDispatcherClient); 111 DISALLOW_COPY_AND_ASSIGN(TestDispatcherClient);
101 }; 112 };
102 #endif // USE_AURA 113 #endif // USE_AURA
103 114
104 } // namespace 115 } // namespace
105 116
117 class TestMenuItemViewShown : public MenuItemView {
118 public:
119 TestMenuItemViewShown() : MenuItemView(nullptr) {
120 submenu_ = new SubmenuViewShown(this);
121 }
122 ~TestMenuItemViewShown() override {}
123
124 private:
125 DISALLOW_COPY_AND_ASSIGN(TestMenuItemViewShown);
126 };
127
106 class MenuControllerTest : public ViewsTestBase { 128 class MenuControllerTest : public ViewsTestBase {
107 public: 129 public:
108 MenuControllerTest() : controller_(nullptr) {} 130 MenuControllerTest() : controller_(nullptr) {}
109 ~MenuControllerTest() override { ResetMenuController(); } 131 ~MenuControllerTest() override { ResetMenuController(); }
110 132
111 // Dispatches |count| number of items, each in a separate iteration of the 133 // Dispatches |count| number of items, each in a separate iteration of the
112 // message-loop, by posting a task. 134 // message-loop, by posting a task.
113 void Step3_DispatchEvents(int count) { 135 void Step3_DispatchEvents(int count) {
114 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); 136 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
115 base::MessageLoop::ScopedNestableTaskAllower allow(loop); 137 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 #endif 185 #endif
164 return widget.Pass(); 186 return widget.Pass();
165 } 187 }
166 188
167 const MenuItemView* pending_state_item() const { 189 const MenuItemView* pending_state_item() const {
168 return controller_->pending_state_.item; 190 return controller_->pending_state_.item;
169 } 191 }
170 192
171 void SetPendingStateItem(MenuItemView* item) { 193 void SetPendingStateItem(MenuItemView* item) {
172 controller_->pending_state_.item = item; 194 controller_->pending_state_.item = item;
195 controller_->pending_state_.submenu_open = true;
173 } 196 }
174 197
175 void ResetSelection() { 198 void ResetSelection() {
176 controller_->SetSelection(nullptr, 199 controller_->SetSelection(nullptr,
177 MenuController::SELECTION_EXIT | 200 MenuController::SELECTION_EXIT |
178 MenuController::SELECTION_UPDATE_IMMEDIATELY); 201 MenuController::SELECTION_UPDATE_IMMEDIATELY);
179 } 202 }
180 203
181 void IncrementSelection(int delta) { 204 void IncrementSelection() {
182 controller_->IncrementSelection(delta); 205 controller_->IncrementSelection(MenuController::INCREMENT_SELECTION_DOWN);
183 } 206 }
184 207
185 MenuItemView* FindFirstSelectableMenuItem(MenuItemView* parent) { 208 void DecrementSelection() {
186 return controller_->FindFirstSelectableMenuItem(parent); 209 controller_->IncrementSelection(MenuController::INCREMENT_SELECTION_UP);
210 }
211
212 MenuItemView* FindInitialSelectableMenuItemDown(MenuItemView* parent) {
213 return controller_->FindInitialSelectableMenuItem(
214 parent, MenuController::INCREMENT_SELECTION_DOWN);
215 }
216
217 MenuItemView* FindInitialSelectableMenuItemUp(MenuItemView* parent) {
218 return controller_->FindInitialSelectableMenuItem(
219 parent, MenuController::INCREMENT_SELECTION_UP);
187 } 220 }
188 221
189 MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent, 222 MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent,
190 int index, 223 int index) {
191 int delta) { 224 return controller_->FindNextSelectableMenuItem(
192 return controller_->FindNextSelectableMenuItem(parent, index, delta); 225 parent, index, MenuController::INCREMENT_SELECTION_DOWN);
193 } 226 }
227
228 MenuItemView* FindPreviousSelectableMenuItem(MenuItemView* parent,
229 int index) {
230 return controller_->FindNextSelectableMenuItem(
231 parent, index, MenuController::INCREMENT_SELECTION_UP);
232 }
233
194 void SetupMenu(views::Widget* owner, views::MenuItemView* item) { 234 void SetupMenu(views::Widget* owner, views::MenuItemView* item) {
195 ResetMenuController(); 235 ResetMenuController();
196 controller_ = new MenuController(nullptr, true, nullptr); 236 controller_ = new MenuController(nullptr, true, nullptr);
197 controller_->owner_ = owner; 237 controller_->owner_ = owner;
198 controller_->showing_ = true; 238 controller_->showing_ = true;
199 controller_->SetSelection(item, 239 controller_->SetSelection(item,
200 MenuController::SELECTION_UPDATE_IMMEDIATELY); 240 MenuController::SELECTION_UPDATE_IMMEDIATELY);
201 } 241 }
202 242
203 void RunMenu(views::Widget* owner) { 243 void RunMenu(views::Widget* owner) {
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 break; 374 break;
335 } 375 }
336 } 376 }
337 377
338 int outstanding_touches() const { return outstanding_touches_; } 378 int outstanding_touches() const { return outstanding_touches_; }
339 379
340 private: 380 private:
341 int outstanding_touches_; 381 int outstanding_touches_;
342 }; 382 };
343 383
344 // Tests that touch event ids are released correctly. See 384 // Tests that touch event ids are released correctly. See crbug.com/439051 for
345 // crbug.com/439051 for details. When the ids aren't managed 385 // details. When the ids aren't managed correctly, we get stuck down touches.
346 // correctly, we get stuck down touches.
347 TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) { 386 TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) {
348 scoped_ptr<Widget> owner(CreateOwnerWidget()); 387 scoped_ptr<Widget> owner(CreateOwnerWidget());
349 TestEventHandler test_event_handler; 388 TestEventHandler test_event_handler;
350 owner->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler( 389 owner->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler(
351 &test_event_handler); 390 &test_event_handler);
352 391
353 std::vector<int> devices; 392 std::vector<int> devices;
354 devices.push_back(1); 393 devices.push_back(1);
355 ui::SetUpTouchDevicesForTest(devices); 394 ui::SetUpTouchDevicesForTest(devices);
356 395
(...skipping 11 matching lines...) Expand all
368 base::Unretained(this), MenuController::EXIT_OUTERMOST)); 407 base::Unretained(this), MenuController::EXIT_OUTERMOST));
369 408
370 RunMenu(owner.get()); 409 RunMenu(owner.get());
371 EXPECT_EQ(0, test_event_handler.outstanding_touches()); 410 EXPECT_EQ(0, test_event_handler.outstanding_touches());
372 411
373 owner->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler( 412 owner->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler(
374 &test_event_handler); 413 &test_event_handler);
375 } 414 }
376 #endif // defined(USE_X11) 415 #endif // defined(USE_X11)
377 416
378 TEST_F(MenuControllerTest, FirstSelectedItem) { 417 // Tests that initial selected menu items are correct when items are enabled or
418 // disabled.
419 TEST_F(MenuControllerTest, InitialSelectedItem) {
379 scoped_ptr<Widget> owner(CreateOwnerWidget()); 420 scoped_ptr<Widget> owner(CreateOwnerWidget());
380 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView); 421 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView);
381 menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One")); 422 menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
382 menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two")); 423 menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two"));
383 // Disabling the item "One" gets it skipped when a menu is first opened. 424 menu_item->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three"));
384 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
385
386 SetupMenu(owner.get(), menu_item.get()); 425 SetupMenu(owner.get(), menu_item.get());
387 426
388 // First selectable item should be item "Two". 427 // Leave items "Two" and "Three" enabled.
389 MenuItemView* first_selectable = FindFirstSelectableMenuItem(menu_item.get()); 428 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
429 // The first selectable item should be item "Two".
430 MenuItemView* first_selectable =
431 FindInitialSelectableMenuItemDown(menu_item.get());
432 ASSERT_NE(nullptr, first_selectable);
390 EXPECT_EQ(2, first_selectable->GetCommand()); 433 EXPECT_EQ(2, first_selectable->GetCommand());
434 // The last selectable item should be item "Three".
435 MenuItemView* last_selectable =
436 FindInitialSelectableMenuItemUp(menu_item.get());
437 ASSERT_NE(nullptr, last_selectable);
438 EXPECT_EQ(3, last_selectable->GetCommand());
439
440 // Leave items "One" and "Two" enabled.
441 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true);
442 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true);
443 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
444 // The first selectable item should be item "One".
445 first_selectable = FindInitialSelectableMenuItemDown(menu_item.get());
446 ASSERT_NE(nullptr, first_selectable);
447 EXPECT_EQ(1, first_selectable->GetCommand());
448 // The last selectable item should be item "Two".
449 last_selectable = FindInitialSelectableMenuItemUp(menu_item.get());
450 ASSERT_NE(nullptr, last_selectable);
451 EXPECT_EQ(2, last_selectable->GetCommand());
452
453 // Leave only a single item "One" enabled.
454 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true);
455 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false);
456 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
457 // The first selectable item should be item "One".
458 first_selectable = FindInitialSelectableMenuItemDown(menu_item.get());
459 ASSERT_NE(nullptr, first_selectable);
460 EXPECT_EQ(1, first_selectable->GetCommand());
461 // The last selectable item should be item "One".
462 last_selectable = FindInitialSelectableMenuItemUp(menu_item.get());
463 ASSERT_NE(nullptr, last_selectable);
464 EXPECT_EQ(1, last_selectable->GetCommand());
465
466 // Leave only a single item "Three" enabled.
467 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
468 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false);
469 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(true);
470 // The first selectable item should be item "Three".
471 first_selectable = FindInitialSelectableMenuItemDown(menu_item.get());
472 ASSERT_NE(nullptr, first_selectable);
473 EXPECT_EQ(3, first_selectable->GetCommand());
474 // The last selectable item should be item "Three".
475 last_selectable = FindInitialSelectableMenuItemUp(menu_item.get());
476 ASSERT_NE(nullptr, last_selectable);
477 EXPECT_EQ(3, last_selectable->GetCommand());
478
479 // Leave only a single item ("Two") selected. It should be the first and the
480 // last selectable item.
481 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
482 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true);
483 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
484 first_selectable = FindInitialSelectableMenuItemDown(menu_item.get());
485 ASSERT_NE(nullptr, first_selectable);
486 EXPECT_EQ(2, first_selectable->GetCommand());
487 last_selectable = FindInitialSelectableMenuItemUp(menu_item.get());
488 ASSERT_NE(nullptr, last_selectable);
489 EXPECT_EQ(2, last_selectable->GetCommand());
391 490
392 // There should be no next or previous selectable item since there is only a 491 // There should be no next or previous selectable item since there is only a
393 // single enabled item in the menu. 492 // single enabled item in the menu.
394 SetPendingStateItem(first_selectable); 493 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item.get(), 1));
395 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item.get(), 1, 1)); 494 EXPECT_EQ(nullptr, FindPreviousSelectableMenuItem(menu_item.get(), 1));
396 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item.get(), 1, -1));
397 495
398 // Clear references in menu controller to the menu item that is going away. 496 // Clear references in menu controller to the menu item that is going away.
399 ResetSelection(); 497 ResetSelection();
400 } 498 }
401 499
500 // Tests that opening menu and pressing 'Down' and 'Up' iterates over enabled
501 // items.
402 TEST_F(MenuControllerTest, NextSelectedItem) { 502 TEST_F(MenuControllerTest, NextSelectedItem) {
403 scoped_ptr<Widget> owner(CreateOwnerWidget()); 503 scoped_ptr<Widget> owner(CreateOwnerWidget());
404 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView); 504 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView);
405 menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One")); 505 menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
406 menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two")); 506 menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two"));
407 menu_item->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three")); 507 menu_item->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three"));
408 menu_item->AppendMenuItemWithLabel(4, base::ASCIIToUTF16("Four")); 508 menu_item->AppendMenuItemWithLabel(4, base::ASCIIToUTF16("Four"));
409 // Disabling the item "Three" gets it skipped when using keyboard to navigate. 509 // Disabling the item "Three" gets it skipped when using keyboard to navigate.
410 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); 510 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
411 511
412 SetupMenu(owner.get(), menu_item.get()); 512 SetupMenu(owner.get(), menu_item.get());
413 513
414 // Fake initial hot selection. 514 // Fake initial hot selection.
415 SetPendingStateItem(menu_item->GetSubmenu()->GetMenuItemAt(0)); 515 SetPendingStateItem(menu_item->GetSubmenu()->GetMenuItemAt(0));
416 EXPECT_EQ(1, pending_state_item()->GetCommand()); 516 EXPECT_EQ(1, pending_state_item()->GetCommand());
417 517
418 // Move down in the menu. 518 // Move down in the menu.
419 // Select next item. 519 // Select next item.
420 IncrementSelection(1); 520 IncrementSelection();
421 EXPECT_EQ(2, pending_state_item()->GetCommand()); 521 EXPECT_EQ(2, pending_state_item()->GetCommand());
422 522
423 // Skip disabled item. 523 // Skip disabled item.
424 IncrementSelection(1); 524 IncrementSelection();
425 EXPECT_EQ(4, pending_state_item()->GetCommand()); 525 EXPECT_EQ(4, pending_state_item()->GetCommand());
426 526
427 // Wrap around. 527 // Wrap around.
428 IncrementSelection(1); 528 IncrementSelection();
429 EXPECT_EQ(1, pending_state_item()->GetCommand()); 529 EXPECT_EQ(1, pending_state_item()->GetCommand());
430 530
431 // Move up in the menu. 531 // Move up in the menu.
432 // Wrap around. 532 // Wrap around.
433 IncrementSelection(-1); 533 DecrementSelection();
434 EXPECT_EQ(4, pending_state_item()->GetCommand()); 534 EXPECT_EQ(4, pending_state_item()->GetCommand());
435 535
436 // Skip disabled item. 536 // Skip disabled item.
437 IncrementSelection(-1); 537 DecrementSelection();
438 EXPECT_EQ(2, pending_state_item()->GetCommand()); 538 EXPECT_EQ(2, pending_state_item()->GetCommand());
439 539
440 // Select previous item. 540 // Select previous item.
441 IncrementSelection(-1); 541 DecrementSelection();
442 EXPECT_EQ(1, pending_state_item()->GetCommand()); 542 EXPECT_EQ(1, pending_state_item()->GetCommand());
443 543
444 // Clear references in menu controller to the menu item that is going away. 544 // Clear references in menu controller to the menu item that is going away.
445 ResetSelection(); 545 ResetSelection();
446 } 546 }
447 547
548 // Tests that opening menu and pressing 'Up' selects the last enabled menu item.
549 TEST_F(MenuControllerTest, PreviousSelectedItem) {
550 scoped_ptr<Widget> owner(CreateOwnerWidget());
551 scoped_ptr<TestMenuItemViewShown> menu_item(new TestMenuItemViewShown);
552 menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
553 menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two"));
554 menu_item->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three"));
555 menu_item->AppendMenuItemWithLabel(4, base::ASCIIToUTF16("Four"));
556 // Disabling the item "Four" gets it skipped when using keyboard to navigate.
557 menu_item->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
558
559 SetupMenu(owner.get(), menu_item.get());
560
561 // Fake initial root item selection and submenu showing.
562 SetPendingStateItem(menu_item.get());
563 EXPECT_EQ(0, pending_state_item()->GetCommand());
564
565 // Move up and select a previous (in our case the last enabled) item.
566 DecrementSelection();
567 EXPECT_EQ(3, pending_state_item()->GetCommand());
568
569 // Clear references in menu controller to the menu item that is going away.
570 ResetSelection();
571 }
572
573 } // namespace test
448 } // namespace views 574 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/menu/menu_controller.cc ('k') | ui/views/controls/menu/menu_item_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698