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

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

Powered by Google App Engine
This is Rietveld 408576698