OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "base/logging.h" | |
6 #include "base/string16.h" | |
7 #include "base/string_number_conversions.h" | |
8 #include "base/utf_string_conversions.h" | 5 #include "base/utf_string_conversions.h" |
9 #include "third_party/skia/include/core/SkColor.h" | |
10 #include "ui/base/keycodes/keyboard_codes.h" | 6 #include "ui/base/keycodes/keyboard_codes.h" |
11 #include "ui/base/models/accelerator.h" | 7 #include "ui/base/models/accelerator.h" |
12 #include "ui/base/models/combobox_model.h" | |
13 #include "ui/gfx/rect.h" | |
14 #include "ui/views/focus/accelerator_handler.h" | 8 #include "ui/views/focus/accelerator_handler.h" |
15 #include "ui/views/focus/focus_manager_factory.h" | 9 #include "ui/views/focus/focus_manager_factory.h" |
16 #include "ui/views/test/views_test_base.h" | 10 #include "ui/views/focus/focus_manager_test.h" |
17 #include "ui/views/widget/root_view.h" | |
18 #include "ui/views/widget/widget.h" | 11 #include "ui/views/widget/widget.h" |
19 #include "ui/views/widget/widget_delegate.h" | 12 #include "views/controls/button/text_button.h" |
20 #include "ui/views/window/non_client_view.h" | 13 #include "views/controls/textfield/textfield.h" |
21 #include "views/background.h" | 14 |
22 #include "views/border.h" | 15 #if !defined(USE_AURA) |
23 #include "views/controls/button/checkbox.h" | 16 #include "views/controls/tabbed_pane/tabbed_pane.h" |
24 #include "views/controls/button/radio_button.h" | |
25 #include "views/controls/combobox/combobox.h" | |
26 #include "views/controls/combobox/native_combobox_wrapper.h" | |
27 #include "views/controls/label.h" | |
28 #include "views/controls/link.h" | |
29 #include "views/controls/native/native_view_host.h" | |
30 #include "views/controls/scroll_view.h" | |
31 #include "views/controls/tabbed_pane/native_tabbed_pane_wrapper.h" | 17 #include "views/controls/tabbed_pane/native_tabbed_pane_wrapper.h" |
32 #include "views/controls/tabbed_pane/tabbed_pane.h" | 18 #endif |
33 #include "views/controls/textfield/textfield.h" | |
34 | 19 |
35 #if defined(OS_LINUX) | 20 #if defined(OS_LINUX) |
36 #include "ui/base/keycodes/keyboard_code_conversion_gtk.h" | 21 #include "ui/base/keycodes/keyboard_code_conversion_gtk.h" |
37 #endif | 22 #endif |
38 | 23 |
39 namespace { | |
40 const int kWindowWidth = 600; | |
41 const int kWindowHeight = 500; | |
42 | |
43 int count = 1; | |
44 | |
45 const int kTopCheckBoxID = count++; // 1 | |
46 const int kLeftContainerID = count++; | |
47 const int kAppleLabelID = count++; | |
48 const int kAppleTextfieldID = count++; | |
49 const int kOrangeLabelID = count++; // 5 | |
50 const int kOrangeTextfieldID = count++; | |
51 const int kBananaLabelID = count++; | |
52 const int kBananaTextfieldID = count++; | |
53 const int kKiwiLabelID = count++; | |
54 const int kKiwiTextfieldID = count++; // 10 | |
55 const int kFruitButtonID = count++; | |
56 const int kFruitCheckBoxID = count++; | |
57 const int kComboboxID = count++; | |
58 | |
59 const int kRightContainerID = count++; | |
60 const int kAsparagusButtonID = count++; // 15 | |
61 const int kBroccoliButtonID = count++; | |
62 const int kCauliflowerButtonID = count++; | |
63 | |
64 const int kInnerContainerID = count++; | |
65 const int kScrollViewID = count++; | |
66 const int kRosettaLinkID = count++; // 20 | |
67 const int kStupeurEtTremblementLinkID = count++; | |
68 const int kDinerGameLinkID = count++; | |
69 const int kRidiculeLinkID = count++; | |
70 const int kClosetLinkID = count++; | |
71 const int kVisitingLinkID = count++; // 25 | |
72 const int kAmelieLinkID = count++; | |
73 const int kJoyeuxNoelLinkID = count++; | |
74 const int kCampingLinkID = count++; | |
75 const int kBriceDeNiceLinkID = count++; | |
76 const int kTaxiLinkID = count++; // 30 | |
77 const int kAsterixLinkID = count++; | |
78 | |
79 const int kOKButtonID = count++; | |
80 const int kCancelButtonID = count++; | |
81 const int kHelpButtonID = count++; | |
82 | |
83 const int kStyleContainerID = count++; // 35 | |
84 const int kBoldCheckBoxID = count++; | |
85 const int kItalicCheckBoxID = count++; | |
86 const int kUnderlinedCheckBoxID = count++; | |
87 const int kStyleHelpLinkID = count++; | |
88 const int kStyleTextEditID = count++; // 40 | |
89 | |
90 const int kSearchContainerID = count++; | |
91 const int kSearchTextfieldID = count++; | |
92 const int kSearchButtonID = count++; | |
93 const int kHelpLinkID = count++; | |
94 | |
95 const int kThumbnailContainerID = count++; // 45 | |
96 const int kThumbnailStarID = count++; | |
97 const int kThumbnailSuperStarID = count++; | |
98 | |
99 } // namespace | |
100 | |
101 namespace views { | 24 namespace views { |
102 | 25 |
103 class FocusManagerTest : public ViewsTestBase, public WidgetDelegate { | |
104 public: | |
105 FocusManagerTest() | |
106 : window_(NULL), | |
107 content_view_(NULL), | |
108 focus_change_listener_(NULL) { | |
109 } | |
110 | |
111 ~FocusManagerTest() { | |
112 } | |
113 | |
114 virtual void SetUp() OVERRIDE { | |
115 ViewsTestBase::SetUp(); | |
116 window_ = Widget::CreateWindowWithBounds(this, bounds()); | |
117 InitContentView(); | |
118 window_->Show(); | |
119 } | |
120 | |
121 virtual void TearDown() OVERRIDE { | |
122 if (focus_change_listener_) | |
123 GetFocusManager()->RemoveFocusChangeListener(focus_change_listener_); | |
124 window_->Close(); | |
125 | |
126 // Flush the message loop to make application verifiers happy. | |
127 RunPendingMessages(); | |
128 ViewsTestBase::TearDown(); | |
129 } | |
130 | |
131 FocusManager* GetFocusManager() { | |
132 return window_->GetFocusManager(); | |
133 } | |
134 | |
135 void FocusNativeView(gfx::NativeView native_view) { | |
136 #if defined(USE_AURA) | |
137 NOTIMPLEMENTED(); | |
138 #elif defined(OS_WIN) | |
139 ::SendMessage(native_view, WM_SETFOCUS, NULL, NULL); | |
140 #else | |
141 gint return_val; | |
142 GdkEventFocus event; | |
143 event.type = GDK_FOCUS_CHANGE; | |
144 event.window = | |
145 gtk_widget_get_root_window(GTK_WIDGET(window_->GetNativeWindow())); | |
146 event.send_event = TRUE; | |
147 event.in = TRUE; | |
148 gtk_signal_emit_by_name(GTK_OBJECT(native_view), "focus-in-event", | |
149 &event, &return_val); | |
150 #endif | |
151 } | |
152 | |
153 // WidgetDelegate Implementation. | |
154 virtual View* GetContentsView() OVERRIDE { | |
155 if (!content_view_) | |
156 content_view_ = new View(); | |
157 return content_view_; | |
158 } | |
159 virtual Widget* GetWidget() OVERRIDE { | |
160 return content_view_->GetWidget(); | |
161 } | |
162 virtual const Widget* GetWidget() const OVERRIDE { | |
163 return content_view_->GetWidget(); | |
164 } | |
165 | |
166 virtual void InitContentView() { | |
167 } | |
168 | |
169 protected: | |
170 virtual gfx::Rect bounds() { | |
171 return gfx::Rect(0, 0, 500, 500); | |
172 } | |
173 | |
174 // Mocks activating/deactivating the window. | |
175 void SimulateActivateWindow() { | |
176 #if defined(USE_AURA) | |
177 NOTIMPLEMENTED(); | |
178 #elif defined(OS_WIN) | |
179 ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_ACTIVE, NULL); | |
180 #else | |
181 gboolean result; | |
182 g_signal_emit_by_name(G_OBJECT(window_->GetNativeWindow()), | |
183 "focus_in_event", 0, &result); | |
184 #endif | |
185 } | |
186 void SimulateDeactivateWindow() { | |
187 #if defined(USE_AURA) | |
188 NOTIMPLEMENTED(); | |
189 #elif defined(OS_WIN) | |
190 ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_INACTIVE, NULL); | |
191 #else | |
192 gboolean result; | |
193 g_signal_emit_by_name(G_OBJECT(window_->GetNativeWindow()), | |
194 "focus_out_event", 0, & result); | |
195 #endif | |
196 } | |
197 | |
198 Widget* window_; | |
199 View* content_view_; | |
200 | |
201 void AddFocusChangeListener(FocusChangeListener* listener) { | |
202 ASSERT_FALSE(focus_change_listener_); | |
203 focus_change_listener_ = listener; | |
204 GetFocusManager()->AddFocusChangeListener(listener); | |
205 } | |
206 | |
207 #if defined(USE_AURA) | |
208 void PostKeyDown(ui::KeyboardCode key_code) { | |
209 NOTIMPLEMENTED(); | |
210 } | |
211 | |
212 void PostKeyUp(ui::KeyboardCode key_code) { | |
213 NOTIMPLEMENTED(); | |
214 } | |
215 #elif defined(OS_WIN) | |
216 void PostKeyDown(ui::KeyboardCode key_code) { | |
217 ::PostMessage(window_->GetNativeWindow(), WM_KEYDOWN, key_code, 0); | |
218 } | |
219 | |
220 void PostKeyUp(ui::KeyboardCode key_code) { | |
221 ::PostMessage(window_->GetNativeWindow(), WM_KEYUP, key_code, 0); | |
222 } | |
223 #elif defined(OS_LINUX) | |
224 void PostKeyDown(ui::KeyboardCode key_code) { | |
225 PostKeyEvent(key_code, true); | |
226 } | |
227 | |
228 void PostKeyUp(ui::KeyboardCode key_code) { | |
229 PostKeyEvent(key_code, false); | |
230 } | |
231 | |
232 void PostKeyEvent(ui::KeyboardCode key_code, bool pressed) { | |
233 int keyval = GdkKeyCodeForWindowsKeyCode(key_code, false); | |
234 GdkKeymapKey* keys; | |
235 gint n_keys; | |
236 gdk_keymap_get_entries_for_keyval( | |
237 gdk_keymap_get_default(), | |
238 keyval, | |
239 &keys, | |
240 &n_keys); | |
241 GdkEvent* event = gdk_event_new(pressed ? GDK_KEY_PRESS : GDK_KEY_RELEASE); | |
242 GdkEventKey* key_event = reinterpret_cast<GdkEventKey*>(event); | |
243 int modifier = 0; | |
244 if (pressed) | |
245 key_event->state = modifier | GDK_KEY_PRESS_MASK; | |
246 else | |
247 key_event->state = modifier | GDK_KEY_RELEASE_MASK; | |
248 | |
249 key_event->window = GTK_WIDGET(window_->GetNativeWindow())->window; | |
250 DCHECK(key_event->window != NULL); | |
251 g_object_ref(key_event->window); | |
252 key_event->send_event = true; | |
253 key_event->time = GDK_CURRENT_TIME; | |
254 key_event->keyval = keyval; | |
255 key_event->hardware_keycode = keys[0].keycode; | |
256 key_event->group = keys[0].group; | |
257 | |
258 g_free(keys); | |
259 | |
260 gdk_event_put(event); | |
261 gdk_event_free(event); | |
262 } | |
263 #endif | |
264 | |
265 private: | |
266 FocusChangeListener* focus_change_listener_; | |
267 | |
268 DISALLOW_COPY_AND_ASSIGN(FocusManagerTest); | |
269 }; | |
270 | |
271 // BorderView is a view containing a native window with its own view hierarchy. | |
272 // It is interesting to test focus traversal from a view hierarchy to an inner | |
273 // view hierarchy. | |
274 class BorderView : public NativeViewHost { | |
275 public: | |
276 explicit BorderView(View* child) : child_(child), widget_(NULL) { | |
277 DCHECK(child); | |
278 set_focusable(false); | |
279 } | |
280 | |
281 virtual ~BorderView() {} | |
282 | |
283 virtual internal::RootView* GetContentsRootView() { | |
284 return static_cast<internal::RootView*>(widget_->GetRootView()); | |
285 } | |
286 | |
287 virtual FocusTraversable* GetFocusTraversable() { | |
288 return static_cast<internal::RootView*>(widget_->GetRootView()); | |
289 } | |
290 | |
291 virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child) { | |
292 NativeViewHost::ViewHierarchyChanged(is_add, parent, child); | |
293 | |
294 if (child == this && is_add) { | |
295 if (!widget_) { | |
296 widget_ = new Widget; | |
297 Widget::InitParams params(Widget::InitParams::TYPE_CONTROL); | |
298 #if defined(OS_WIN) | |
299 params.parent = parent->GetWidget()->GetNativeView(); | |
300 #elif defined(TOOLKIT_USES_GTK) | |
301 params.parent = native_view(); | |
302 #else | |
303 NOTREACHED(); | |
304 #endif | |
305 widget_->Init(params); | |
306 widget_->SetFocusTraversableParentView(this); | |
307 widget_->SetContentsView(child_); | |
308 } | |
309 | |
310 // We have been added to a view hierarchy, attach the native view. | |
311 Attach(widget_->GetNativeView()); | |
312 // Also update the FocusTraversable parent so the focus traversal works. | |
313 static_cast<internal::RootView*>(widget_->GetRootView())-> | |
314 SetFocusTraversableParent(GetWidget()->GetFocusTraversable()); | |
315 } | |
316 } | |
317 | |
318 private: | |
319 View* child_; | |
320 Widget* widget_; | |
321 | |
322 DISALLOW_COPY_AND_ASSIGN(BorderView); | |
323 }; | |
324 | |
325 class DummyComboboxModel : public ui::ComboboxModel { | |
326 public: | |
327 virtual int GetItemCount() { return 10; } | |
328 | |
329 virtual string16 GetItemAt(int index) { | |
330 return ASCIIToUTF16("Item ") + base::IntToString16(index); | |
331 } | |
332 }; | |
333 | |
334 // A View that can act as a pane. | |
335 class PaneView : public View, public FocusTraversable { | |
336 public: | |
337 PaneView() : focus_search_(NULL) {} | |
338 | |
339 // If this method is called, this view will use GetPaneFocusTraversable to | |
340 // have this provided FocusSearch used instead of the default one, allowing | |
341 // you to trap focus within the pane. | |
342 void EnablePaneFocus(FocusSearch* focus_search) { | |
343 focus_search_ = focus_search; | |
344 } | |
345 | |
346 // Overridden from views::View: | |
347 virtual FocusTraversable* GetPaneFocusTraversable() { | |
348 if (focus_search_) | |
349 return this; | |
350 else | |
351 return NULL; | |
352 } | |
353 | |
354 // Overridden from views::FocusTraversable: | |
355 virtual views::FocusSearch* GetFocusSearch() { | |
356 return focus_search_; | |
357 } | |
358 virtual FocusTraversable* GetFocusTraversableParent() { | |
359 return NULL; | |
360 } | |
361 virtual View* GetFocusTraversableParentView() { | |
362 return NULL; | |
363 } | |
364 | |
365 private: | |
366 FocusSearch* focus_search_; | |
367 }; | |
368 | |
369 class FocusTraversalTest : public FocusManagerTest { | |
370 public: | |
371 ~FocusTraversalTest(); | |
372 | |
373 virtual void InitContentView(); | |
374 | |
375 protected: | |
376 FocusTraversalTest(); | |
377 | |
378 virtual gfx::Rect bounds() { | |
379 return gfx::Rect(0, 0, 600, 460); | |
380 } | |
381 | |
382 View* FindViewByID(int id) { | |
383 View* view = GetContentsView()->GetViewByID(id); | |
384 if (view) | |
385 return view; | |
386 if (style_tab_) | |
387 view = style_tab_->GetSelectedTab()->GetViewByID(id); | |
388 if (view) | |
389 return view; | |
390 view = search_border_view_->GetContentsRootView()->GetViewByID(id); | |
391 if (view) | |
392 return view; | |
393 return NULL; | |
394 } | |
395 | |
396 protected: | |
397 TabbedPane* style_tab_; | |
398 BorderView* search_border_view_; | |
399 DummyComboboxModel combobox_model_; | |
400 PaneView* left_container_; | |
401 PaneView* right_container_; | |
402 | |
403 DISALLOW_COPY_AND_ASSIGN(FocusTraversalTest); | |
404 }; | |
405 | |
406 //////////////////////////////////////////////////////////////////////////////// | |
407 // FocusTraversalTest | |
408 //////////////////////////////////////////////////////////////////////////////// | |
409 | |
410 FocusTraversalTest::FocusTraversalTest() | |
411 : style_tab_(NULL), | |
412 search_border_view_(NULL) { | |
413 } | |
414 | |
415 FocusTraversalTest::~FocusTraversalTest() { | |
416 } | |
417 | |
418 void FocusTraversalTest::InitContentView() { | |
419 // Create a complicated view hierarchy with lots of control types for | |
420 // use by all of the focus traversal tests. | |
421 // | |
422 // Class name, ID, and asterisk next to focusable views: | |
423 // | |
424 // View | |
425 // Checkbox * kTopCheckBoxID | |
426 // PaneView kLeftContainerID | |
427 // Label kAppleLabelID | |
428 // Textfield * kAppleTextfieldID | |
429 // Label kOrangeLabelID | |
430 // Textfield * kOrangeTextfieldID | |
431 // Label kBananaLabelID | |
432 // Textfield * kBananaTextfieldID | |
433 // Label kKiwiLabelID | |
434 // Textfield * kKiwiTextfieldID | |
435 // NativeButton * kFruitButtonID | |
436 // Checkbox * kFruitCheckBoxID | |
437 // Combobox * kComboboxID | |
438 // PaneView kRightContainerID | |
439 // RadioButton * kAsparagusButtonID | |
440 // RadioButton * kBroccoliButtonID | |
441 // RadioButton * kCauliflowerButtonID | |
442 // View kInnerContainerID | |
443 // ScrollView kScrollViewID | |
444 // View | |
445 // Link * kRosettaLinkID | |
446 // Link * kStupeurEtTremblementLinkID | |
447 // Link * kDinerGameLinkID | |
448 // Link * kRidiculeLinkID | |
449 // Link * kClosetLinkID | |
450 // Link * kVisitingLinkID | |
451 // Link * kAmelieLinkID | |
452 // Link * kJoyeuxNoelLinkID | |
453 // Link * kCampingLinkID | |
454 // Link * kBriceDeNiceLinkID | |
455 // Link * kTaxiLinkID | |
456 // Link * kAsterixLinkID | |
457 // NativeButton * kOKButtonID | |
458 // NativeButton * kCancelButtonID | |
459 // NativeButton * kHelpButtonID | |
460 // TabbedPane * kStyleContainerID | |
461 // View | |
462 // Checkbox * kBoldCheckBoxID | |
463 // Checkbox * kItalicCheckBoxID | |
464 // Checkbox * kUnderlinedCheckBoxID | |
465 // Link * kStyleHelpLinkID | |
466 // Textfield * kStyleTextEditID | |
467 // Other | |
468 // BorderView kSearchContainerID | |
469 // View | |
470 // Textfield * kSearchTextfieldID | |
471 // NativeButton * kSearchButtonID | |
472 // Link * kHelpLinkID | |
473 // View * kThumbnailContainerID | |
474 // NativeButton * kThumbnailStarID | |
475 // NativeButton * kThumbnailSuperStarID | |
476 | |
477 content_view_->set_background( | |
478 Background::CreateSolidBackground(SK_ColorWHITE)); | |
479 | |
480 Checkbox* cb = new Checkbox(ASCIIToUTF16("This is a checkbox")); | |
481 content_view_->AddChildView(cb); | |
482 // In this fast paced world, who really has time for non hard-coded layout? | |
483 cb->SetBounds(10, 10, 200, 20); | |
484 cb->set_id(kTopCheckBoxID); | |
485 | |
486 left_container_ = new PaneView(); | |
487 left_container_->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK)); | |
488 left_container_->set_background( | |
489 Background::CreateSolidBackground(240, 240, 240)); | |
490 left_container_->set_id(kLeftContainerID); | |
491 content_view_->AddChildView(left_container_); | |
492 left_container_->SetBounds(10, 35, 250, 200); | |
493 | |
494 int label_x = 5; | |
495 int label_width = 50; | |
496 int label_height = 15; | |
497 int text_field_width = 150; | |
498 int y = 10; | |
499 int gap_between_labels = 10; | |
500 | |
501 Label* label = new Label(ASCIIToUTF16("Apple:")); | |
502 label->set_id(kAppleLabelID); | |
503 left_container_->AddChildView(label); | |
504 label->SetBounds(label_x, y, label_width, label_height); | |
505 | |
506 Textfield* text_field = new Textfield(); | |
507 text_field->set_id(kAppleTextfieldID); | |
508 left_container_->AddChildView(text_field); | |
509 text_field->SetBounds(label_x + label_width + 5, y, | |
510 text_field_width, label_height); | |
511 | |
512 y += label_height + gap_between_labels; | |
513 | |
514 label = new Label(ASCIIToUTF16("Orange:")); | |
515 label->set_id(kOrangeLabelID); | |
516 left_container_->AddChildView(label); | |
517 label->SetBounds(label_x, y, label_width, label_height); | |
518 | |
519 text_field = new Textfield(); | |
520 text_field->set_id(kOrangeTextfieldID); | |
521 left_container_->AddChildView(text_field); | |
522 text_field->SetBounds(label_x + label_width + 5, y, | |
523 text_field_width, label_height); | |
524 | |
525 y += label_height + gap_between_labels; | |
526 | |
527 label = new Label(ASCIIToUTF16("Banana:")); | |
528 label->set_id(kBananaLabelID); | |
529 left_container_->AddChildView(label); | |
530 label->SetBounds(label_x, y, label_width, label_height); | |
531 | |
532 text_field = new Textfield(); | |
533 text_field->set_id(kBananaTextfieldID); | |
534 left_container_->AddChildView(text_field); | |
535 text_field->SetBounds(label_x + label_width + 5, y, | |
536 text_field_width, label_height); | |
537 | |
538 y += label_height + gap_between_labels; | |
539 | |
540 label = new Label(ASCIIToUTF16("Kiwi:")); | |
541 label->set_id(kKiwiLabelID); | |
542 left_container_->AddChildView(label); | |
543 label->SetBounds(label_x, y, label_width, label_height); | |
544 | |
545 text_field = new Textfield(); | |
546 text_field->set_id(kKiwiTextfieldID); | |
547 left_container_->AddChildView(text_field); | |
548 text_field->SetBounds(label_x + label_width + 5, y, | |
549 text_field_width, label_height); | |
550 | |
551 y += label_height + gap_between_labels; | |
552 | |
553 NativeTextButton* button = new NativeTextButton(NULL, | |
554 ASCIIToUTF16("Click me")); | |
555 button->SetBounds(label_x, y + 10, 80, 30); | |
556 button->set_id(kFruitButtonID); | |
557 left_container_->AddChildView(button); | |
558 y += 40; | |
559 | |
560 cb = new Checkbox(ASCIIToUTF16("This is another check box")); | |
561 cb->SetBounds(label_x + label_width + 5, y, 180, 20); | |
562 cb->set_id(kFruitCheckBoxID); | |
563 left_container_->AddChildView(cb); | |
564 y += 20; | |
565 | |
566 Combobox* combobox = new Combobox(&combobox_model_); | |
567 combobox->SetBounds(label_x + label_width + 5, y, 150, 30); | |
568 combobox->set_id(kComboboxID); | |
569 left_container_->AddChildView(combobox); | |
570 | |
571 right_container_ = new PaneView(); | |
572 right_container_->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK)); | |
573 right_container_->set_background( | |
574 Background::CreateSolidBackground(240, 240, 240)); | |
575 right_container_->set_id(kRightContainerID); | |
576 content_view_->AddChildView(right_container_); | |
577 right_container_->SetBounds(270, 35, 300, 200); | |
578 | |
579 y = 10; | |
580 int radio_button_height = 18; | |
581 int gap_between_radio_buttons = 10; | |
582 RadioButton* radio_button = new RadioButton(ASCIIToUTF16("Asparagus"), 1); | |
583 radio_button->set_id(kAsparagusButtonID); | |
584 right_container_->AddChildView(radio_button); | |
585 radio_button->SetBounds(5, y, 70, radio_button_height); | |
586 radio_button->SetGroup(1); | |
587 y += radio_button_height + gap_between_radio_buttons; | |
588 radio_button = new RadioButton(ASCIIToUTF16("Broccoli"), 1); | |
589 radio_button->set_id(kBroccoliButtonID); | |
590 right_container_->AddChildView(radio_button); | |
591 radio_button->SetBounds(5, y, 70, radio_button_height); | |
592 radio_button->SetGroup(1); | |
593 RadioButton* radio_button_to_check = radio_button; | |
594 y += radio_button_height + gap_between_radio_buttons; | |
595 radio_button = new RadioButton(ASCIIToUTF16("Cauliflower"), 1); | |
596 radio_button->set_id(kCauliflowerButtonID); | |
597 right_container_->AddChildView(radio_button); | |
598 radio_button->SetBounds(5, y, 70, radio_button_height); | |
599 radio_button->SetGroup(1); | |
600 y += radio_button_height + gap_between_radio_buttons; | |
601 | |
602 View* inner_container = new View(); | |
603 inner_container->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK)); | |
604 inner_container->set_background( | |
605 Background::CreateSolidBackground(230, 230, 230)); | |
606 inner_container->set_id(kInnerContainerID); | |
607 right_container_->AddChildView(inner_container); | |
608 inner_container->SetBounds(100, 10, 150, 180); | |
609 | |
610 ScrollView* scroll_view = new ScrollView(); | |
611 scroll_view->set_id(kScrollViewID); | |
612 inner_container->AddChildView(scroll_view); | |
613 scroll_view->SetBounds(1, 1, 148, 178); | |
614 | |
615 View* scroll_content = new View(); | |
616 scroll_content->SetBounds(0, 0, 200, 200); | |
617 scroll_content->set_background( | |
618 Background::CreateSolidBackground(200, 200, 200)); | |
619 scroll_view->SetContents(scroll_content); | |
620 | |
621 static const char* const kTitles[] = { | |
622 "Rosetta", "Stupeur et tremblement", "The diner game", | |
623 "Ridicule", "Le placard", "Les Visiteurs", "Amelie", | |
624 "Joyeux Noel", "Camping", "Brice de Nice", | |
625 "Taxi", "Asterix" | |
626 }; | |
627 | |
628 static const int kIDs[] = { | |
629 kRosettaLinkID, kStupeurEtTremblementLinkID, kDinerGameLinkID, | |
630 kRidiculeLinkID, kClosetLinkID, kVisitingLinkID, kAmelieLinkID, | |
631 kJoyeuxNoelLinkID, kCampingLinkID, kBriceDeNiceLinkID, | |
632 kTaxiLinkID, kAsterixLinkID | |
633 }; | |
634 | |
635 DCHECK(arraysize(kTitles) == arraysize(kIDs)); | |
636 | |
637 y = 5; | |
638 for (size_t i = 0; i < arraysize(kTitles); ++i) { | |
639 Link* link = new Link(ASCIIToUTF16(kTitles[i])); | |
640 link->SetHorizontalAlignment(Label::ALIGN_LEFT); | |
641 link->set_id(kIDs[i]); | |
642 scroll_content->AddChildView(link); | |
643 link->SetBounds(5, y, 300, 15); | |
644 y += 15; | |
645 } | |
646 | |
647 y = 250; | |
648 int width = 60; | |
649 button = new NativeTextButton(NULL, ASCIIToUTF16("OK")); | |
650 button->set_id(kOKButtonID); | |
651 button->SetIsDefault(true); | |
652 | |
653 content_view_->AddChildView(button); | |
654 button->SetBounds(150, y, width, 30); | |
655 | |
656 button = new NativeTextButton(NULL, ASCIIToUTF16("Cancel")); | |
657 button->set_id(kCancelButtonID); | |
658 content_view_->AddChildView(button); | |
659 button->SetBounds(220, y, width, 30); | |
660 | |
661 button = new NativeTextButton(NULL, ASCIIToUTF16("Help")); | |
662 button->set_id(kHelpButtonID); | |
663 content_view_->AddChildView(button); | |
664 button->SetBounds(290, y, width, 30); | |
665 | |
666 y += 40; | |
667 | |
668 // Left bottom box with style checkboxes. | |
669 View* contents = new View(); | |
670 contents->set_background(Background::CreateSolidBackground(SK_ColorWHITE)); | |
671 cb = new Checkbox(ASCIIToUTF16("Bold")); | |
672 contents->AddChildView(cb); | |
673 cb->SetBounds(10, 10, 50, 20); | |
674 cb->set_id(kBoldCheckBoxID); | |
675 | |
676 cb = new Checkbox(ASCIIToUTF16("Italic")); | |
677 contents->AddChildView(cb); | |
678 cb->SetBounds(70, 10, 50, 20); | |
679 cb->set_id(kItalicCheckBoxID); | |
680 | |
681 cb = new Checkbox(ASCIIToUTF16("Underlined")); | |
682 contents->AddChildView(cb); | |
683 cb->SetBounds(130, 10, 70, 20); | |
684 cb->set_id(kUnderlinedCheckBoxID); | |
685 | |
686 Link* link = new Link(ASCIIToUTF16("Help")); | |
687 contents->AddChildView(link); | |
688 link->SetBounds(10, 35, 70, 10); | |
689 link->set_id(kStyleHelpLinkID); | |
690 | |
691 text_field = new Textfield(); | |
692 contents->AddChildView(text_field); | |
693 text_field->SetBounds(10, 50, 100, 20); | |
694 text_field->set_id(kStyleTextEditID); | |
695 | |
696 style_tab_ = new TabbedPane(); | |
697 style_tab_->set_id(kStyleContainerID); | |
698 content_view_->AddChildView(style_tab_); | |
699 style_tab_->SetBounds(10, y, 210, 100); | |
700 style_tab_->AddTab(ASCIIToUTF16("Style"), contents); | |
701 style_tab_->AddTab(ASCIIToUTF16("Other"), new View()); | |
702 | |
703 // Right bottom box with search. | |
704 contents = new View(); | |
705 contents->set_background(Background::CreateSolidBackground(SK_ColorWHITE)); | |
706 text_field = new Textfield(); | |
707 contents->AddChildView(text_field); | |
708 text_field->SetBounds(10, 10, 100, 20); | |
709 text_field->set_id(kSearchTextfieldID); | |
710 | |
711 button = new NativeTextButton(NULL, ASCIIToUTF16("Search")); | |
712 contents->AddChildView(button); | |
713 button->SetBounds(112, 5, 60, 30); | |
714 button->set_id(kSearchButtonID); | |
715 | |
716 link = new Link(ASCIIToUTF16("Help")); | |
717 link->SetHorizontalAlignment(Label::ALIGN_LEFT); | |
718 link->set_id(kHelpLinkID); | |
719 contents->AddChildView(link); | |
720 link->SetBounds(175, 10, 30, 20); | |
721 | |
722 search_border_view_ = new BorderView(contents); | |
723 search_border_view_->set_id(kSearchContainerID); | |
724 | |
725 content_view_->AddChildView(search_border_view_); | |
726 search_border_view_->SetBounds(300, y, 240, 50); | |
727 | |
728 y += 60; | |
729 | |
730 contents = new View(); | |
731 contents->set_focusable(true); | |
732 contents->set_background(Background::CreateSolidBackground(SK_ColorBLUE)); | |
733 contents->set_id(kThumbnailContainerID); | |
734 button = new NativeTextButton(NULL, ASCIIToUTF16("Star")); | |
735 contents->AddChildView(button); | |
736 button->SetBounds(5, 5, 50, 30); | |
737 button->set_id(kThumbnailStarID); | |
738 button = new NativeTextButton(NULL, ASCIIToUTF16("SuperStar")); | |
739 contents->AddChildView(button); | |
740 button->SetBounds(60, 5, 100, 30); | |
741 button->set_id(kThumbnailSuperStarID); | |
742 | |
743 content_view_->AddChildView(contents); | |
744 contents->SetBounds(250, y, 200, 50); | |
745 // We can only call RadioButton::SetChecked() on the radio-button is part of | |
746 // the view hierarchy. | |
747 radio_button_to_check->SetChecked(true); | |
748 } | |
749 | |
750 //////////////////////////////////////////////////////////////////////////////// | |
751 // The tests | |
752 //////////////////////////////////////////////////////////////////////////////// | |
753 | |
754 enum FocusTestEventType { | 26 enum FocusTestEventType { |
755 ON_FOCUS = 0, | 27 ON_FOCUS = 0, |
756 ON_BLUR | 28 ON_BLUR |
757 }; | 29 }; |
758 | 30 |
759 struct FocusTestEvent { | 31 struct FocusTestEvent { |
760 FocusTestEvent(FocusTestEventType type, int view_id) | 32 FocusTestEvent(FocusTestEventType type, int view_id) |
761 : type(type), | 33 : type(type), |
762 view_id(view_id) { | 34 view_id(view_id) { |
763 } | 35 } |
(...skipping 24 matching lines...) Expand all Loading... |
788 | 60 |
789 // Tests that the appropriate Focus related methods are called when a View | 61 // Tests that the appropriate Focus related methods are called when a View |
790 // gets/loses focus. | 62 // gets/loses focus. |
791 TEST_F(FocusManagerTest, ViewFocusCallbacks) { | 63 TEST_F(FocusManagerTest, ViewFocusCallbacks) { |
792 std::vector<FocusTestEvent> event_list; | 64 std::vector<FocusTestEvent> event_list; |
793 const int kView1ID = 1; | 65 const int kView1ID = 1; |
794 const int kView2ID = 2; | 66 const int kView2ID = 2; |
795 | 67 |
796 SimpleTestView* view1 = new SimpleTestView(&event_list, kView1ID); | 68 SimpleTestView* view1 = new SimpleTestView(&event_list, kView1ID); |
797 SimpleTestView* view2 = new SimpleTestView(&event_list, kView2ID); | 69 SimpleTestView* view2 = new SimpleTestView(&event_list, kView2ID); |
798 content_view_->AddChildView(view1); | 70 GetContentsView()->AddChildView(view1); |
799 content_view_->AddChildView(view2); | 71 GetContentsView()->AddChildView(view2); |
800 | 72 |
801 view1->RequestFocus(); | 73 view1->RequestFocus(); |
802 ASSERT_EQ(1, static_cast<int>(event_list.size())); | 74 ASSERT_EQ(1, static_cast<int>(event_list.size())); |
803 EXPECT_EQ(ON_FOCUS, event_list[0].type); | 75 EXPECT_EQ(ON_FOCUS, event_list[0].type); |
804 EXPECT_EQ(kView1ID, event_list[0].view_id); | 76 EXPECT_EQ(kView1ID, event_list[0].view_id); |
805 | 77 |
806 event_list.clear(); | 78 event_list.clear(); |
807 view2->RequestFocus(); | 79 view2->RequestFocus(); |
808 ASSERT_EQ(2, static_cast<int>(event_list.size())); | 80 ASSERT_EQ(2, static_cast<int>(event_list.size())); |
809 EXPECT_EQ(ON_BLUR, event_list[0].type); | 81 EXPECT_EQ(ON_BLUR, event_list[0].type); |
810 EXPECT_EQ(kView1ID, event_list[0].view_id); | 82 EXPECT_EQ(kView1ID, event_list[0].view_id); |
811 EXPECT_EQ(ON_FOCUS, event_list[1].type); | 83 EXPECT_EQ(ON_FOCUS, event_list[1].type); |
812 EXPECT_EQ(kView2ID, event_list[1].view_id); | 84 EXPECT_EQ(kView2ID, event_list[1].view_id); |
813 | 85 |
814 event_list.clear(); | 86 event_list.clear(); |
815 GetFocusManager()->ClearFocus(); | 87 GetFocusManager()->ClearFocus(); |
816 ASSERT_EQ(1, static_cast<int>(event_list.size())); | 88 ASSERT_EQ(1, static_cast<int>(event_list.size())); |
817 EXPECT_EQ(ON_BLUR, event_list[0].type); | 89 EXPECT_EQ(ON_BLUR, event_list[0].type); |
818 EXPECT_EQ(kView2ID, event_list[0].view_id); | 90 EXPECT_EQ(kView2ID, event_list[0].view_id); |
819 } | 91 } |
820 | 92 |
821 typedef std::pair<View*, View*> ViewPair; | |
822 class TestFocusChangeListener : public FocusChangeListener { | |
823 public: | |
824 virtual void OnWillChangeFocus(View* focused_before, View* focused_now) { | |
825 focus_changes_.push_back(ViewPair(focused_before, focused_now)); | |
826 } | |
827 virtual void OnDidChangeFocus(View* focused_before, View* focused_now) { | |
828 } | |
829 | |
830 const std::vector<ViewPair>& focus_changes() const { return focus_changes_; } | |
831 void ClearFocusChanges() { focus_changes_.clear(); } | |
832 | |
833 private: | |
834 // A vector of which views lost/gained focus. | |
835 std::vector<ViewPair> focus_changes_; | |
836 }; | |
837 | |
838 TEST_F(FocusManagerTest, FocusChangeListener) { | 93 TEST_F(FocusManagerTest, FocusChangeListener) { |
839 View* view1 = new View(); | 94 View* view1 = new View(); |
840 view1->set_focusable(true); | 95 view1->set_focusable(true); |
841 View* view2 = new View(); | 96 View* view2 = new View(); |
842 view2->set_focusable(true); | 97 view2->set_focusable(true); |
843 content_view_->AddChildView(view1); | 98 GetContentsView()->AddChildView(view1); |
844 content_view_->AddChildView(view2); | 99 GetContentsView()->AddChildView(view2); |
845 | 100 |
846 TestFocusChangeListener listener; | 101 TestFocusChangeListener listener; |
847 AddFocusChangeListener(&listener); | 102 AddFocusChangeListener(&listener); |
848 | 103 |
849 // Visual Studio 2010 has problems converting NULL to the null pointer for | 104 // Visual Studio 2010 has problems converting NULL to the null pointer for |
850 // std::pair. See http://connect.microsoft.com/VisualStudio/feedback/details/
520043/error-converting-from-null-to-a-pointer-type-in-std-pair | 105 // std::pair. See http://connect.microsoft.com/VisualStudio/feedback/details/
520043/error-converting-from-null-to-a-pointer-type-in-std-pair |
851 // It will work if we pass nullptr. | 106 // It will work if we pass nullptr. |
852 #if defined(_MSC_VER) && _MSC_VER >= 1600 | 107 #if defined(_MSC_VER) && _MSC_VER >= 1600 |
853 views::View* null_view = nullptr; | 108 views::View* null_view = nullptr; |
854 #else | 109 #else |
855 views::View* null_view = NULL; | 110 views::View* null_view = NULL; |
856 #endif | 111 #endif |
857 | 112 |
858 view1->RequestFocus(); | 113 view1->RequestFocus(); |
859 ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); | 114 ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); |
860 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view1)); | 115 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view1)); |
861 listener.ClearFocusChanges(); | 116 listener.ClearFocusChanges(); |
862 | 117 |
863 view2->RequestFocus(); | 118 view2->RequestFocus(); |
864 ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); | 119 ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); |
865 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(view1, view2)); | 120 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(view1, view2)); |
866 listener.ClearFocusChanges(); | 121 listener.ClearFocusChanges(); |
867 | 122 |
868 GetFocusManager()->ClearFocus(); | 123 GetFocusManager()->ClearFocus(); |
869 ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); | 124 ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); |
870 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(view2, null_view)); | 125 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(view2, null_view)); |
871 } | 126 } |
872 | 127 |
873 class TestNativeButton : public NativeTextButton { | 128 #if !defined(USE_AURA) |
874 public: | |
875 explicit TestNativeButton(const string16& text) | |
876 : NativeTextButton(NULL, text) { | |
877 }; | |
878 virtual gfx::NativeView TestGetNativeControlView() { | |
879 return GetWidget()->GetNativeView(); | |
880 } | |
881 }; | |
882 | |
883 class TestCheckbox : public Checkbox { | |
884 public: | |
885 explicit TestCheckbox(const string16& text) : Checkbox(text) { | |
886 }; | |
887 virtual gfx::NativeView TestGetNativeControlView() { | |
888 return GetWidget()->GetNativeView(); | |
889 } | |
890 }; | |
891 | |
892 class TestRadioButton : public RadioButton { | |
893 public: | |
894 explicit TestRadioButton(const string16& text) | |
895 : RadioButton(text, 1) { | |
896 } | |
897 virtual gfx::NativeView TestGetNativeControlView() { | |
898 return GetWidget()->GetNativeView(); | |
899 } | |
900 }; | |
901 | |
902 class TestTextfield : public Textfield { | 129 class TestTextfield : public Textfield { |
903 public: | 130 public: |
904 TestTextfield() { } | 131 TestTextfield() {} |
905 virtual gfx::NativeView TestGetNativeControlView() { | 132 virtual gfx::NativeView TestGetNativeControlView() { |
906 return native_wrapper_->GetTestingHandle(); | 133 return native_wrapper_->GetTestingHandle(); |
907 } | 134 } |
908 }; | 135 }; |
909 | 136 |
910 class TestCombobox : public Combobox, public ui::ComboboxModel { | |
911 public: | |
912 TestCombobox() : Combobox(this) { } | |
913 virtual gfx::NativeView TestGetNativeControlView() { | |
914 return native_wrapper_->GetTestingHandle(); | |
915 } | |
916 virtual int GetItemCount() { | |
917 return 10; | |
918 } | |
919 virtual string16 GetItemAt(int index) { | |
920 return ASCIIToUTF16("Hello combo"); | |
921 } | |
922 }; | |
923 | |
924 class TestTabbedPane : public TabbedPane { | 137 class TestTabbedPane : public TabbedPane { |
925 public: | 138 public: |
926 TestTabbedPane() { } | 139 TestTabbedPane() {} |
927 virtual gfx::NativeView TestGetNativeControlView() { | 140 virtual gfx::NativeView TestGetNativeControlView() { |
928 return native_tabbed_pane_->GetTestingHandle(); | 141 return native_tabbed_pane_->GetTestingHandle(); |
929 } | 142 } |
930 }; | 143 }; |
931 | 144 |
932 #if !defined(TOUCH_UI) | 145 // Tests that NativeControls do set the focused View appropriately on the |
933 // TODO(oshima): replace TOUCH_UI with PURE_VIEWS | |
934 | |
935 // Tests that NativeControls do set the focus View appropriately on the | |
936 // FocusManager. | 146 // FocusManager. |
937 TEST_F(FocusManagerTest, FAILS_FocusNativeControls) { | 147 TEST_F(FocusManagerTest, FAILS_FocusNativeControls) { |
938 TestTextfield* textfield = new TestTextfield(); | 148 TestTextfield* textfield = new TestTextfield(); |
939 TestTabbedPane* tabbed_pane = new TestTabbedPane(); | 149 TestTabbedPane* tabbed_pane = new TestTabbedPane(); |
940 TestTextfield* textfield2 = new TestTextfield(); | 150 TestTextfield* textfield2 = new TestTextfield(); |
941 | 151 |
942 content_view_->AddChildView(textfield); | 152 GetContentsView()->AddChildView(textfield); |
943 content_view_->AddChildView(tabbed_pane); | 153 GetContentsView()->AddChildView(tabbed_pane); |
944 | 154 |
945 tabbed_pane->AddTab(ASCIIToUTF16("Awesome textfield"), textfield2); | 155 tabbed_pane->AddTab(ASCIIToUTF16("Awesome textfield"), textfield2); |
946 | 156 |
947 // Simulate the native view getting the native focus (such as by user click). | 157 // Simulate the native view getting the native focus (such as by user click). |
948 FocusNativeView(textfield->TestGetNativeControlView()); | 158 GetWidget()->FocusNativeView(textfield->TestGetNativeControlView()); |
949 EXPECT_EQ(textfield, GetFocusManager()->GetFocusedView()); | 159 EXPECT_EQ(textfield, GetFocusManager()->GetFocusedView()); |
950 | 160 |
951 FocusNativeView(tabbed_pane->TestGetNativeControlView()); | 161 GetWidget()->FocusNativeView(tabbed_pane->TestGetNativeControlView()); |
952 EXPECT_EQ(tabbed_pane, GetFocusManager()->GetFocusedView()); | 162 EXPECT_EQ(tabbed_pane, GetFocusManager()->GetFocusedView()); |
953 | 163 |
954 FocusNativeView(textfield2->TestGetNativeControlView()); | 164 GetWidget()->FocusNativeView(textfield2->TestGetNativeControlView()); |
955 EXPECT_EQ(textfield2, GetFocusManager()->GetFocusedView()); | 165 EXPECT_EQ(textfield2, GetFocusManager()->GetFocusedView()); |
956 } | 166 } |
957 #endif | 167 #endif |
958 | 168 |
959 // On linux, we don't store/restore focused view because gtk handles | 169 // There is no tabbed pane in Aura. |
960 // this (and pure views will be the same). | 170 #if !defined(USE_AURA) |
961 #if defined(OS_WIN) | |
962 | |
963 // Test that when activating/deactivating the top window, the focus is stored/ | |
964 // restored properly. | |
965 TEST_F(FocusManagerTest, FocusStoreRestore) { | |
966 // Simulate an activate, otherwise the deactivate isn't going to do anything. | |
967 SimulateActivateWindow(); | |
968 | |
969 NativeTextButton* button = new NativeTextButton(NULL, | |
970 ASCIIToUTF16("Press me")); | |
971 View* view = new View(); | |
972 view->set_focusable(true); | |
973 | |
974 content_view_->AddChildView(button); | |
975 button->SetBounds(10, 10, 200, 30); | |
976 content_view_->AddChildView(view); | |
977 RunPendingMessages(); | |
978 | |
979 TestFocusChangeListener listener; | |
980 AddFocusChangeListener(&listener); | |
981 | |
982 view->RequestFocus(); | |
983 RunPendingMessages(); | |
984 // MessageLoopForUI::current()->RunWithDispatcher(new AcceleratorHandler()); | |
985 | |
986 // Visual Studio 2010 has problems converting NULL to the null pointer for | |
987 // std::pair. See http://connect.microsoft.com/VisualStudio/feedback/details/
520043/error-converting-from-null-to-a-pointer-type-in-std-pair | |
988 // It will work if we pass nullptr. | |
989 #if defined(_MSC_VER) && _MSC_VER >= 1600 | |
990 views::View* null_view = nullptr; | |
991 #else | |
992 views::View* null_view = NULL; | |
993 #endif | |
994 | |
995 // Deacivate the window, it should store its focus. | |
996 SimulateDeactivateWindow(); | |
997 EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView()); | |
998 ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size())); | |
999 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view)); | |
1000 EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(view, null_view)); | |
1001 listener.ClearFocusChanges(); | |
1002 | |
1003 // Reactivate, focus should come-back to the previously focused view. | |
1004 SimulateActivateWindow(); | |
1005 EXPECT_EQ(view, GetFocusManager()->GetFocusedView()); | |
1006 ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); | |
1007 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view)); | |
1008 listener.ClearFocusChanges(); | |
1009 | |
1010 // Same test with a NativeControl. | |
1011 button->RequestFocus(); | |
1012 SimulateDeactivateWindow(); | |
1013 EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView()); | |
1014 ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size())); | |
1015 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(view, button)); | |
1016 EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(button, null_view)); | |
1017 listener.ClearFocusChanges(); | |
1018 | |
1019 SimulateActivateWindow(); | |
1020 EXPECT_EQ(button, GetFocusManager()->GetFocusedView()); | |
1021 ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); | |
1022 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, button)); | |
1023 listener.ClearFocusChanges(); | |
1024 | |
1025 /* | |
1026 // Now test that while the window is inactive we can change the focused view | |
1027 // (we do that in several places). | |
1028 SimulateDeactivateWindow(); | |
1029 // TODO: would have to mock the window being inactive (with a TestWidgetWin | |
1030 // that would return false on IsActive()). | |
1031 GetFocusManager()->SetFocusedView(view); | |
1032 ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_ACTIVE, NULL); | |
1033 | |
1034 EXPECT_EQ(view, GetFocusManager()->GetFocusedView()); | |
1035 ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size())); | |
1036 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(button, null_view)); | |
1037 EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(null_view, view)); | |
1038 */ | |
1039 } | |
1040 #endif | |
1041 | |
1042 #if !defined(TOUCH_UI) | |
1043 // TODO(oshima): There is no tabbed pane in pure views. Replace it | |
1044 // with different implementation. | |
1045 | |
1046 TEST_F(FocusManagerTest, ContainsView) { | 171 TEST_F(FocusManagerTest, ContainsView) { |
1047 View* view = new View(); | 172 View* view = new View(); |
1048 scoped_ptr<View> detached_view(new View()); | 173 scoped_ptr<View> detached_view(new View()); |
1049 TabbedPane* tabbed_pane = new TabbedPane(); | 174 TabbedPane* tabbed_pane = new TabbedPane(); |
1050 TabbedPane* nested_tabbed_pane = new TabbedPane(); | 175 TabbedPane* nested_tabbed_pane = new TabbedPane(); |
1051 NativeTextButton* tab_button = new NativeTextButton( | 176 NativeTextButton* tab_button = new NativeTextButton( |
1052 NULL, ASCIIToUTF16("tab button")); | 177 NULL, ASCIIToUTF16("tab button")); |
1053 | 178 |
1054 content_view_->AddChildView(view); | 179 GetContentsView()->AddChildView(view); |
1055 content_view_->AddChildView(tabbed_pane); | 180 GetContentsView()->AddChildView(tabbed_pane); |
1056 // Adding a View inside a TabbedPane to test the case of nested root view. | 181 // Adding a View inside a TabbedPane to test the case of nested root view. |
1057 | 182 |
1058 tabbed_pane->AddTab(ASCIIToUTF16("Awesome tab"), nested_tabbed_pane); | 183 tabbed_pane->AddTab(ASCIIToUTF16("Awesome tab"), nested_tabbed_pane); |
1059 nested_tabbed_pane->AddTab(ASCIIToUTF16("Awesomer tab"), tab_button); | 184 nested_tabbed_pane->AddTab(ASCIIToUTF16("Awesomer tab"), tab_button); |
1060 | 185 |
1061 EXPECT_TRUE(GetFocusManager()->ContainsView(view)); | 186 EXPECT_TRUE(GetFocusManager()->ContainsView(view)); |
1062 EXPECT_TRUE(GetFocusManager()->ContainsView(tabbed_pane)); | 187 EXPECT_TRUE(GetFocusManager()->ContainsView(tabbed_pane)); |
1063 EXPECT_TRUE(GetFocusManager()->ContainsView(nested_tabbed_pane)); | 188 EXPECT_TRUE(GetFocusManager()->ContainsView(nested_tabbed_pane)); |
1064 EXPECT_TRUE(GetFocusManager()->ContainsView(tab_button)); | 189 EXPECT_TRUE(GetFocusManager()->ContainsView(tab_button)); |
1065 EXPECT_FALSE(GetFocusManager()->ContainsView(detached_view.get())); | 190 EXPECT_FALSE(GetFocusManager()->ContainsView(detached_view.get())); |
1066 } | 191 } |
1067 #endif | 192 #endif |
1068 | 193 |
1069 TEST_F(FocusTraversalTest, NormalTraversal) { | |
1070 const int kTraversalIDs[] = { kTopCheckBoxID, kAppleTextfieldID, | |
1071 kOrangeTextfieldID, kBananaTextfieldID, kKiwiTextfieldID, | |
1072 kFruitButtonID, kFruitCheckBoxID, kComboboxID, kBroccoliButtonID, | |
1073 kRosettaLinkID, kStupeurEtTremblementLinkID, | |
1074 kDinerGameLinkID, kRidiculeLinkID, kClosetLinkID, kVisitingLinkID, | |
1075 kAmelieLinkID, kJoyeuxNoelLinkID, kCampingLinkID, kBriceDeNiceLinkID, | |
1076 kTaxiLinkID, kAsterixLinkID, kOKButtonID, kCancelButtonID, kHelpButtonID, | |
1077 kStyleContainerID, kBoldCheckBoxID, kItalicCheckBoxID, | |
1078 kUnderlinedCheckBoxID, kStyleHelpLinkID, kStyleTextEditID, | |
1079 kSearchTextfieldID, kSearchButtonID, kHelpLinkID, | |
1080 kThumbnailContainerID, kThumbnailStarID, kThumbnailSuperStarID }; | |
1081 | |
1082 // Uncomment the following line if you want to test manually the UI of this | |
1083 // test. | |
1084 // MessageLoopForUI::current()->RunWithDispatcher(new AcceleratorHandler()); | |
1085 | |
1086 // Let's traverse the whole focus hierarchy (several times, to make sure it | |
1087 // loops OK). | |
1088 GetFocusManager()->ClearFocus(); | |
1089 for (int i = 0; i < 3; ++i) { | |
1090 for (size_t j = 0; j < arraysize(kTraversalIDs); j++) { | |
1091 GetFocusManager()->AdvanceFocus(false); | |
1092 View* focused_view = GetFocusManager()->GetFocusedView(); | |
1093 EXPECT_TRUE(focused_view != NULL); | |
1094 if (focused_view) | |
1095 EXPECT_EQ(kTraversalIDs[j], focused_view->id()); | |
1096 } | |
1097 } | |
1098 | |
1099 // Let's traverse in reverse order. | |
1100 GetFocusManager()->ClearFocus(); | |
1101 for (int i = 0; i < 3; ++i) { | |
1102 for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) { | |
1103 GetFocusManager()->AdvanceFocus(true); | |
1104 View* focused_view = GetFocusManager()->GetFocusedView(); | |
1105 EXPECT_TRUE(focused_view != NULL); | |
1106 if (focused_view) | |
1107 EXPECT_EQ(kTraversalIDs[j], focused_view->id()); | |
1108 } | |
1109 } | |
1110 } | |
1111 | |
1112 TEST_F(FocusTraversalTest, TraversalWithNonEnabledViews) { | |
1113 const int kDisabledIDs[] = { | |
1114 kBananaTextfieldID, kFruitCheckBoxID, kComboboxID, kAsparagusButtonID, | |
1115 kCauliflowerButtonID, kClosetLinkID, kVisitingLinkID, kBriceDeNiceLinkID, | |
1116 kTaxiLinkID, kAsterixLinkID, kHelpButtonID, kBoldCheckBoxID, | |
1117 kSearchTextfieldID, kHelpLinkID }; | |
1118 | |
1119 const int kTraversalIDs[] = { kTopCheckBoxID, kAppleTextfieldID, | |
1120 kOrangeTextfieldID, kKiwiTextfieldID, kFruitButtonID, kBroccoliButtonID, | |
1121 kRosettaLinkID, kStupeurEtTremblementLinkID, kDinerGameLinkID, | |
1122 kRidiculeLinkID, kAmelieLinkID, kJoyeuxNoelLinkID, kCampingLinkID, | |
1123 kOKButtonID, kCancelButtonID, kStyleContainerID, kItalicCheckBoxID, | |
1124 kUnderlinedCheckBoxID, kStyleHelpLinkID, kStyleTextEditID, | |
1125 kSearchButtonID, kThumbnailContainerID, kThumbnailStarID, | |
1126 kThumbnailSuperStarID }; | |
1127 | |
1128 // Let's disable some views. | |
1129 for (size_t i = 0; i < arraysize(kDisabledIDs); i++) { | |
1130 View* v = FindViewByID(kDisabledIDs[i]); | |
1131 ASSERT_TRUE(v != NULL); | |
1132 v->SetEnabled(false); | |
1133 } | |
1134 | |
1135 // Uncomment the following line if you want to test manually the UI of this | |
1136 // test. | |
1137 // MessageLoopForUI::current()->RunWithDispatcher(new AcceleratorHandler()); | |
1138 | |
1139 View* focused_view; | |
1140 // Let's do one traversal (several times, to make sure it loops ok). | |
1141 GetFocusManager()->ClearFocus(); | |
1142 for (int i = 0; i < 3; ++i) { | |
1143 for (size_t j = 0; j < arraysize(kTraversalIDs); j++) { | |
1144 GetFocusManager()->AdvanceFocus(false); | |
1145 focused_view = GetFocusManager()->GetFocusedView(); | |
1146 EXPECT_TRUE(focused_view != NULL); | |
1147 if (focused_view) | |
1148 EXPECT_EQ(kTraversalIDs[j], focused_view->id()); | |
1149 } | |
1150 } | |
1151 | |
1152 // Same thing in reverse. | |
1153 GetFocusManager()->ClearFocus(); | |
1154 for (int i = 0; i < 3; ++i) { | |
1155 for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) { | |
1156 GetFocusManager()->AdvanceFocus(true); | |
1157 focused_view = GetFocusManager()->GetFocusedView(); | |
1158 EXPECT_TRUE(focused_view != NULL); | |
1159 if (focused_view) | |
1160 EXPECT_EQ(kTraversalIDs[j], focused_view->id()); | |
1161 } | |
1162 } | |
1163 } | |
1164 | |
1165 TEST_F(FocusTraversalTest, TraversalWithInvisibleViews) { | |
1166 const int kInvisibleIDs[] = { kTopCheckBoxID, kOKButtonID, | |
1167 kThumbnailContainerID }; | |
1168 | |
1169 const int kTraversalIDs[] = { kAppleTextfieldID, kOrangeTextfieldID, | |
1170 kBananaTextfieldID, kKiwiTextfieldID, kFruitButtonID, kFruitCheckBoxID, | |
1171 kComboboxID, kBroccoliButtonID, kRosettaLinkID, | |
1172 kStupeurEtTremblementLinkID, kDinerGameLinkID, kRidiculeLinkID, | |
1173 kClosetLinkID, kVisitingLinkID, kAmelieLinkID, kJoyeuxNoelLinkID, | |
1174 kCampingLinkID, kBriceDeNiceLinkID, kTaxiLinkID, kAsterixLinkID, | |
1175 kCancelButtonID, kHelpButtonID, kStyleContainerID, kBoldCheckBoxID, | |
1176 kItalicCheckBoxID, kUnderlinedCheckBoxID, kStyleHelpLinkID, | |
1177 kStyleTextEditID, kSearchTextfieldID, kSearchButtonID, kHelpLinkID }; | |
1178 | |
1179 | |
1180 // Let's make some views invisible. | |
1181 for (size_t i = 0; i < arraysize(kInvisibleIDs); i++) { | |
1182 View* v = FindViewByID(kInvisibleIDs[i]); | |
1183 ASSERT_TRUE(v != NULL); | |
1184 v->SetVisible(false); | |
1185 } | |
1186 | |
1187 // Uncomment the following line if you want to test manually the UI of this | |
1188 // test. | |
1189 // MessageLoopForUI::current()->RunWithDispatcher(new AcceleratorHandler()); | |
1190 | |
1191 View* focused_view; | |
1192 // Let's do one traversal (several times, to make sure it loops ok). | |
1193 GetFocusManager()->ClearFocus(); | |
1194 for (int i = 0; i < 3; ++i) { | |
1195 for (size_t j = 0; j < arraysize(kTraversalIDs); j++) { | |
1196 GetFocusManager()->AdvanceFocus(false); | |
1197 focused_view = GetFocusManager()->GetFocusedView(); | |
1198 EXPECT_TRUE(focused_view != NULL); | |
1199 if (focused_view) | |
1200 EXPECT_EQ(kTraversalIDs[j], focused_view->id()); | |
1201 } | |
1202 } | |
1203 | |
1204 // Same thing in reverse. | |
1205 GetFocusManager()->ClearFocus(); | |
1206 for (int i = 0; i < 3; ++i) { | |
1207 for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) { | |
1208 GetFocusManager()->AdvanceFocus(true); | |
1209 focused_view = GetFocusManager()->GetFocusedView(); | |
1210 EXPECT_TRUE(focused_view != NULL); | |
1211 if (focused_view) | |
1212 EXPECT_EQ(kTraversalIDs[j], focused_view->id()); | |
1213 } | |
1214 } | |
1215 } | |
1216 | |
1217 TEST_F(FocusTraversalTest, PaneTraversal) { | |
1218 // Tests trapping the traversal within a pane - useful for full | |
1219 // keyboard accessibility for toolbars. | |
1220 | |
1221 // First test the left container. | |
1222 const int kLeftTraversalIDs[] = { | |
1223 kAppleTextfieldID, | |
1224 kOrangeTextfieldID, kBananaTextfieldID, kKiwiTextfieldID, | |
1225 kFruitButtonID, kFruitCheckBoxID, kComboboxID }; | |
1226 | |
1227 FocusSearch focus_search_left(left_container_, true, false); | |
1228 left_container_->EnablePaneFocus(&focus_search_left); | |
1229 FindViewByID(kComboboxID)->RequestFocus(); | |
1230 | |
1231 // Traverse the focus hierarchy within the pane several times. | |
1232 for (int i = 0; i < 3; ++i) { | |
1233 for (size_t j = 0; j < arraysize(kLeftTraversalIDs); j++) { | |
1234 GetFocusManager()->AdvanceFocus(false); | |
1235 View* focused_view = GetFocusManager()->GetFocusedView(); | |
1236 EXPECT_TRUE(focused_view != NULL); | |
1237 if (focused_view) | |
1238 EXPECT_EQ(kLeftTraversalIDs[j], focused_view->id()); | |
1239 } | |
1240 } | |
1241 | |
1242 // Traverse in reverse order. | |
1243 FindViewByID(kAppleTextfieldID)->RequestFocus(); | |
1244 for (int i = 0; i < 3; ++i) { | |
1245 for (int j = arraysize(kLeftTraversalIDs) - 1; j >= 0; --j) { | |
1246 GetFocusManager()->AdvanceFocus(true); | |
1247 View* focused_view = GetFocusManager()->GetFocusedView(); | |
1248 EXPECT_TRUE(focused_view != NULL); | |
1249 if (focused_view) | |
1250 EXPECT_EQ(kLeftTraversalIDs[j], focused_view->id()); | |
1251 } | |
1252 } | |
1253 | |
1254 // Now test the right container, but this time with accessibility mode. | |
1255 // Make some links not focusable, but mark one of them as | |
1256 // "accessibility focusable", so it should show up in the traversal. | |
1257 const int kRightTraversalIDs[] = { | |
1258 kBroccoliButtonID, kDinerGameLinkID, kRidiculeLinkID, | |
1259 kClosetLinkID, kVisitingLinkID, kAmelieLinkID, kJoyeuxNoelLinkID, | |
1260 kCampingLinkID, kBriceDeNiceLinkID, kTaxiLinkID, kAsterixLinkID }; | |
1261 | |
1262 FocusSearch focus_search_right(right_container_, true, true); | |
1263 right_container_->EnablePaneFocus(&focus_search_right); | |
1264 FindViewByID(kRosettaLinkID)->set_focusable(false); | |
1265 FindViewByID(kStupeurEtTremblementLinkID)->set_focusable(false); | |
1266 FindViewByID(kDinerGameLinkID)->set_accessibility_focusable(true); | |
1267 FindViewByID(kDinerGameLinkID)->set_focusable(false); | |
1268 FindViewByID(kAsterixLinkID)->RequestFocus(); | |
1269 | |
1270 // Traverse the focus hierarchy within the pane several times. | |
1271 for (int i = 0; i < 3; ++i) { | |
1272 for (size_t j = 0; j < arraysize(kRightTraversalIDs); j++) { | |
1273 GetFocusManager()->AdvanceFocus(false); | |
1274 View* focused_view = GetFocusManager()->GetFocusedView(); | |
1275 EXPECT_TRUE(focused_view != NULL); | |
1276 if (focused_view) | |
1277 EXPECT_EQ(kRightTraversalIDs[j], focused_view->id()); | |
1278 } | |
1279 } | |
1280 | |
1281 // Traverse in reverse order. | |
1282 FindViewByID(kBroccoliButtonID)->RequestFocus(); | |
1283 for (int i = 0; i < 3; ++i) { | |
1284 for (int j = arraysize(kRightTraversalIDs) - 1; j >= 0; --j) { | |
1285 GetFocusManager()->AdvanceFocus(true); | |
1286 View* focused_view = GetFocusManager()->GetFocusedView(); | |
1287 EXPECT_TRUE(focused_view != NULL); | |
1288 if (focused_view) | |
1289 EXPECT_EQ(kRightTraversalIDs[j], focused_view->id()); | |
1290 } | |
1291 } | |
1292 } | |
1293 | |
1294 // Counts accelerator calls. | 194 // Counts accelerator calls. |
1295 class TestAcceleratorTarget : public ui::AcceleratorTarget { | 195 class TestAcceleratorTarget : public ui::AcceleratorTarget { |
1296 public: | 196 public: |
1297 explicit TestAcceleratorTarget(bool process_accelerator) | 197 explicit TestAcceleratorTarget(bool process_accelerator) |
1298 : accelerator_count_(0), process_accelerator_(process_accelerator) {} | 198 : accelerator_count_(0), process_accelerator_(process_accelerator) {} |
1299 | 199 |
1300 virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) { | 200 virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) { |
1301 ++accelerator_count_; | 201 ++accelerator_count_; |
1302 return process_accelerator_; | 202 return process_accelerator_; |
1303 } | 203 } |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1446 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); | 346 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); |
1447 EXPECT_EQ(target.accelerator_count(), 1); | 347 EXPECT_EQ(target.accelerator_count(), 1); |
1448 EXPECT_EQ(NULL, | 348 EXPECT_EQ(NULL, |
1449 focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); | 349 focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); |
1450 | 350 |
1451 // Hitting the return key again; nothing should happen. | 351 // Hitting the return key again; nothing should happen. |
1452 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); | 352 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); |
1453 EXPECT_EQ(target.accelerator_count(), 1); | 353 EXPECT_EQ(target.accelerator_count(), 1); |
1454 } | 354 } |
1455 | 355 |
1456 class MessageTrackingView : public View { | |
1457 public: | |
1458 MessageTrackingView() : accelerator_pressed_(false) { | |
1459 } | |
1460 | |
1461 virtual bool OnKeyPressed(const KeyEvent& e) { | |
1462 keys_pressed_.push_back(e.key_code()); | |
1463 return true; | |
1464 } | |
1465 | |
1466 virtual bool OnKeyReleased(const KeyEvent& e) { | |
1467 keys_released_.push_back(e.key_code()); | |
1468 return true; | |
1469 } | |
1470 | |
1471 virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) { | |
1472 accelerator_pressed_ = true; | |
1473 return true; | |
1474 } | |
1475 | |
1476 void Reset() { | |
1477 accelerator_pressed_ = false; | |
1478 keys_pressed_.clear(); | |
1479 keys_released_.clear(); | |
1480 } | |
1481 | |
1482 const std::vector<ui::KeyboardCode>& keys_pressed() const { | |
1483 return keys_pressed_; | |
1484 } | |
1485 | |
1486 const std::vector<ui::KeyboardCode>& keys_released() const { | |
1487 return keys_released_; | |
1488 } | |
1489 | |
1490 bool accelerator_pressed() const { | |
1491 return accelerator_pressed_; | |
1492 } | |
1493 | |
1494 private: | |
1495 bool accelerator_pressed_; | |
1496 std::vector<ui::KeyboardCode> keys_pressed_; | |
1497 std::vector<ui::KeyboardCode> keys_released_; | |
1498 | |
1499 DISALLOW_COPY_AND_ASSIGN(MessageTrackingView); | |
1500 }; | |
1501 | |
1502 #if defined(OS_WIN) | |
1503 // This test is now Windows only. Linux Views port does not handle accelerator | |
1504 // keys in AcceleratorHandler anymore. The logic has been moved into | |
1505 // NativeWidgetGtk::OnKeyEvent(). | |
1506 // Tests that the keyup messages are eaten for accelerators. | |
1507 TEST_F(FocusManagerTest, IgnoreKeyupForAccelerators) { | |
1508 FocusManager* focus_manager = GetFocusManager(); | |
1509 MessageTrackingView* mtv = new MessageTrackingView(); | |
1510 mtv->AddAccelerator(ui::Accelerator(ui::VKEY_0, false, false, false)); | |
1511 mtv->AddAccelerator(ui::Accelerator(ui::VKEY_1, false, false, false)); | |
1512 content_view_->AddChildView(mtv); | |
1513 focus_manager->SetFocusedView(mtv); | |
1514 | |
1515 // First send a non-accelerator key sequence. | |
1516 PostKeyDown(ui::VKEY_9); | |
1517 PostKeyUp(ui::VKEY_9); | |
1518 AcceleratorHandler accelerator_handler; | |
1519 MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); | |
1520 MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler); | |
1521 // Make sure we get a key-up and key-down. | |
1522 ASSERT_EQ(1U, mtv->keys_pressed().size()); | |
1523 EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[0]); | |
1524 ASSERT_EQ(1U, mtv->keys_released().size()); | |
1525 EXPECT_EQ(ui::VKEY_9, mtv->keys_released()[0]); | |
1526 EXPECT_FALSE(mtv->accelerator_pressed()); | |
1527 mtv->Reset(); | |
1528 | |
1529 // Same thing with repeat and more than one key at once. | |
1530 PostKeyDown(ui::VKEY_9); | |
1531 PostKeyDown(ui::VKEY_9); | |
1532 PostKeyDown(ui::VKEY_8); | |
1533 PostKeyDown(ui::VKEY_9); | |
1534 PostKeyDown(ui::VKEY_7); | |
1535 PostKeyUp(ui::VKEY_9); | |
1536 PostKeyUp(ui::VKEY_7); | |
1537 PostKeyUp(ui::VKEY_8); | |
1538 MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); | |
1539 MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler); | |
1540 // Make sure we get a key-up and key-down. | |
1541 ASSERT_EQ(5U, mtv->keys_pressed().size()); | |
1542 EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[0]); | |
1543 EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[1]); | |
1544 EXPECT_EQ(ui::VKEY_8, mtv->keys_pressed()[2]); | |
1545 EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[3]); | |
1546 EXPECT_EQ(ui::VKEY_7, mtv->keys_pressed()[4]); | |
1547 ASSERT_EQ(3U, mtv->keys_released().size()); | |
1548 EXPECT_EQ(ui::VKEY_9, mtv->keys_released()[0]); | |
1549 EXPECT_EQ(ui::VKEY_7, mtv->keys_released()[1]); | |
1550 EXPECT_EQ(ui::VKEY_8, mtv->keys_released()[2]); | |
1551 EXPECT_FALSE(mtv->accelerator_pressed()); | |
1552 mtv->Reset(); | |
1553 | |
1554 // Now send an accelerator key sequence. | |
1555 PostKeyDown(ui::VKEY_0); | |
1556 PostKeyUp(ui::VKEY_0); | |
1557 MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); | |
1558 MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler); | |
1559 EXPECT_TRUE(mtv->keys_pressed().empty()); | |
1560 EXPECT_TRUE(mtv->keys_released().empty()); | |
1561 EXPECT_TRUE(mtv->accelerator_pressed()); | |
1562 mtv->Reset(); | |
1563 | |
1564 // Same thing with repeat and more than one key at once. | |
1565 PostKeyDown(ui::VKEY_0); | |
1566 PostKeyDown(ui::VKEY_1); | |
1567 PostKeyDown(ui::VKEY_1); | |
1568 PostKeyDown(ui::VKEY_0); | |
1569 PostKeyDown(ui::VKEY_0); | |
1570 PostKeyUp(ui::VKEY_1); | |
1571 PostKeyUp(ui::VKEY_0); | |
1572 MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); | |
1573 MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler); | |
1574 EXPECT_TRUE(mtv->keys_pressed().empty()); | |
1575 EXPECT_TRUE(mtv->keys_released().empty()); | |
1576 EXPECT_TRUE(mtv->accelerator_pressed()); | |
1577 mtv->Reset(); | |
1578 } | |
1579 #endif | |
1580 | |
1581 #if defined(OS_WIN) && !defined(USE_AURA) | |
1582 // Test that the focus manager is created successfully for the first view | |
1583 // window parented to a native dialog. | |
1584 TEST_F(FocusManagerTest, CreationForNativeRoot) { | |
1585 // Create a window class. | |
1586 WNDCLASSEX class_ex; | |
1587 memset(&class_ex, 0, sizeof(class_ex)); | |
1588 class_ex.cbSize = sizeof(WNDCLASSEX); | |
1589 class_ex.lpfnWndProc = &DefWindowProc; | |
1590 class_ex.lpszClassName = L"TestWindow"; | |
1591 ATOM atom = RegisterClassEx(&class_ex); | |
1592 ASSERT_TRUE(atom); | |
1593 | |
1594 // Create a native dialog window. | |
1595 HWND hwnd = CreateWindowEx(0, class_ex.lpszClassName, NULL, | |
1596 WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, | |
1597 NULL, NULL, NULL, NULL); | |
1598 ASSERT_TRUE(hwnd); | |
1599 | |
1600 // Create a view window parented to native dialog. | |
1601 scoped_ptr<Widget> widget1(new Widget); | |
1602 Widget::InitParams params(Widget::InitParams::TYPE_CONTROL); | |
1603 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
1604 params.parent = hwnd; | |
1605 params.bounds = gfx::Rect(0, 0, 100, 100); | |
1606 params.top_level = true; // This is top level in views hierarchy. | |
1607 widget1->Init(params); | |
1608 | |
1609 // Get the focus manager directly from the first window. Should exist | |
1610 // because the first window is the root widget. | |
1611 views::FocusManager* focus_manager1 = widget1->GetFocusManager(); | |
1612 EXPECT_TRUE(focus_manager1); | |
1613 | |
1614 // Create another view window parented to the first view window. | |
1615 scoped_ptr<Widget> widget2(new Widget); | |
1616 params.parent = widget1->GetNativeView(); | |
1617 params.top_level = false; // This is child widget. | |
1618 widget2->Init(params); | |
1619 | |
1620 // Access the shared focus manager directly from the second window. | |
1621 views::FocusManager* focus_manager2 = widget2->GetFocusManager(); | |
1622 EXPECT_EQ(focus_manager2, focus_manager1); | |
1623 | |
1624 // Access the shared focus manager indirectly from the first window handle. | |
1625 gfx::NativeWindow native_window = widget1->GetNativeWindow(); | |
1626 views::Widget* widget = | |
1627 views::Widget::GetWidgetForNativeWindow(native_window); | |
1628 EXPECT_EQ(widget->GetFocusManager(), focus_manager1); | |
1629 | |
1630 // Access the shared focus manager indirectly from the second window handle. | |
1631 native_window = widget2->GetNativeWindow(); | |
1632 widget = views::Widget::GetWidgetForNativeWindow(native_window); | |
1633 EXPECT_EQ(widget->GetFocusManager(), focus_manager1); | |
1634 | |
1635 // Access the shared focus manager indirectly from the first view handle. | |
1636 gfx::NativeView native_view = widget1->GetNativeView(); | |
1637 widget = views::Widget::GetTopLevelWidgetForNativeView(native_view); | |
1638 EXPECT_EQ(widget->GetFocusManager(), focus_manager1); | |
1639 | |
1640 // Access the shared focus manager indirectly from the second view handle. | |
1641 native_view = widget2->GetNativeView(); | |
1642 widget = views::Widget::GetTopLevelWidgetForNativeView(native_view); | |
1643 EXPECT_EQ(widget->GetFocusManager(), focus_manager1); | |
1644 | |
1645 DestroyWindow(hwnd); | |
1646 } | |
1647 #endif | |
1648 | |
1649 class FocusManagerDtorTest : public FocusManagerTest { | 356 class FocusManagerDtorTest : public FocusManagerTest { |
1650 protected: | 357 protected: |
1651 typedef std::vector<std::string> DtorTrackVector; | 358 typedef std::vector<std::string> DtorTrackVector; |
1652 | 359 |
1653 class FocusManagerDtorTracked : public FocusManager { | 360 class FocusManagerDtorTracked : public FocusManager { |
1654 public: | 361 public: |
1655 FocusManagerDtorTracked(Widget* widget, DtorTrackVector* dtor_tracker) | 362 FocusManagerDtorTracked(Widget* widget, DtorTrackVector* dtor_tracker) |
1656 : FocusManager(widget), | 363 : FocusManager(widget), |
1657 dtor_tracker_(dtor_tracker) { | 364 dtor_tracker_(dtor_tracker) { |
1658 } | 365 } |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1706 dtor_tracker_->push_back("WindowDtorTracked"); | 413 dtor_tracker_->push_back("WindowDtorTracked"); |
1707 } | 414 } |
1708 | 415 |
1709 DtorTrackVector* dtor_tracker_; | 416 DtorTrackVector* dtor_tracker_; |
1710 }; | 417 }; |
1711 | 418 |
1712 virtual void SetUp() { | 419 virtual void SetUp() { |
1713 ViewsTestBase::SetUp(); | 420 ViewsTestBase::SetUp(); |
1714 FocusManagerFactory::Install(new TestFocusManagerFactory(&dtor_tracker_)); | 421 FocusManagerFactory::Install(new TestFocusManagerFactory(&dtor_tracker_)); |
1715 // Create WindowDtorTracked that uses FocusManagerDtorTracked. | 422 // Create WindowDtorTracked that uses FocusManagerDtorTracked. |
1716 window_ = new WindowDtorTracked(&dtor_tracker_); | 423 Widget* widget = new WindowDtorTracked(&dtor_tracker_); |
1717 Widget::InitParams params; | 424 Widget::InitParams params; |
1718 params.delegate = this; | 425 params.delegate = this; |
1719 params.bounds = gfx::Rect(0, 0, 100, 100); | 426 params.bounds = gfx::Rect(0, 0, 100, 100); |
1720 window_->Init(params); | 427 widget->Init(params); |
1721 | 428 |
1722 tracked_focus_manager_ = | 429 tracked_focus_manager_ = |
1723 static_cast<FocusManagerDtorTracked*>(GetFocusManager()); | 430 static_cast<FocusManagerDtorTracked*>(GetFocusManager()); |
1724 window_->Show(); | 431 widget->Show(); |
1725 } | 432 } |
1726 | 433 |
1727 virtual void TearDown() { | 434 virtual void TearDown() { |
1728 if (window_) { | |
1729 window_->Close(); | |
1730 RunPendingMessages(); | |
1731 } | |
1732 FocusManagerFactory::Install(NULL); | 435 FocusManagerFactory::Install(NULL); |
1733 ViewsTestBase::TearDown(); | 436 ViewsTestBase::TearDown(); |
1734 } | 437 } |
1735 | 438 |
1736 FocusManager* tracked_focus_manager_; | 439 FocusManager* tracked_focus_manager_; |
1737 DtorTrackVector dtor_tracker_; | 440 DtorTrackVector dtor_tracker_; |
1738 }; | 441 }; |
1739 | 442 |
| 443 #if !defined(USE_AURA) |
1740 TEST_F(FocusManagerDtorTest, FocusManagerDestructedLast) { | 444 TEST_F(FocusManagerDtorTest, FocusManagerDestructedLast) { |
1741 // Setup views hierarchy. | 445 // Setup views hierarchy. |
1742 TabbedPane* tabbed_pane = new TabbedPane(); | 446 TabbedPane* tabbed_pane = new TabbedPane(); |
1743 content_view_->AddChildView(tabbed_pane); | 447 GetContentsView()->AddChildView(tabbed_pane); |
1744 | 448 |
1745 NativeButtonDtorTracked* button = new NativeButtonDtorTracked( | 449 NativeButtonDtorTracked* button = new NativeButtonDtorTracked( |
1746 ASCIIToUTF16("button"), &dtor_tracker_); | 450 ASCIIToUTF16("button"), &dtor_tracker_); |
1747 tabbed_pane->AddTab(ASCIIToUTF16("Awesome tab"), button); | 451 tabbed_pane->AddTab(ASCIIToUTF16("Awesome tab"), button); |
1748 | 452 |
1749 // Close the window. | 453 // Close the window. |
1750 window_->Close(); | 454 GetWidget()->Close(); |
1751 RunPendingMessages(); | 455 RunPendingMessages(); |
1752 | 456 |
1753 // Test window, button and focus manager should all be destructed. | 457 // Test window, button and focus manager should all be destructed. |
1754 ASSERT_EQ(3, static_cast<int>(dtor_tracker_.size())); | 458 ASSERT_EQ(3, static_cast<int>(dtor_tracker_.size())); |
1755 | 459 |
1756 // Focus manager should be the last one to destruct. | 460 // Focus manager should be the last one to destruct. |
1757 ASSERT_STREQ("FocusManagerDtorTracked", dtor_tracker_[2].c_str()); | 461 ASSERT_STREQ("FocusManagerDtorTracked", dtor_tracker_[2].c_str()); |
1758 | |
1759 // Clear window_ so that we don't try to close it again. | |
1760 window_ = NULL; | |
1761 } | 462 } |
| 463 #endif |
1762 | 464 |
1763 } // namespace views | 465 } // namespace views |
OLD | NEW |