| 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 |