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

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: Cleanup 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 if (menu_controller_) {
oshima 2015/09/08 21:43:08 do you need this if?
afakhry 2015/09/08 23:34:38 No. removed.
129 FROM_HERE, 99 menu_controller_->showing_ = false;
130 base::Bind(&MenuControllerTest::Step3_DispatchEvents, 100 menu_controller_->owner_ = nullptr;
131 base::Unretained(this), 101 delete menu_controller_;
132 count - 1)); 102 menu_controller_ = nullptr;
133 } else {
134 EXPECT_TRUE(run_loop_->running());
135 run_loop_->Quit();
136 } 103 }
137 } 104
138 105 ViewsTestBase::TearDown();
139 // Runs a nested message-loop that does not involve the menu itself. 106 }
140 void Step2_RunNestedLoop() { 107
141 base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); 108 void ReleaseTouchId(int id) {
142 base::MessageLoop::ScopedNestableTaskAllower allow(loop); 109 event_generator_->ReleaseTouchId(id);
143 base::MessageLoop::current()->PostTask( 110 }
144 FROM_HERE, 111
145 base::Bind(&MenuControllerTest::Step3_DispatchEvents, 112 void PressKey(ui::KeyboardCode key_code) {
146 base::Unretained(this), 113 event_generator_->PressKey(key_code, 0);
147 3)); 114 }
148 run_loop_.reset(new base::RunLoop()); 115
149 run_loop_->Run(); 116 #if defined(OS_LINUX) && defined(USE_X11)
150 } 117 void TestEventTargeter() {
151 118 {
152 void Step1_RunMenu() { 119 // With the |ui::NullEventTargeter| instantiated and assigned we expect
153 base::MessageLoop::current()->PostTask( 120 // the menu to not handle the key event.
154 FROM_HERE, 121 aura::ScopedWindowTargeter scoped_targeter(
155 base::Bind(&MenuControllerTest::Step2_RunNestedLoop, 122 owner()->GetNativeWindow()->GetRootWindow(),
156 base::Unretained(this))); 123 scoped_ptr<ui::EventTargeter>(new ui::NullEventTargeter));
157 scoped_ptr<Widget> owner(CreateOwnerWidget()); 124 event_generator_->PressKey(ui::VKEY_ESCAPE, 0);
158 RunMenu(owner.get()); 125 EXPECT_EQ(MenuController::EXIT_NONE, menu_exit_type());
159 } 126 }
160 127 // Now that the targeter has been destroyed, expect to exit the menu
161 scoped_ptr<Widget> CreateOwnerWidget() { 128 // normally when hitting escape.
162 scoped_ptr<Widget> widget(new Widget); 129 event_generator_->PressKey(ui::VKEY_ESCAPE, 0);
130 EXPECT_EQ(MenuController::EXIT_OUTERMOST, menu_exit_type());
131 }
132 #endif // defined(OS_LINUX) && defined(USE_X11)
133
134 protected:
135 void SetPendingStateItem(MenuItemView* item) {
136 menu_controller_->pending_state_.item = item;
137 menu_controller_->pending_state_.submenu_open = true;
138 }
139
140 void ResetSelection() {
141 menu_controller_->SetSelection(
142 nullptr,
143 MenuController::SELECTION_EXIT |
144 MenuController::SELECTION_UPDATE_IMMEDIATELY);
145 }
146
147 void IncrementSelection() {
148 menu_controller_->IncrementSelection(
149 MenuController::INCREMENT_SELECTION_DOWN);
150 }
151
152 void DecrementSelection() {
153 menu_controller_->IncrementSelection(
154 MenuController::INCREMENT_SELECTION_UP);
155 }
156
157 MenuItemView* FindInitialSelectableMenuItemDown(MenuItemView* parent) {
158 return menu_controller_->FindInitialSelectableMenuItem(
159 parent, MenuController::INCREMENT_SELECTION_DOWN);
160 }
161
162 MenuItemView* FindInitialSelectableMenuItemUp(MenuItemView* parent) {
163 return menu_controller_->FindInitialSelectableMenuItem(
164 parent, MenuController::INCREMENT_SELECTION_UP);
165 }
166
167 MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent,
168 int index) {
169
170 return menu_controller_->FindNextSelectableMenuItem(
171 parent, index, MenuController::INCREMENT_SELECTION_DOWN);
172 }
173
174 MenuItemView* FindPreviousSelectableMenuItem(MenuItemView* parent,
175 int index) {
176 return menu_controller_->FindNextSelectableMenuItem(
177 parent, index, MenuController::INCREMENT_SELECTION_UP);
178 }
179
180 void RunMenu() {
181 menu_controller_->RunMessageLoop(false);
182 }
183
184 Widget* owner() { return owner_.get(); }
185 ui::test::EventGenerator* event_generator() { return event_generator_.get(); }
186 TestMenuItemViewShown* menu_item() { return menu_item_.get(); }
187 MenuController* menu_controller() { return menu_controller_; }
188 const MenuItemView* pending_state_item() const {
189 return menu_controller_->pending_state_.item;
190 }
191 MenuController::ExitType menu_exit_type() const {
192 return menu_controller_->exit_type_;
193 }
194
195 private:
196 void Init() {
197 owner_.reset(new Widget);
163 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 198 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
164 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 199 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
165 widget->Init(params); 200 owner_->Init(params);
166 widget->Show(); 201 event_generator_.reset(
167 202 new ui::test::EventGenerator(GetContext(), owner_->GetNativeWindow()));
168 #if defined(USE_AURA) 203 owner_->Show();
169 aura::client::SetDispatcherClient( 204
170 widget->GetNativeWindow()->GetRootWindow(), &dispatcher_client_); 205 SetupMenuItem();
171 #endif 206
172 return widget.Pass(); 207 SetupMenuController();
173 } 208 }
174 209
175 const MenuItemView* pending_state_item() const { 210 void SetupMenuItem() {
176 return controller_->pending_state_.item; 211 menu_item_.reset(new TestMenuItemViewShown);
177 } 212 menu_item_->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
178 213 menu_item_->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two"));
179 void SetPendingStateItem(MenuItemView* item) { 214 menu_item_->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three"));
180 controller_->pending_state_.item = item; 215 menu_item_->AppendMenuItemWithLabel(4, base::ASCIIToUTF16("Four"));
181 controller_->pending_state_.submenu_open = true; 216 }
182 } 217
183 218 void SetupMenuController() {
184 void ResetSelection() { 219 menu_controller_= new MenuController(nullptr, true, nullptr);
185 controller_->SetSelection(nullptr, 220 menu_controller_->owner_ = owner_.get();
186 MenuController::SELECTION_EXIT | 221 menu_controller_->showing_ = true;
187 MenuController::SELECTION_UPDATE_IMMEDIATELY); 222 menu_controller_->SetSelection(
188 } 223 menu_item_.get(), MenuController::SELECTION_UPDATE_IMMEDIATELY);
189 224 }
190 void IncrementSelection() { 225
191 controller_->IncrementSelection(MenuController::INCREMENT_SELECTION_DOWN); 226 scoped_ptr<Widget> owner_;
192 } 227 scoped_ptr<ui::test::EventGenerator> event_generator_;
193 228 scoped_ptr<TestMenuItemViewShown> menu_item_;
194 void DecrementSelection() { 229 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 230
301 DISALLOW_COPY_AND_ASSIGN(MenuControllerTest); 231 DISALLOW_COPY_AND_ASSIGN(MenuControllerTest);
302 }; 232 };
303 233
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) 234 #if defined(OS_LINUX) && defined(USE_X11)
313 // Tests that an event targeter which blocks events will be honored by the menu 235 // Tests that an event targeter which blocks events will be honored by the menu
314 // event dispatcher. 236 // event dispatcher.
315 TEST_F(MenuControllerTest, EventTargeter) { 237 TEST_F(MenuControllerTest, EventTargeter) {
316 { 238 base::MessageLoopForUI::current()->PostTask(
317 // Verify that the menu handles the escape key under normal circumstances. 239 FROM_HERE,
318 scoped_ptr<Widget> owner(CreateOwnerWidget()); 240 base::Bind(&MenuControllerTest::TestEventTargeter,
319 message_loop()->PostTask( 241 base::Unretained(this)));
320 FROM_HERE, 242 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 } 243 }
342 #endif 244 #endif // defined(OS_LINUX) && defined(USE_X11)
343 245
344 #if defined(USE_X11) 246 #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 247 // 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. 248 // details. When the ids aren't managed correctly, we get stuck down touches.
372 TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) { 249 TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) {
373 scoped_ptr<Widget> owner(CreateOwnerWidget());
374 TestEventHandler test_event_handler; 250 TestEventHandler test_event_handler;
375 owner->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler( 251 owner()->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler(
376 &test_event_handler); 252 &test_event_handler);
377 253
378 std::vector<int> devices; 254 std::vector<int> devices;
379 devices.push_back(1); 255 devices.push_back(1);
380 ui::SetUpTouchDevicesForTest(devices); 256 ui::SetUpTouchDevicesForTest(devices);
381 257
382 DispatchTouch(XI_TouchBegin, 0); 258 event_generator()->PressTouchId(0);
383 DispatchTouch(XI_TouchBegin, 1); 259 event_generator()->PressTouchId(1);
384 DispatchTouch(XI_TouchEnd, 0); 260 event_generator()->ReleaseTouchId(0);
385 261
386 message_loop()->PostTask(FROM_HERE, 262 base::MessageLoopForUI::current()->PostTask(
387 base::Bind(&MenuControllerTest::DispatchTouch,
388 base::Unretained(this), XI_TouchEnd, 1));
389
390 message_loop()->PostTask(
391 FROM_HERE, 263 FROM_HERE,
392 base::Bind(&MenuControllerTest::DispatchEscapeAndExpect, 264 base::Bind(&MenuControllerTest::ReleaseTouchId,
393 base::Unretained(this), MenuController::EXIT_OUTERMOST)); 265 base::Unretained(this),
394 266 1));
395 RunMenu(owner.get()); 267
268 base::MessageLoopForUI::current()->PostTask(
269 FROM_HERE,
270 base::Bind(&MenuControllerTest::PressKey,
271 base::Unretained(this),
272 ui::VKEY_ESCAPE));
273
274 RunMenu();
275
276 EXPECT_EQ(MenuController::EXIT_OUTERMOST, menu_exit_type());
396 EXPECT_EQ(0, test_event_handler.outstanding_touches()); 277 EXPECT_EQ(0, test_event_handler.outstanding_touches());
397 278
398 owner->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler( 279 owner()->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler(
399 &test_event_handler); 280 &test_event_handler);
400 } 281 }
401 #endif // defined(USE_X11) 282 #endif // defined(USE_X11)
402 283
403 // Tests that initial selected menu items are correct when items are enabled or 284 // Tests that initial selected menu items are correct when items are enabled or
404 // disabled. 285 // disabled.
405 TEST_F(MenuControllerTest, InitialSelectedItem) { 286 TEST_F(MenuControllerTest, InitialSelectedItem) {
406 scoped_ptr<Widget> owner(CreateOwnerWidget()); 287 // Leave items "Two", "Three", and "Four" enabled.
407 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView); 288 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". 289 // The first selectable item should be item "Two".
416 MenuItemView* first_selectable = 290 MenuItemView* first_selectable =
417 FindInitialSelectableMenuItemDown(menu_item.get()); 291 FindInitialSelectableMenuItemDown(menu_item());
418 ASSERT_NE(nullptr, first_selectable); 292 ASSERT_NE(nullptr, first_selectable);
419 EXPECT_EQ(2, first_selectable->GetCommand()); 293 EXPECT_EQ(2, first_selectable->GetCommand());
420 // The last selectable item should be item "Three". 294 // The last selectable item should be item "Four".
421 MenuItemView* last_selectable = 295 MenuItemView* last_selectable =
422 FindInitialSelectableMenuItemUp(menu_item.get()); 296 FindInitialSelectableMenuItemUp(menu_item());
423 ASSERT_NE(nullptr, last_selectable); 297 ASSERT_NE(nullptr, last_selectable);
424 EXPECT_EQ(3, last_selectable->GetCommand()); 298 EXPECT_EQ(4, last_selectable->GetCommand());
425 299
426 // Leave items "One" and "Two" enabled. 300 // Leave items "One" and "Two" enabled.
427 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true); 301 menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true);
428 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true); 302 menu_item()->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true);
429 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); 303 menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
304 menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
430 // The first selectable item should be item "One". 305 // The first selectable item should be item "One".
431 first_selectable = FindInitialSelectableMenuItemDown(menu_item.get()); 306 first_selectable = FindInitialSelectableMenuItemDown(menu_item());
432 ASSERT_NE(nullptr, first_selectable); 307 ASSERT_NE(nullptr, first_selectable);
433 EXPECT_EQ(1, first_selectable->GetCommand()); 308 EXPECT_EQ(1, first_selectable->GetCommand());
434 // The last selectable item should be item "Two". 309 // The last selectable item should be item "Two".
435 last_selectable = FindInitialSelectableMenuItemUp(menu_item.get()); 310 last_selectable = FindInitialSelectableMenuItemUp(menu_item());
436 ASSERT_NE(nullptr, last_selectable); 311 ASSERT_NE(nullptr, last_selectable);
437 EXPECT_EQ(2, last_selectable->GetCommand()); 312 EXPECT_EQ(2, last_selectable->GetCommand());
438 313
439 // Leave only a single item "One" enabled. 314 // Leave only a single item "One" enabled.
440 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true); 315 menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(true);
441 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false); 316 menu_item()->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false);
442 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); 317 menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
318 menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
443 // The first selectable item should be item "One". 319 // The first selectable item should be item "One".
444 first_selectable = FindInitialSelectableMenuItemDown(menu_item.get()); 320 first_selectable = FindInitialSelectableMenuItemDown(menu_item());
445 ASSERT_NE(nullptr, first_selectable); 321 ASSERT_NE(nullptr, first_selectable);
446 EXPECT_EQ(1, first_selectable->GetCommand()); 322 EXPECT_EQ(1, first_selectable->GetCommand());
447 // The last selectable item should be item "One". 323 // The last selectable item should be item "One".
448 last_selectable = FindInitialSelectableMenuItemUp(menu_item.get()); 324 last_selectable = FindInitialSelectableMenuItemUp(menu_item());
449 ASSERT_NE(nullptr, last_selectable); 325 ASSERT_NE(nullptr, last_selectable);
450 EXPECT_EQ(1, last_selectable->GetCommand()); 326 EXPECT_EQ(1, last_selectable->GetCommand());
451 327
452 // Leave only a single item "Three" enabled. 328 // Leave only a single item "Three" enabled.
453 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false); 329 menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
454 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false); 330 menu_item()->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(false);
455 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(true); 331 menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(true);
332 menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
456 // The first selectable item should be item "Three". 333 // The first selectable item should be item "Three".
457 first_selectable = FindInitialSelectableMenuItemDown(menu_item.get()); 334 first_selectable = FindInitialSelectableMenuItemDown(menu_item());
458 ASSERT_NE(nullptr, first_selectable); 335 ASSERT_NE(nullptr, first_selectable);
459 EXPECT_EQ(3, first_selectable->GetCommand()); 336 EXPECT_EQ(3, first_selectable->GetCommand());
460 // The last selectable item should be item "Three". 337 // The last selectable item should be item "Three".
461 last_selectable = FindInitialSelectableMenuItemUp(menu_item.get()); 338 last_selectable = FindInitialSelectableMenuItemUp(menu_item());
462 ASSERT_NE(nullptr, last_selectable); 339 ASSERT_NE(nullptr, last_selectable);
463 EXPECT_EQ(3, last_selectable->GetCommand()); 340 EXPECT_EQ(3, last_selectable->GetCommand());
464 341
465 // Leave only a single item ("Two") selected. It should be the first and the 342 // Leave only a single item ("Two") selected. It should be the first and the
466 // last selectable item. 343 // last selectable item.
467 menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false); 344 menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false);
468 menu_item->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true); 345 menu_item()->GetSubmenu()->GetMenuItemAt(1)->SetEnabled(true);
469 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); 346 menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
470 first_selectable = FindInitialSelectableMenuItemDown(menu_item.get()); 347 menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
348 first_selectable = FindInitialSelectableMenuItemDown(menu_item());
471 ASSERT_NE(nullptr, first_selectable); 349 ASSERT_NE(nullptr, first_selectable);
472 EXPECT_EQ(2, first_selectable->GetCommand()); 350 EXPECT_EQ(2, first_selectable->GetCommand());
473 last_selectable = FindInitialSelectableMenuItemUp(menu_item.get()); 351 last_selectable = FindInitialSelectableMenuItemUp(menu_item());
474 ASSERT_NE(nullptr, last_selectable); 352 ASSERT_NE(nullptr, last_selectable);
475 EXPECT_EQ(2, last_selectable->GetCommand()); 353 EXPECT_EQ(2, last_selectable->GetCommand());
476 354
477 // There should be no next or previous selectable item since there is only a 355 // There should be no next or previous selectable item since there is only a
478 // single enabled item in the menu. 356 // single enabled item in the menu.
479 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item.get(), 1)); 357 EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item(), 1));
480 EXPECT_EQ(nullptr, FindPreviousSelectableMenuItem(menu_item.get(), 1)); 358 EXPECT_EQ(nullptr, FindPreviousSelectableMenuItem(menu_item(), 1));
481 359
482 // Clear references in menu controller to the menu item that is going away. 360 // Clear references in menu controller to the menu item that is going away.
483 ResetSelection(); 361 ResetSelection();
484 } 362 }
485 363
486 // Tests that opening menu and pressing 'Down' and 'Up' iterates over enabled 364 // Tests that opening menu and pressing 'Down' and 'Up' iterates over enabled
487 // items. 365 // items.
488 TEST_F(MenuControllerTest, NextSelectedItem) { 366 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. 367 // Disabling the item "Three" gets it skipped when using keyboard to navigate.
496 menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); 368 menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false);
497
498 SetupMenu(owner.get(), menu_item.get());
499 369
500 // Fake initial hot selection. 370 // Fake initial hot selection.
501 SetPendingStateItem(menu_item->GetSubmenu()->GetMenuItemAt(0)); 371 SetPendingStateItem(menu_item()->GetSubmenu()->GetMenuItemAt(0));
502 EXPECT_EQ(1, pending_state_item()->GetCommand()); 372 EXPECT_EQ(1, pending_state_item()->GetCommand());
503 373
504 // Move down in the menu. 374 // Move down in the menu.
505 // Select next item. 375 // Select next item.
506 IncrementSelection(); 376 IncrementSelection();
507 EXPECT_EQ(2, pending_state_item()->GetCommand()); 377 EXPECT_EQ(2, pending_state_item()->GetCommand());
508 378
509 // Skip disabled item. 379 // Skip disabled item.
510 IncrementSelection(); 380 IncrementSelection();
511 EXPECT_EQ(4, pending_state_item()->GetCommand()); 381 EXPECT_EQ(4, pending_state_item()->GetCommand());
(...skipping 14 matching lines...) Expand all
526 // Select previous item. 396 // Select previous item.
527 DecrementSelection(); 397 DecrementSelection();
528 EXPECT_EQ(1, pending_state_item()->GetCommand()); 398 EXPECT_EQ(1, pending_state_item()->GetCommand());
529 399
530 // Clear references in menu controller to the menu item that is going away. 400 // Clear references in menu controller to the menu item that is going away.
531 ResetSelection(); 401 ResetSelection();
532 } 402 }
533 403
534 // Tests that opening menu and pressing 'Up' selects the last enabled menu item. 404 // Tests that opening menu and pressing 'Up' selects the last enabled menu item.
535 TEST_F(MenuControllerTest, PreviousSelectedItem) { 405 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. 406 // Disabling the item "Four" gets it skipped when using keyboard to navigate.
543 menu_item->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false); 407 menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false);
544
545 SetupMenu(owner.get(), menu_item.get());
546 408
547 // Fake initial root item selection and submenu showing. 409 // Fake initial root item selection and submenu showing.
548 SetPendingStateItem(menu_item.get()); 410 SetPendingStateItem(menu_item());
549 EXPECT_EQ(0, pending_state_item()->GetCommand()); 411 EXPECT_EQ(0, pending_state_item()->GetCommand());
550 412
551 // Move up and select a previous (in our case the last enabled) item. 413 // Move up and select a previous (in our case the last enabled) item.
552 DecrementSelection(); 414 DecrementSelection();
553 EXPECT_EQ(3, pending_state_item()->GetCommand()); 415 EXPECT_EQ(3, pending_state_item()->GetCommand());
554 416
555 // Clear references in menu controller to the menu item that is going away. 417 // Clear references in menu controller to the menu item that is going away.
556 ResetSelection(); 418 ResetSelection();
557 } 419 }
558 420
559 } // namespace test 421 } // namespace test
560 } // namespace views 422 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698