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

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

Issue 1138523006: Enable keyboard accelerators while a menu is open (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Removed OnTouchEvent() Created 5 years, 3 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
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"
8 #include "base/strings/utf_string_conversions.h" 7 #include "base/strings/utf_string_conversions.h"
8 #include "ui/aura/scoped_window_targeter.h"
9 #include "ui/aura/window.h"
9 #include "ui/events/event_handler.h" 10 #include "ui/events/event_handler.h"
10 #include "ui/events/null_event_targeter.h" 11 #include "ui/events/null_event_targeter.h"
11 #include "ui/events/platform/platform_event_source.h" 12 #include "ui/events/test/event_generator.h"
12 #include "ui/events/test/platform_event_source_test_api.h"
13 #include "ui/views/controls/menu/menu_item_view.h" 13 #include "ui/views/controls/menu/menu_item_view.h"
14 #include "ui/views/controls/menu/submenu_view.h" 14 #include "ui/views/controls/menu/submenu_view.h"
15 #include "ui/views/test/views_test_base.h" 15 #include "ui/views/test/views_test_base.h"
16 16
17 #if defined(USE_AURA) 17 #if defined(USE_AURA)
18 #include "ui/aura/env.h"
19 #include "ui/aura/scoped_window_targeter.h" 18 #include "ui/aura/scoped_window_targeter.h"
20 #include "ui/aura/window.h" 19 #include "ui/aura/window.h"
21 #include "ui/wm/public/dispatcher_client.h"
22 #endif 20 #endif
23 21
24 #if defined(OS_WIN) 22 #if defined(USE_X11)
25 #include "base/message_loop/message_pump_dispatcher.h"
26 #elif defined(USE_X11)
27 #include <X11/Xlib.h> 23 #include <X11/Xlib.h>
28 #undef Bool 24 #undef Bool
29 #undef None 25 #undef None
30 #include "ui/events/test/events_test_utils_x11.h" 26 #include "ui/events/test/events_test_utils_x11.h"
31 #elif defined(USE_OZONE)
32 #include "ui/events/event.h"
33 #elif defined(OS_MACOSX)
34 #include "ui/events/test/event_generator.h"
35 #endif 27 #endif
36 28
37 namespace views { 29 namespace views {
38 namespace test { 30 namespace test {
39 31
40 namespace { 32 namespace {
41 33
42 class TestMenuItemView : public MenuItemView {
43 public:
44 TestMenuItemView() : MenuItemView(nullptr) {}
45 ~TestMenuItemView() override {}
46
47 private:
48 DISALLOW_COPY_AND_ASSIGN(TestMenuItemView);
49 };
50
51 class SubmenuViewShown : public SubmenuView { 34 class SubmenuViewShown : public SubmenuView {
52 public: 35 public:
53 SubmenuViewShown(MenuItemView* parent) : SubmenuView(parent) {} 36 SubmenuViewShown(MenuItemView* parent) : SubmenuView(parent) {}
54 ~SubmenuViewShown() override {} 37 ~SubmenuViewShown() override {}
55 bool IsShowing() override { return true; } 38 bool IsShowing() override { return true; }
56 39
57 private: 40 private:
58 DISALLOW_COPY_AND_ASSIGN(SubmenuViewShown); 41 DISALLOW_COPY_AND_ASSIGN(SubmenuViewShown);
59 }; 42 };
60 43
61 #if defined(USE_AURA) 44 class TestEventHandler : public ui::EventHandler {
62 class TestDispatcherClient : public aura::client::DispatcherClient {
63 public: 45 public:
64 TestDispatcherClient() : dispatcher_(nullptr) {} 46 TestEventHandler() : outstanding_touches_(0) {}
65 ~TestDispatcherClient() override {}
66 47
67 base::MessagePumpDispatcher* dispatcher() { 48 void OnTouchEvent(ui::TouchEvent* event) override {
68 return dispatcher_; 49 switch(event->type()) {
50 case ui::ET_TOUCH_PRESSED:
51 outstanding_touches_++;
52 break;
53 case ui::ET_TOUCH_RELEASED:
54 case ui::ET_TOUCH_CANCELLED:
55 outstanding_touches_--;
56 break;
57 default:
58 break;
59 }
69 } 60 }
70 61
71 // aura::client::DispatcherClient: 62 int outstanding_touches() const { return outstanding_touches_; }
72 void PrepareNestedLoopClosures(base::MessagePumpDispatcher* dispatcher,
73 base::Closure* run_closure,
74 base::Closure* quit_closure) override {
75 scoped_ptr<base::RunLoop> run_loop(new base::RunLoop());
76 *quit_closure = run_loop->QuitClosure();
77 *run_closure = base::Bind(&TestDispatcherClient::RunNestedDispatcher,
78 base::Unretained(this),
79 base::Passed(&run_loop),
80 dispatcher);
81 }
82 63
83 private: 64 private:
84 void RunNestedDispatcher(scoped_ptr<base::RunLoop> run_loop, 65 int outstanding_touches_;
85 base::MessagePumpDispatcher* dispatcher) { 66 DISALLOW_COPY_AND_ASSIGN(TestEventHandler);
86 base::AutoReset<base::MessagePumpDispatcher*> reset_dispatcher(&dispatcher_,
87 dispatcher);
88 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
89 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
90 run_loop->Run();
91 }
92
93 base::MessagePumpDispatcher* dispatcher_;
94
95 DISALLOW_COPY_AND_ASSIGN(TestDispatcherClient);
96 }; 67 };
97 #endif // USE_AURA
98 68
99 } // namespace 69 } // namespace
100 70
101 class TestMenuItemViewShown : public MenuItemView { 71 class TestMenuItemViewShown : public MenuItemView {
102 public: 72 public:
103 TestMenuItemViewShown() : MenuItemView(nullptr) { 73 TestMenuItemViewShown() : MenuItemView(nullptr) {
104 submenu_ = new SubmenuViewShown(this); 74 submenu_ = new SubmenuViewShown(this);
105 } 75 }
106 ~TestMenuItemViewShown() override {} 76 ~TestMenuItemViewShown() override {}
107 77
108 private: 78 private:
109 DISALLOW_COPY_AND_ASSIGN(TestMenuItemViewShown); 79 DISALLOW_COPY_AND_ASSIGN(TestMenuItemViewShown);
110 }; 80 };
111 81
112 class MenuControllerTest : public ViewsTestBase { 82 class MenuControllerTest : public ViewsTestBase {
113 public: 83 public:
114 MenuControllerTest() 84 MenuControllerTest() : menu_controller_(nullptr) {
115 : controller_(nullptr), 85 }
116 event_source_(ui::PlatformEventSource::GetInstance()) {} 86
117 ~MenuControllerTest() override { ResetMenuController(); } 87 ~MenuControllerTest() override {}
118 88
119 // Dispatches |count| number of items, each in a separate iteration of the 89 // ViewsTestBase:
120 // message-loop, by posting a task. 90 void SetUp() override {
121 void Step3_DispatchEvents(int count) { 91 ViewsTestBase::SetUp();
122 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); 92 Init();
123 base::MessageLoop::ScopedNestableTaskAllower allow(loop); 93 }
124 controller_->exit_type_ = MenuController::EXIT_ALL; 94
125 95 void TearDown() override {
126 DispatchEvent(); 96 owner_->CloseNow();
127 if (count) { 97
128 base::MessageLoop::current()->PostTask( 98 menu_controller_->showing_ = false;
129 FROM_HERE, 99 menu_controller_->owner_ = nullptr;
130 base::Bind(&MenuControllerTest::Step3_DispatchEvents, 100 delete menu_controller_;
131 base::Unretained(this), 101 menu_controller_ = nullptr;
132 count - 1)); 102
133 } else { 103 ViewsTestBase::TearDown();
134 EXPECT_TRUE(run_loop_->running()); 104 }
135 run_loop_->Quit(); 105
106 void ReleaseTouchId(int id) {
107 event_generator_->ReleaseTouchId(id);
108 }
109
110 void PressKey(ui::KeyboardCode key_code) {
111 event_generator_->PressKey(key_code, 0);
112 }
113
114 #if defined(OS_LINUX) && defined(USE_X11)
115 void TestEventTargeter() {
116 {
117 // With the |ui::NullEventTargeter| instantiated and assigned we expect
118 // the menu to not handle the key event.
119 aura::ScopedWindowTargeter scoped_targeter(
120 owner()->GetNativeWindow()->GetRootWindow(),
121 scoped_ptr<ui::EventTargeter>(new ui::NullEventTargeter));
122 event_generator_->PressKey(ui::VKEY_ESCAPE, 0);
123 EXPECT_EQ(MenuController::EXIT_NONE, menu_exit_type());
136 } 124 }
137 } 125 // Now that the targeter has been destroyed, expect to exit the menu
138 126 // normally when hitting escape.
139 // Runs a nested message-loop that does not involve the menu itself. 127 event_generator_->PressKey(ui::VKEY_ESCAPE, 0);
140 void Step2_RunNestedLoop() { 128 EXPECT_EQ(MenuController::EXIT_OUTERMOST, menu_exit_type());
141 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); 129 }
142 base::MessageLoop::ScopedNestableTaskAllower allow(loop); 130 #endif // defined(OS_LINUX) && defined(USE_X11)
143 base::MessageLoop::current()->PostTask( 131
144 FROM_HERE, 132 protected:
145 base::Bind(&MenuControllerTest::Step3_DispatchEvents, 133 void SetPendingStateItem(MenuItemView* item) {
146 base::Unretained(this), 134 menu_controller_->pending_state_.item = item;
147 3)); 135 menu_controller_->pending_state_.submenu_open = true;
148 run_loop_.reset(new base::RunLoop()); 136 }
149 run_loop_->Run(); 137
150 } 138 void ResetSelection() {
151 139 menu_controller_->SetSelection(
152 void Step1_RunMenu() { 140 nullptr,
153 base::MessageLoop::current()->PostTask( 141 MenuController::SELECTION_EXIT |
154 FROM_HERE, 142 MenuController::SELECTION_UPDATE_IMMEDIATELY);
155 base::Bind(&MenuControllerTest::Step2_RunNestedLoop, 143 }
156 base::Unretained(this))); 144
157 scoped_ptr<Widget> owner(CreateOwnerWidget()); 145 void IncrementSelection() {
158 RunMenu(owner.get()); 146 menu_controller_->IncrementSelection(
159 } 147 MenuController::INCREMENT_SELECTION_DOWN);
160 148 }
161 scoped_ptr<Widget> CreateOwnerWidget() { 149
162 scoped_ptr<Widget> widget(new Widget); 150 void DecrementSelection() {
151 menu_controller_->IncrementSelection(
152 MenuController::INCREMENT_SELECTION_UP);
153 }
154
155 MenuItemView* FindInitialSelectableMenuItemDown(MenuItemView* parent) {
156 return menu_controller_->FindInitialSelectableMenuItem(
157 parent, MenuController::INCREMENT_SELECTION_DOWN);
158 }
159
160 MenuItemView* FindInitialSelectableMenuItemUp(MenuItemView* parent) {
161 return menu_controller_->FindInitialSelectableMenuItem(
162 parent, MenuController::INCREMENT_SELECTION_UP);
163 }
164
165 MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent,
166 int index) {
167
168 return menu_controller_->FindNextSelectableMenuItem(
169 parent, index, MenuController::INCREMENT_SELECTION_DOWN);
170 }
171
172 MenuItemView* FindPreviousSelectableMenuItem(MenuItemView* parent,
173 int index) {
174 return menu_controller_->FindNextSelectableMenuItem(
175 parent, index, MenuController::INCREMENT_SELECTION_UP);
176 }
177
178 void RunMenu() {
179 menu_controller_->RunMessageLoop(false);
180 }
181
182 Widget* owner() { return owner_.get(); }
183 ui::test::EventGenerator* event_generator() { return event_generator_.get(); }
184 TestMenuItemViewShown* menu_item() { return menu_item_.get(); }
185 MenuController* menu_controller() { return menu_controller_; }
186 const MenuItemView* pending_state_item() const {
187 return menu_controller_->pending_state_.item;
188 }
189 MenuController::ExitType menu_exit_type() const {
190 return menu_controller_->exit_type_;
191 }
192
193 private:
194 void Init() {
195 owner_.reset(new Widget);
163 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 196 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
164 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 197 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
165 widget->Init(params); 198 owner_->Init(params);
166 widget->Show(); 199 event_generator_.reset(
167 200 new ui::test::EventGenerator(GetContext(), owner_->GetNativeWindow()));
168 #if defined(USE_AURA) 201 owner_->Show();
169 aura::client::SetDispatcherClient( 202
170 widget->GetNativeWindow()->GetRootWindow(), &dispatcher_client_); 203 SetupMenuItem();
171 #endif 204
172 return widget.Pass(); 205 SetupMenuController();
173 } 206 }
174 207
175 const MenuItemView* pending_state_item() const { 208 void SetupMenuItem() {
176 return controller_->pending_state_.item; 209 menu_item_.reset(new TestMenuItemViewShown);
177 } 210 menu_item_->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
178 211 menu_item_->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two"));
179 void SetPendingStateItem(MenuItemView* item) { 212 menu_item_->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three"));
180 controller_->pending_state_.item = item; 213 menu_item_->AppendMenuItemWithLabel(4, base::ASCIIToUTF16("Four"));
181 controller_->pending_state_.submenu_open = true; 214 }
182 } 215
183 216 void SetupMenuController() {
184 void ResetSelection() { 217 menu_controller_= new MenuController(nullptr, true, nullptr);
185 controller_->SetSelection(nullptr, 218 menu_controller_->owner_ = owner_.get();
186 MenuController::SELECTION_EXIT | 219 menu_controller_->showing_ = true;
187 MenuController::SELECTION_UPDATE_IMMEDIATELY); 220 menu_controller_->SetSelection(
188 } 221 menu_item_.get(), MenuController::SELECTION_UPDATE_IMMEDIATELY);
189 222 }
190 void IncrementSelection() { 223
191 controller_->IncrementSelection(MenuController::INCREMENT_SELECTION_DOWN); 224 scoped_ptr<Widget> owner_;
192 } 225 scoped_ptr<ui::test::EventGenerator> event_generator_;
193 226 scoped_ptr<TestMenuItemViewShown> menu_item_;
194 void DecrementSelection() { 227 MenuController* menu_controller_;
195 controller_->IncrementSelection(MenuController::INCREMENT_SELECTION_UP);
196 }
197
198 MenuItemView* FindInitialSelectableMenuItemDown(MenuItemView* parent) {
199 return controller_->FindInitialSelectableMenuItem(
200 parent, MenuController::INCREMENT_SELECTION_DOWN);
201 }
202
203 MenuItemView* FindInitialSelectableMenuItemUp(MenuItemView* parent) {
204 return controller_->FindInitialSelectableMenuItem(
205 parent, MenuController::INCREMENT_SELECTION_UP);
206 }
207
208 MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent,
209 int index) {
210 return controller_->FindNextSelectableMenuItem(
211 parent, index, MenuController::INCREMENT_SELECTION_DOWN);
212 }
213
214 MenuItemView* FindPreviousSelectableMenuItem(MenuItemView* parent,
215 int index) {
216 return controller_->FindNextSelectableMenuItem(
217 parent, index, MenuController::INCREMENT_SELECTION_UP);
218 }
219
220 void SetupMenu(views::Widget* owner, views::MenuItemView* item) {
221 ResetMenuController();
222 controller_ = new MenuController(nullptr, true, nullptr);
223 controller_->owner_ = owner;
224 controller_->showing_ = true;
225 controller_->SetSelection(item,
226 MenuController::SELECTION_UPDATE_IMMEDIATELY);
227 }
228
229 void RunMenu(views::Widget* owner) {
230 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView);
231 SetupMenu(owner, menu_item.get());
232 controller_->RunMessageLoop(false);
233 }
234
235 #if defined(USE_X11)
236 void DispatchEscapeAndExpect(MenuController::ExitType exit_type) {
237 ui::ScopedXI2Event key_event;
238 key_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0);
239 event_source_.Dispatch(key_event);
240 EXPECT_EQ(exit_type, controller_->exit_type());
241 controller_->exit_type_ = MenuController::EXIT_ALL;
242 DispatchEvent();
243 }
244
245 void DispatchTouch(int evtype, int id) {
246 ui::ScopedXI2Event touch_event;
247 std::vector<ui::Valuator> valuators;
248 touch_event.InitTouchEvent(1, evtype, id, gfx::Point(10, 10), valuators);
249 event_source_.Dispatch(touch_event);
250 DispatchEvent();
251 }
252 #endif
253
254 void DispatchEvent() {
255 #if defined(USE_X11)
256 XEvent xevent;
257 memset(&xevent, 0, sizeof(xevent));
258 event_source_.Dispatch(&xevent);
259 #elif defined(OS_WIN)
260 MSG msg;
261 memset(&msg, 0, sizeof(MSG));
262 dispatcher_client_.dispatcher()->Dispatch(msg);
263 #elif defined(USE_OZONE)
264 ui::KeyEvent event(' ', ui::VKEY_SPACE, ui::EF_NONE);
265 event_source_.Dispatch(&event);
266 #elif defined(OS_MACOSX) && !defined(USE_AURA)
267 // Since this is not an interactive test, on Mac there will be no key
268 // window. Any system event will just get ignored, so use the EventGenerator
269 // to generate a dummy event. Without Aura, these will be native events.
270 gfx::NativeWindow window = controller_->owner()->GetNativeWindow();
271 ui::test::EventGenerator generator(window, window);
272 // Send "up", since this will not activate a menu item. But note that the
273 // test has already set exit_type_ = EXIT_ALL just before the first call
274 // to this function.
275 generator.PressKey(ui::VKEY_UP, 0);
276 #else
277 #error Unsupported platform
278 #endif
279 }
280
281 private:
282 void ResetMenuController() {
283 if (controller_) {
284 // These properties are faked by RunMenu for the purposes of testing and
285 // need to be undone before we call the destructor.
286 controller_->owner_ = nullptr;
287 controller_->showing_ = false;
288 delete controller_;
289 controller_ = nullptr;
290 }
291 }
292
293 // A weak pointer to the MenuController owned by this class.
294 MenuController* controller_;
295 scoped_ptr<base::RunLoop> run_loop_;
296 ui::test::PlatformEventSourceTestAPI event_source_;
297 #if defined(USE_AURA)
298 TestDispatcherClient dispatcher_client_;
299 #endif
300 228
301 DISALLOW_COPY_AND_ASSIGN(MenuControllerTest); 229 DISALLOW_COPY_AND_ASSIGN(MenuControllerTest);
302 }; 230 };
303 231
304 TEST_F(MenuControllerTest, Basic) {
305 base::MessageLoop::ScopedNestableTaskAllower allow_nested(
306 base::MessageLoop::current());
307 message_loop()->PostTask(
308 FROM_HERE,
309 base::Bind(&MenuControllerTest::Step1_RunMenu, base::Unretained(this)));
310 }
311
312 #if defined(OS_LINUX) && defined(USE_X11) 232 #if defined(OS_LINUX) && defined(USE_X11)
313 // Tests that an event targeter which blocks events will be honored by the menu 233 // Tests that an event targeter which blocks events will be honored by the menu
314 // event dispatcher. 234 // event dispatcher.
315 TEST_F(MenuControllerTest, EventTargeter) { 235 TEST_F(MenuControllerTest, EventTargeter) {
316 { 236 base::MessageLoopForUI::current()->PostTask(
317 // Verify that the menu handles the escape key under normal circumstances. 237 FROM_HERE,
318 scoped_ptr<Widget> owner(CreateOwnerWidget()); 238 base::Bind(&MenuControllerTest::TestEventTargeter,
319 message_loop()->PostTask( 239 base::Unretained(this)));
320 FROM_HERE, 240 RunMenu();
321 base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
322 base::Unretained(this),
323 MenuController::EXIT_OUTERMOST));
324 RunMenu(owner.get());
325 }
326
327 {
328 // With the NULL targeter instantiated and assigned we expect the menu to
329 // not handle the key event.
330 scoped_ptr<Widget> owner(CreateOwnerWidget());
331 aura::ScopedWindowTargeter scoped_targeter(
332 owner->GetNativeWindow()->GetRootWindow(),
333 scoped_ptr<ui::EventTargeter>(new ui::NullEventTargeter));
334 message_loop()->PostTask(
335 FROM_HERE,
336 base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
337 base::Unretained(this),
338 MenuController::EXIT_NONE));
339 RunMenu(owner.get());
340 }
341 } 241 }
342 #endif 242 #endif // defined(OS_LINUX) && defined(USE_X11)
343 243
344 #if defined(USE_X11) 244 #if defined(USE_X11)
345
346 class TestEventHandler : public ui::EventHandler {
347 public:
348 TestEventHandler() : outstanding_touches_(0) {}
349
350 void OnTouchEvent(ui::TouchEvent* event) override {
351 switch(event->type()) {
352 case ui::ET_TOUCH_PRESSED:
353 outstanding_touches_++;
354 break;
355 case ui::ET_TOUCH_RELEASED:
356 case ui::ET_TOUCH_CANCELLED:
357 outstanding_touches_--;
358 break;
359 default:
360 break;
361 }
362 }
363
364 int outstanding_touches() const { return outstanding_touches_; }
365
366 private:
367 int outstanding_touches_;
368 };
369
370 // Tests that touch event ids are released correctly. See crbug.com/439051 for 245 // Tests that touch event ids are released correctly. See crbug.com/439051 for
371 // details. When the ids aren't managed correctly, we get stuck down touches. 246 // details. When the ids aren't managed correctly, we get stuck down touches.
372 TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) { 247 TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) {
373 scoped_ptr<Widget> owner(CreateOwnerWidget());
374 TestEventHandler test_event_handler; 248 TestEventHandler test_event_handler;
375 owner->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler( 249 owner()->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler(
376 &test_event_handler); 250 &test_event_handler);
377 251
378 std::vector<int> devices; 252 std::vector<int> devices;
379 devices.push_back(1); 253 devices.push_back(1);
380 ui::SetUpTouchDevicesForTest(devices); 254 ui::SetUpTouchDevicesForTest(devices);
381 255
382 DispatchTouch(XI_TouchBegin, 0); 256 event_generator()->PressTouchId(0);
383 DispatchTouch(XI_TouchBegin, 1); 257 event_generator()->PressTouchId(1);
384 DispatchTouch(XI_TouchEnd, 0); 258 event_generator()->ReleaseTouchId(0);
385 259
386 message_loop()->PostTask(FROM_HERE, 260 base::MessageLoopForUI::current()->PostTask(
387 base::Bind(&MenuControllerTest::DispatchTouch,
388 base::Unretained(this), XI_TouchEnd, 1));
389
390 message_loop()->PostTask(
391 FROM_HERE, 261 FROM_HERE,
392 base::Bind(&MenuControllerTest::DispatchEscapeAndExpect, 262 base::Bind(&MenuControllerTest::ReleaseTouchId,
393 base::Unretained(this), MenuController::EXIT_OUTERMOST)); 263 base::Unretained(this),
394 264 1));
395 RunMenu(owner.get()); 265
266 base::MessageLoopForUI::current()->PostTask(
267 FROM_HERE,
268 base::Bind(&MenuControllerTest::PressKey,
269 base::Unretained(this),
270 ui::VKEY_ESCAPE));
271
272 RunMenu();
273
274 EXPECT_EQ(MenuController::EXIT_OUTERMOST, menu_exit_type());
396 EXPECT_EQ(0, test_event_handler.outstanding_touches()); 275 EXPECT_EQ(0, test_event_handler.outstanding_touches());
397 276
398 owner->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler( 277 owner()->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler(
399 &test_event_handler); 278 &test_event_handler);
400 } 279 }
401 #endif // defined(USE_X11) 280 #endif // defined(USE_X11)
402 281
403 // Tests that initial selected menu items are correct when items are enabled or 282 // Tests that initial selected menu items are correct when items are enabled or
404 // disabled. 283 // disabled.
405 TEST_F(MenuControllerTest, InitialSelectedItem) { 284 TEST_F(MenuControllerTest, InitialSelectedItem) {
406 scoped_ptr<Widget> owner(CreateOwnerWidget()); 285 // Leave items "Two", "Three", and "Four" enabled.
407 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView); 286 menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
408 menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
409 menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two"));
410 menu_item->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three"));
411 SetupMenu(owner.get(), menu_item.get());
412
413 // Leave items "Two" and "Three" enabled.
414 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
415 // The first selectable item should be item "Two". 287 // The first selectable item should be item "Two".
416 MenuItemView* first_selectable = 288 MenuItemView* first_selectable =
417 FindInitialSelectableMenuItemDown(menu_item.get()); 289 FindInitialSelectableMenuItemDown(menu_item());
418 ASSERT_NE(nullptr, first_selectable); 290 ASSERT_NE(nullptr, first_selectable);
419 EXPECT_EQ(2, first_selectable->GetCommand()); 291 EXPECT_EQ(2, first_selectable->GetCommand());
420 // The last selectable item should be item "Three". 292 // The last selectable item should be item "Four".
421 MenuItemView* last_selectable = 293 MenuItemView* last_selectable =
422 FindInitialSelectableMenuItemUp(menu_item.get()); 294 FindInitialSelectableMenuItemUp(menu_item());
423 ASSERT_NE(nullptr, last_selectable); 295 ASSERT_NE(nullptr, last_selectable);
424 EXPECT_EQ(3, last_selectable->GetCommand()); 296 EXPECT_EQ(4, last_selectable->GetCommand());
425 297
426 // Leave items "One" and "Two" enabled. 298 // Leave items "One" and "Two" enabled.
427 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true); 299 menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true);
428 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true); 300 menu_item()->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true);
429 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); 301 menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
302 menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
430 // The first selectable item should be item "One". 303 // The first selectable item should be item "One".
431 first_selectable = FindInitialSelectableMenuItemDown(menu_item.get()); 304 first_selectable = FindInitialSelectableMenuItemDown(menu_item());
432 ASSERT_NE(nullptr, first_selectable); 305 ASSERT_NE(nullptr, first_selectable);
433 EXPECT_EQ(1, first_selectable->GetCommand()); 306 EXPECT_EQ(1, first_selectable->GetCommand());
434 // The last selectable item should be item "Two". 307 // The last selectable item should be item "Two".
435 last_selectable = FindInitialSelectableMenuItemUp(menu_item.get()); 308 last_selectable = FindInitialSelectableMenuItemUp(menu_item());
436 ASSERT_NE(nullptr, last_selectable); 309 ASSERT_NE(nullptr, last_selectable);
437 EXPECT_EQ(2, last_selectable->GetCommand()); 310 EXPECT_EQ(2, last_selectable->GetCommand());
438 311
439 // Leave only a single item "One" enabled. 312 // Leave only a single item "One" enabled.
440 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true); 313 menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true);
441 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false); 314 menu_item()->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false);
442 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); 315 menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
316 menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
443 // The first selectable item should be item "One". 317 // The first selectable item should be item "One".
444 first_selectable = FindInitialSelectableMenuItemDown(menu_item.get()); 318 first_selectable = FindInitialSelectableMenuItemDown(menu_item());
445 ASSERT_NE(nullptr, first_selectable); 319 ASSERT_NE(nullptr, first_selectable);
446 EXPECT_EQ(1, first_selectable->GetCommand()); 320 EXPECT_EQ(1, first_selectable->GetCommand());
447 // The last selectable item should be item "One". 321 // The last selectable item should be item "One".
448 last_selectable = FindInitialSelectableMenuItemUp(menu_item.get()); 322 last_selectable = FindInitialSelectableMenuItemUp(menu_item());
449 ASSERT_NE(nullptr, last_selectable); 323 ASSERT_NE(nullptr, last_selectable);
450 EXPECT_EQ(1, last_selectable->GetCommand()); 324 EXPECT_EQ(1, last_selectable->GetCommand());
451 325
452 // Leave only a single item "Three" enabled. 326 // Leave only a single item "Three" enabled.
453 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false); 327 menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
454 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false); 328 menu_item()->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false);
455 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(true); 329 menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(true);
330 menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
456 // The first selectable item should be item "Three". 331 // The first selectable item should be item "Three".
457 first_selectable = FindInitialSelectableMenuItemDown(menu_item.get()); 332 first_selectable = FindInitialSelectableMenuItemDown(menu_item());
458 ASSERT_NE(nullptr, first_selectable); 333 ASSERT_NE(nullptr, first_selectable);
459 EXPECT_EQ(3, first_selectable->GetCommand()); 334 EXPECT_EQ(3, first_selectable->GetCommand());
460 // The last selectable item should be item "Three". 335 // The last selectable item should be item "Three".
461 last_selectable = FindInitialSelectableMenuItemUp(menu_item.get()); 336 last_selectable = FindInitialSelectableMenuItemUp(menu_item());
462 ASSERT_NE(nullptr, last_selectable); 337 ASSERT_NE(nullptr, last_selectable);
463 EXPECT_EQ(3, last_selectable->GetCommand()); 338 EXPECT_EQ(3, last_selectable->GetCommand());
464 339
465 // Leave only a single item ("Two") selected. It should be the first and the 340 // Leave only a single item ("Two") selected. It should be the first and the
466 // last selectable item. 341 // last selectable item.
467 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false); 342 menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
468 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true); 343 menu_item()->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true);
469 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); 344 menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
470 first_selectable = FindInitialSelectableMenuItemDown(menu_item.get()); 345 menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
346 first_selectable = FindInitialSelectableMenuItemDown(menu_item());
471 ASSERT_NE(nullptr, first_selectable); 347 ASSERT_NE(nullptr, first_selectable);
472 EXPECT_EQ(2, first_selectable->GetCommand()); 348 EXPECT_EQ(2, first_selectable->GetCommand());
473 last_selectable = FindInitialSelectableMenuItemUp(menu_item.get()); 349 last_selectable = FindInitialSelectableMenuItemUp(menu_item());
474 ASSERT_NE(nullptr, last_selectable); 350 ASSERT_NE(nullptr, last_selectable);
475 EXPECT_EQ(2, last_selectable->GetCommand()); 351 EXPECT_EQ(2, last_selectable->GetCommand());
476 352
477 // There should be no next or previous selectable item since there is only a 353 // There should be no next or previous selectable item since there is only a
478 // single enabled item in the menu. 354 // single enabled item in the menu.
479 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item.get(), 1)); 355 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item(), 1));
480 EXPECT_EQ(nullptr, FindPreviousSelectableMenuItem(menu_item.get(), 1)); 356 EXPECT_EQ(nullptr, FindPreviousSelectableMenuItem(menu_item(), 1));
481 357
482 // Clear references in menu controller to the menu item that is going away. 358 // Clear references in menu controller to the menu item that is going away.
483 ResetSelection(); 359 ResetSelection();
484 } 360 }
485 361
486 // Tests that opening menu and pressing 'Down' and 'Up' iterates over enabled 362 // Tests that opening menu and pressing 'Down' and 'Up' iterates over enabled
487 // items. 363 // items.
488 TEST_F(MenuControllerTest, NextSelectedItem) { 364 TEST_F(MenuControllerTest, NextSelectedItem) {
489 scoped_ptr<Widget> owner(CreateOwnerWidget());
490 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView);
491 menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
492 menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two"));
493 menu_item->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three"));
494 menu_item->AppendMenuItemWithLabel(4, base::ASCIIToUTF16("Four"));
495 // Disabling the item "Three" gets it skipped when using keyboard to navigate. 365 // Disabling the item "Three" gets it skipped when using keyboard to navigate.
496 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); 366 menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
497
498 SetupMenu(owner.get(), menu_item.get());
499 367
500 // Fake initial hot selection. 368 // Fake initial hot selection.
501 SetPendingStateItem(menu_item->GetSubmenu()->GetMenuItemAt(0)); 369 SetPendingStateItem(menu_item()->GetSubmenu()->GetMenuItemAt(0));
502 EXPECT_EQ(1, pending_state_item()->GetCommand()); 370 EXPECT_EQ(1, pending_state_item()->GetCommand());
503 371
504 // Move down in the menu. 372 // Move down in the menu.
505 // Select next item. 373 // Select next item.
506 IncrementSelection(); 374 IncrementSelection();
507 EXPECT_EQ(2, pending_state_item()->GetCommand()); 375 EXPECT_EQ(2, pending_state_item()->GetCommand());
508 376
509 // Skip disabled item. 377 // Skip disabled item.
510 IncrementSelection(); 378 IncrementSelection();
511 EXPECT_EQ(4, pending_state_item()->GetCommand()); 379 EXPECT_EQ(4, pending_state_item()->GetCommand());
(...skipping 14 matching lines...) Expand all
526 // Select previous item. 394 // Select previous item.
527 DecrementSelection(); 395 DecrementSelection();
528 EXPECT_EQ(1, pending_state_item()->GetCommand()); 396 EXPECT_EQ(1, pending_state_item()->GetCommand());
529 397
530 // Clear references in menu controller to the menu item that is going away. 398 // Clear references in menu controller to the menu item that is going away.
531 ResetSelection(); 399 ResetSelection();
532 } 400 }
533 401
534 // Tests that opening menu and pressing 'Up' selects the last enabled menu item. 402 // Tests that opening menu and pressing 'Up' selects the last enabled menu item.
535 TEST_F(MenuControllerTest, PreviousSelectedItem) { 403 TEST_F(MenuControllerTest, PreviousSelectedItem) {
536 scoped_ptr<Widget> owner(CreateOwnerWidget());
537 scoped_ptr<TestMenuItemViewShown> menu_item(new TestMenuItemViewShown);
538 menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
539 menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two"));
540 menu_item->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three"));
541 menu_item->AppendMenuItemWithLabel(4, base::ASCIIToUTF16("Four"));
542 // Disabling the item "Four" gets it skipped when using keyboard to navigate. 404 // Disabling the item "Four" gets it skipped when using keyboard to navigate.
543 menu_item->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false); 405 menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
544
545 SetupMenu(owner.get(), menu_item.get());
546 406
547 // Fake initial root item selection and submenu showing. 407 // Fake initial root item selection and submenu showing.
548 SetPendingStateItem(menu_item.get()); 408 SetPendingStateItem(menu_item());
549 EXPECT_EQ(0, pending_state_item()->GetCommand()); 409 EXPECT_EQ(0, pending_state_item()->GetCommand());
550 410
551 // Move up and select a previous (in our case the last enabled) item. 411 // Move up and select a previous (in our case the last enabled) item.
552 DecrementSelection(); 412 DecrementSelection();
553 EXPECT_EQ(3, pending_state_item()->GetCommand()); 413 EXPECT_EQ(3, pending_state_item()->GetCommand());
554 414
555 // Clear references in menu controller to the menu item that is going away. 415 // Clear references in menu controller to the menu item that is going away.
556 ResetSelection(); 416 ResetSelection();
557 } 417 }
558 418
559 } // namespace test 419 } // namespace test
560 } // namespace views 420 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/menu/menu_controller.h ('k') | ui/views/controls/menu/menu_key_event_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698