diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-22 21:37:54 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-22 21:37:54 +0000 |
commit | 47dfc956f274408cb60666181d846f057c827ba9 (patch) | |
tree | 18bcbecece29723f310a21b14cc6dc5cc40a024e /ui | |
parent | ace7ca0c74a46611c404e399fc35cee45ba840e4 (diff) | |
download | chromium_src-47dfc956f274408cb60666181d846f057c827ba9.zip chromium_src-47dfc956f274408cb60666181d846f057c827ba9.tar.gz chromium_src-47dfc956f274408cb60666181d846f057c827ba9.tar.bz2 |
Enable FocusManager tests for Aura.
- Now building the file!
- Disable some tests that only work on Windows.
- Remove some dead Gtk code.
http://crbug.com/102572
TEST=unittests
Review URL: http://codereview.chromium.org/8642002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111220 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/views/focus/focus_manager.cc | 4 | ||||
-rw-r--r-- | ui/views/focus/focus_manager.h | 3 | ||||
-rw-r--r-- | ui/views/focus/focus_manager_test.cc | 114 | ||||
-rw-r--r-- | ui/views/focus/focus_manager_test.h | 83 | ||||
-rw-r--r-- | ui/views/focus/focus_manager_unittest.cc | 1360 | ||||
-rw-r--r-- | ui/views/focus/focus_manager_unittest_win.cc | 285 | ||||
-rw-r--r-- | ui/views/focus/focus_traversal_unittest.cc | 812 | ||||
-rw-r--r-- | ui/views/widget/native_widget_aura.cc | 3 |
8 files changed, 1326 insertions, 1338 deletions
diff --git a/ui/views/focus/focus_manager.cc b/ui/views/focus/focus_manager.cc index 1c98a12..0a44877 100644 --- a/ui/views/focus/focus_manager.cc +++ b/ui/views/focus/focus_manager.cc @@ -384,10 +384,6 @@ ui::AcceleratorTarget* FocusManager::GetCurrentTargetForAccelerator( return accelerator_manager_->GetCurrentTarget(accelerator); } -void FocusManager::FocusNativeView(gfx::NativeView native_view) { - widget_->FocusNativeView(native_view); -} - // static bool FocusManager::IsTabTraversalKeyEvent(const KeyEvent& key_event) { return key_event.key_code() == ui::VKEY_TAB && !key_event.IsControlDown(); diff --git a/ui/views/focus/focus_manager.h b/ui/views/focus/focus_manager.h index 01899e1..b428399 100644 --- a/ui/views/focus/focus_manager.h +++ b/ui/views/focus/focus_manager.h @@ -230,9 +230,6 @@ class VIEWS_EXPORT FocusManager { ui::AcceleratorTarget* GetCurrentTargetForAccelerator( const ui::Accelerator& accelertor) const; - // Sets the focus to the specified native view. - virtual void FocusNativeView(gfx::NativeView native_view); - // Clears the native view having the focus. virtual void ClearNativeFocus(); diff --git a/ui/views/focus/focus_manager_test.cc b/ui/views/focus/focus_manager_test.cc new file mode 100644 index 0000000..da15b27 --- /dev/null +++ b/ui/views/focus/focus_manager_test.cc @@ -0,0 +1,114 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/views/focus/focus_manager_test.h" + +#include "ui/views/focus/focus_manager.h" +#include "ui/views/widget/widget.h" + +namespace views { + +//////////////////////////////////////////////////////////////////////////////// +// FocusManagerTest, public: + +FocusManagerTest::FocusManagerTest() + : contents_view_(new View), + focus_change_listener_(NULL) { +} + +FocusManagerTest::~FocusManagerTest() { +} + +FocusManager* FocusManagerTest::GetFocusManager() { + return GetWidget()->GetFocusManager(); +} + +//////////////////////////////////////////////////////////////////////////////// +// FocusManagerTest, ViewTestBase overrides: + +void FocusManagerTest::SetUp() { + ViewsTestBase::SetUp(); + Widget* widget = + Widget::CreateWindowWithBounds(this, gfx::Rect(0, 0, 1024, 768)); + InitContentView(); + widget->Show(); +} + +void FocusManagerTest::TearDown() { + if (focus_change_listener_) + GetFocusManager()->RemoveFocusChangeListener(focus_change_listener_); + GetWidget()->Close(); + + // Flush the message loop to make application verifiers happy. + RunPendingMessages(); + ViewsTestBase::TearDown(); +} + +//////////////////////////////////////////////////////////////////////////////// +// FocusManagerTest, WidgetDelegate implementation: + +View* FocusManagerTest::GetContentsView() { + return contents_view_; +} + +Widget* FocusManagerTest::GetWidget() { + return contents_view_->GetWidget(); +} + +const Widget* FocusManagerTest::GetWidget() const { + return contents_view_->GetWidget(); +} + +//////////////////////////////////////////////////////////////////////////////// +// FocusManagerTest, protected: + +void FocusManagerTest::InitContentView() { +} + +void FocusManagerTest::AddFocusChangeListener(FocusChangeListener* listener) { + ASSERT_FALSE(focus_change_listener_); + focus_change_listener_ = listener; + GetFocusManager()->AddFocusChangeListener(listener); +} + +#if defined(OS_WIN) && !defined(USE_AURA) +void FocusManagerTest::SimulateActivateWindow() { + SendMessage(GetWidget()->GetNativeWindow(), WM_ACTIVATE, WA_ACTIVE, NULL); +} + +void FocusManagerTest::SimulateDeactivateWindow() { + SendMessage(GetWidget()->GetNativeWindow(), WM_ACTIVATE, WA_INACTIVE, NULL); +} + +void FocusManagerTest::PostKeyDown(ui::KeyboardCode key_code) { + PostMessage(GetWidget()->GetNativeView(), WM_KEYDOWN, key_code, 0); +} + +void FocusManagerTest::PostKeyUp(ui::KeyboardCode key_code) { + PostMessage(GetWidget()->GetNativeView(), WM_KEYUP, key_code, 0); +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +// TestFocusChangeListener + +TestFocusChangeListener::TestFocusChangeListener() { +} + +TestFocusChangeListener::~TestFocusChangeListener() { +} + +void TestFocusChangeListener::OnWillChangeFocus(View* focused_before, + View* focused_now) { + focus_changes_.push_back(ViewPair(focused_before, focused_now)); +} +void TestFocusChangeListener::OnDidChangeFocus(View* focused_before, + View* focused_now) { +} + +void TestFocusChangeListener::ClearFocusChanges() { + focus_changes_.clear(); +} + +} // namespace views diff --git a/ui/views/focus/focus_manager_test.h b/ui/views/focus/focus_manager_test.h new file mode 100644 index 0000000..188ad23 --- /dev/null +++ b/ui/views/focus/focus_manager_test.h @@ -0,0 +1,83 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_VIEWS_FOCUS_FOCUS_MANAGER_TEST_H_ +#define UI_VIEWS_FOCUS_FOCUS_MANAGER_TEST_H_ + +#include "ui/views/focus/focus_manager.h" +#include "ui/views/test/views_test_base.h" +#include "ui/views/widget/widget_delegate.h" + +namespace views { + +class FocusChangeListener; + +class FocusManagerTest : public ViewsTestBase, + public WidgetDelegate { + public: + FocusManagerTest(); + virtual ~FocusManagerTest(); + + // Convenience to obtain the focus manager for the test's hosting widget. + FocusManager* GetFocusManager(); + + // Overridden from ViewsTestBase: + virtual void SetUp() OVERRIDE; + virtual void TearDown() OVERRIDE; + + // Overridden from WidgetDelegate: + virtual View* GetContentsView() OVERRIDE; + virtual Widget* GetWidget() OVERRIDE; + virtual const Widget* GetWidget() const OVERRIDE; + + protected: + // Called after the Widget is initialized and the content view is added. + // Override to add controls to the layout. + virtual void InitContentView(); + + void AddFocusChangeListener(FocusChangeListener* listener); + +#if defined(OS_WIN) && !defined(USE_AURA) + // Mocks activating/deactivating the window. + void SimulateActivateWindow(); + void SimulateDeactivateWindow(); + + void PostKeyDown(ui::KeyboardCode key_code); + void PostKeyUp(ui::KeyboardCode key_code); +#endif + + private: + View* contents_view_; + FocusChangeListener* focus_change_listener_; + + DISALLOW_COPY_AND_ASSIGN(FocusManagerTest); +}; + +typedef std::pair<View*, View*> ViewPair; + +// Use to record focus change notifications. +class TestFocusChangeListener : public FocusChangeListener { + public: + TestFocusChangeListener(); + virtual ~TestFocusChangeListener(); + + const std::vector<ViewPair>& focus_changes() const { return focus_changes_; } + void ClearFocusChanges(); + + // Overridden from FocusChangeListener: + virtual void OnWillChangeFocus(View* focused_before, + View* focused_now) OVERRIDE; + virtual void OnDidChangeFocus(View* focused_before, + View* focused_now) OVERRIDE; + + private: + // A vector of which views lost/gained focus. + std::vector<ViewPair> focus_changes_; + + DISALLOW_COPY_AND_ASSIGN(TestFocusChangeListener); +}; + +} // namespace views + +#endif // UI_VIEWS_FOCUS_FOCUS_MANAGER_TEST_H_ diff --git a/ui/views/focus/focus_manager_unittest.cc b/ui/views/focus/focus_manager_unittest.cc index 46c629a..21a6d8f 100644 --- a/ui/views/focus/focus_manager_unittest.cc +++ b/ui/views/focus/focus_manager_unittest.cc @@ -2,755 +2,27 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/logging.h" -#include "base/string16.h" -#include "base/string_number_conversions.h" #include "base/utf_string_conversions.h" -#include "third_party/skia/include/core/SkColor.h" #include "ui/base/keycodes/keyboard_codes.h" #include "ui/base/models/accelerator.h" -#include "ui/base/models/combobox_model.h" -#include "ui/gfx/rect.h" #include "ui/views/focus/accelerator_handler.h" #include "ui/views/focus/focus_manager_factory.h" -#include "ui/views/test/views_test_base.h" -#include "ui/views/widget/root_view.h" +#include "ui/views/focus/focus_manager_test.h" #include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" -#include "ui/views/window/non_client_view.h" -#include "views/background.h" -#include "views/border.h" -#include "views/controls/button/checkbox.h" -#include "views/controls/button/radio_button.h" -#include "views/controls/combobox/combobox.h" -#include "views/controls/combobox/native_combobox_wrapper.h" -#include "views/controls/label.h" -#include "views/controls/link.h" -#include "views/controls/native/native_view_host.h" -#include "views/controls/scroll_view.h" -#include "views/controls/tabbed_pane/native_tabbed_pane_wrapper.h" -#include "views/controls/tabbed_pane/tabbed_pane.h" +#include "views/controls/button/text_button.h" #include "views/controls/textfield/textfield.h" +#if !defined(USE_AURA) +#include "views/controls/tabbed_pane/tabbed_pane.h" +#include "views/controls/tabbed_pane/native_tabbed_pane_wrapper.h" +#endif + #if defined(OS_LINUX) #include "ui/base/keycodes/keyboard_code_conversion_gtk.h" #endif -namespace { -const int kWindowWidth = 600; -const int kWindowHeight = 500; - -int count = 1; - -const int kTopCheckBoxID = count++; // 1 -const int kLeftContainerID = count++; -const int kAppleLabelID = count++; -const int kAppleTextfieldID = count++; -const int kOrangeLabelID = count++; // 5 -const int kOrangeTextfieldID = count++; -const int kBananaLabelID = count++; -const int kBananaTextfieldID = count++; -const int kKiwiLabelID = count++; -const int kKiwiTextfieldID = count++; // 10 -const int kFruitButtonID = count++; -const int kFruitCheckBoxID = count++; -const int kComboboxID = count++; - -const int kRightContainerID = count++; -const int kAsparagusButtonID = count++; // 15 -const int kBroccoliButtonID = count++; -const int kCauliflowerButtonID = count++; - -const int kInnerContainerID = count++; -const int kScrollViewID = count++; -const int kRosettaLinkID = count++; // 20 -const int kStupeurEtTremblementLinkID = count++; -const int kDinerGameLinkID = count++; -const int kRidiculeLinkID = count++; -const int kClosetLinkID = count++; -const int kVisitingLinkID = count++; // 25 -const int kAmelieLinkID = count++; -const int kJoyeuxNoelLinkID = count++; -const int kCampingLinkID = count++; -const int kBriceDeNiceLinkID = count++; -const int kTaxiLinkID = count++; // 30 -const int kAsterixLinkID = count++; - -const int kOKButtonID = count++; -const int kCancelButtonID = count++; -const int kHelpButtonID = count++; - -const int kStyleContainerID = count++; // 35 -const int kBoldCheckBoxID = count++; -const int kItalicCheckBoxID = count++; -const int kUnderlinedCheckBoxID = count++; -const int kStyleHelpLinkID = count++; -const int kStyleTextEditID = count++; // 40 - -const int kSearchContainerID = count++; -const int kSearchTextfieldID = count++; -const int kSearchButtonID = count++; -const int kHelpLinkID = count++; - -const int kThumbnailContainerID = count++; // 45 -const int kThumbnailStarID = count++; -const int kThumbnailSuperStarID = count++; - -} // namespace - namespace views { -class FocusManagerTest : public ViewsTestBase, public WidgetDelegate { - public: - FocusManagerTest() - : window_(NULL), - content_view_(NULL), - focus_change_listener_(NULL) { - } - - ~FocusManagerTest() { - } - - virtual void SetUp() OVERRIDE { - ViewsTestBase::SetUp(); - window_ = Widget::CreateWindowWithBounds(this, bounds()); - InitContentView(); - window_->Show(); - } - - virtual void TearDown() OVERRIDE { - if (focus_change_listener_) - GetFocusManager()->RemoveFocusChangeListener(focus_change_listener_); - window_->Close(); - - // Flush the message loop to make application verifiers happy. - RunPendingMessages(); - ViewsTestBase::TearDown(); - } - - FocusManager* GetFocusManager() { - return window_->GetFocusManager(); - } - - void FocusNativeView(gfx::NativeView native_view) { -#if defined(USE_AURA) - NOTIMPLEMENTED(); -#elif defined(OS_WIN) - ::SendMessage(native_view, WM_SETFOCUS, NULL, NULL); -#else - gint return_val; - GdkEventFocus event; - event.type = GDK_FOCUS_CHANGE; - event.window = - gtk_widget_get_root_window(GTK_WIDGET(window_->GetNativeWindow())); - event.send_event = TRUE; - event.in = TRUE; - gtk_signal_emit_by_name(GTK_OBJECT(native_view), "focus-in-event", - &event, &return_val); -#endif - } - - // WidgetDelegate Implementation. - virtual View* GetContentsView() OVERRIDE { - if (!content_view_) - content_view_ = new View(); - return content_view_; - } - virtual Widget* GetWidget() OVERRIDE { - return content_view_->GetWidget(); - } - virtual const Widget* GetWidget() const OVERRIDE { - return content_view_->GetWidget(); - } - - virtual void InitContentView() { - } - - protected: - virtual gfx::Rect bounds() { - return gfx::Rect(0, 0, 500, 500); - } - - // Mocks activating/deactivating the window. - void SimulateActivateWindow() { -#if defined(USE_AURA) - NOTIMPLEMENTED(); -#elif defined(OS_WIN) - ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_ACTIVE, NULL); -#else - gboolean result; - g_signal_emit_by_name(G_OBJECT(window_->GetNativeWindow()), - "focus_in_event", 0, &result); -#endif - } - void SimulateDeactivateWindow() { -#if defined(USE_AURA) - NOTIMPLEMENTED(); -#elif defined(OS_WIN) - ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_INACTIVE, NULL); -#else - gboolean result; - g_signal_emit_by_name(G_OBJECT(window_->GetNativeWindow()), - "focus_out_event", 0, & result); -#endif - } - - Widget* window_; - View* content_view_; - - void AddFocusChangeListener(FocusChangeListener* listener) { - ASSERT_FALSE(focus_change_listener_); - focus_change_listener_ = listener; - GetFocusManager()->AddFocusChangeListener(listener); - } - -#if defined(USE_AURA) - void PostKeyDown(ui::KeyboardCode key_code) { - NOTIMPLEMENTED(); - } - - void PostKeyUp(ui::KeyboardCode key_code) { - NOTIMPLEMENTED(); - } -#elif defined(OS_WIN) - void PostKeyDown(ui::KeyboardCode key_code) { - ::PostMessage(window_->GetNativeWindow(), WM_KEYDOWN, key_code, 0); - } - - void PostKeyUp(ui::KeyboardCode key_code) { - ::PostMessage(window_->GetNativeWindow(), WM_KEYUP, key_code, 0); - } -#elif defined(OS_LINUX) - void PostKeyDown(ui::KeyboardCode key_code) { - PostKeyEvent(key_code, true); - } - - void PostKeyUp(ui::KeyboardCode key_code) { - PostKeyEvent(key_code, false); - } - - void PostKeyEvent(ui::KeyboardCode key_code, bool pressed) { - int keyval = GdkKeyCodeForWindowsKeyCode(key_code, false); - GdkKeymapKey* keys; - gint n_keys; - gdk_keymap_get_entries_for_keyval( - gdk_keymap_get_default(), - keyval, - &keys, - &n_keys); - GdkEvent* event = gdk_event_new(pressed ? GDK_KEY_PRESS : GDK_KEY_RELEASE); - GdkEventKey* key_event = reinterpret_cast<GdkEventKey*>(event); - int modifier = 0; - if (pressed) - key_event->state = modifier | GDK_KEY_PRESS_MASK; - else - key_event->state = modifier | GDK_KEY_RELEASE_MASK; - - key_event->window = GTK_WIDGET(window_->GetNativeWindow())->window; - DCHECK(key_event->window != NULL); - g_object_ref(key_event->window); - key_event->send_event = true; - key_event->time = GDK_CURRENT_TIME; - key_event->keyval = keyval; - key_event->hardware_keycode = keys[0].keycode; - key_event->group = keys[0].group; - - g_free(keys); - - gdk_event_put(event); - gdk_event_free(event); - } -#endif - - private: - FocusChangeListener* focus_change_listener_; - - DISALLOW_COPY_AND_ASSIGN(FocusManagerTest); -}; - -// BorderView is a view containing a native window with its own view hierarchy. -// It is interesting to test focus traversal from a view hierarchy to an inner -// view hierarchy. -class BorderView : public NativeViewHost { - public: - explicit BorderView(View* child) : child_(child), widget_(NULL) { - DCHECK(child); - set_focusable(false); - } - - virtual ~BorderView() {} - - virtual internal::RootView* GetContentsRootView() { - return static_cast<internal::RootView*>(widget_->GetRootView()); - } - - virtual FocusTraversable* GetFocusTraversable() { - return static_cast<internal::RootView*>(widget_->GetRootView()); - } - - virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child) { - NativeViewHost::ViewHierarchyChanged(is_add, parent, child); - - if (child == this && is_add) { - if (!widget_) { - widget_ = new Widget; - Widget::InitParams params(Widget::InitParams::TYPE_CONTROL); -#if defined(OS_WIN) - params.parent = parent->GetWidget()->GetNativeView(); -#elif defined(TOOLKIT_USES_GTK) - params.parent = native_view(); -#else - NOTREACHED(); -#endif - widget_->Init(params); - widget_->SetFocusTraversableParentView(this); - widget_->SetContentsView(child_); - } - - // We have been added to a view hierarchy, attach the native view. - Attach(widget_->GetNativeView()); - // Also update the FocusTraversable parent so the focus traversal works. - static_cast<internal::RootView*>(widget_->GetRootView())-> - SetFocusTraversableParent(GetWidget()->GetFocusTraversable()); - } - } - - private: - View* child_; - Widget* widget_; - - DISALLOW_COPY_AND_ASSIGN(BorderView); -}; - -class DummyComboboxModel : public ui::ComboboxModel { - public: - virtual int GetItemCount() { return 10; } - - virtual string16 GetItemAt(int index) { - return ASCIIToUTF16("Item ") + base::IntToString16(index); - } -}; - -// A View that can act as a pane. -class PaneView : public View, public FocusTraversable { - public: - PaneView() : focus_search_(NULL) {} - - // If this method is called, this view will use GetPaneFocusTraversable to - // have this provided FocusSearch used instead of the default one, allowing - // you to trap focus within the pane. - void EnablePaneFocus(FocusSearch* focus_search) { - focus_search_ = focus_search; - } - - // Overridden from views::View: - virtual FocusTraversable* GetPaneFocusTraversable() { - if (focus_search_) - return this; - else - return NULL; - } - - // Overridden from views::FocusTraversable: - virtual views::FocusSearch* GetFocusSearch() { - return focus_search_; - } - virtual FocusTraversable* GetFocusTraversableParent() { - return NULL; - } - virtual View* GetFocusTraversableParentView() { - return NULL; - } - - private: - FocusSearch* focus_search_; -}; - -class FocusTraversalTest : public FocusManagerTest { - public: - ~FocusTraversalTest(); - - virtual void InitContentView(); - - protected: - FocusTraversalTest(); - - virtual gfx::Rect bounds() { - return gfx::Rect(0, 0, 600, 460); - } - - View* FindViewByID(int id) { - View* view = GetContentsView()->GetViewByID(id); - if (view) - return view; - if (style_tab_) - view = style_tab_->GetSelectedTab()->GetViewByID(id); - if (view) - return view; - view = search_border_view_->GetContentsRootView()->GetViewByID(id); - if (view) - return view; - return NULL; - } - - protected: - TabbedPane* style_tab_; - BorderView* search_border_view_; - DummyComboboxModel combobox_model_; - PaneView* left_container_; - PaneView* right_container_; - - DISALLOW_COPY_AND_ASSIGN(FocusTraversalTest); -}; - -//////////////////////////////////////////////////////////////////////////////// -// FocusTraversalTest -//////////////////////////////////////////////////////////////////////////////// - -FocusTraversalTest::FocusTraversalTest() - : style_tab_(NULL), - search_border_view_(NULL) { -} - -FocusTraversalTest::~FocusTraversalTest() { -} - -void FocusTraversalTest::InitContentView() { - // Create a complicated view hierarchy with lots of control types for - // use by all of the focus traversal tests. - // - // Class name, ID, and asterisk next to focusable views: - // - // View - // Checkbox * kTopCheckBoxID - // PaneView kLeftContainerID - // Label kAppleLabelID - // Textfield * kAppleTextfieldID - // Label kOrangeLabelID - // Textfield * kOrangeTextfieldID - // Label kBananaLabelID - // Textfield * kBananaTextfieldID - // Label kKiwiLabelID - // Textfield * kKiwiTextfieldID - // NativeButton * kFruitButtonID - // Checkbox * kFruitCheckBoxID - // Combobox * kComboboxID - // PaneView kRightContainerID - // RadioButton * kAsparagusButtonID - // RadioButton * kBroccoliButtonID - // RadioButton * kCauliflowerButtonID - // View kInnerContainerID - // ScrollView kScrollViewID - // View - // Link * kRosettaLinkID - // Link * kStupeurEtTremblementLinkID - // Link * kDinerGameLinkID - // Link * kRidiculeLinkID - // Link * kClosetLinkID - // Link * kVisitingLinkID - // Link * kAmelieLinkID - // Link * kJoyeuxNoelLinkID - // Link * kCampingLinkID - // Link * kBriceDeNiceLinkID - // Link * kTaxiLinkID - // Link * kAsterixLinkID - // NativeButton * kOKButtonID - // NativeButton * kCancelButtonID - // NativeButton * kHelpButtonID - // TabbedPane * kStyleContainerID - // View - // Checkbox * kBoldCheckBoxID - // Checkbox * kItalicCheckBoxID - // Checkbox * kUnderlinedCheckBoxID - // Link * kStyleHelpLinkID - // Textfield * kStyleTextEditID - // Other - // BorderView kSearchContainerID - // View - // Textfield * kSearchTextfieldID - // NativeButton * kSearchButtonID - // Link * kHelpLinkID - // View * kThumbnailContainerID - // NativeButton * kThumbnailStarID - // NativeButton * kThumbnailSuperStarID - - content_view_->set_background( - Background::CreateSolidBackground(SK_ColorWHITE)); - - Checkbox* cb = new Checkbox(ASCIIToUTF16("This is a checkbox")); - content_view_->AddChildView(cb); - // In this fast paced world, who really has time for non hard-coded layout? - cb->SetBounds(10, 10, 200, 20); - cb->set_id(kTopCheckBoxID); - - left_container_ = new PaneView(); - left_container_->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK)); - left_container_->set_background( - Background::CreateSolidBackground(240, 240, 240)); - left_container_->set_id(kLeftContainerID); - content_view_->AddChildView(left_container_); - left_container_->SetBounds(10, 35, 250, 200); - - int label_x = 5; - int label_width = 50; - int label_height = 15; - int text_field_width = 150; - int y = 10; - int gap_between_labels = 10; - - Label* label = new Label(ASCIIToUTF16("Apple:")); - label->set_id(kAppleLabelID); - left_container_->AddChildView(label); - label->SetBounds(label_x, y, label_width, label_height); - - Textfield* text_field = new Textfield(); - text_field->set_id(kAppleTextfieldID); - left_container_->AddChildView(text_field); - text_field->SetBounds(label_x + label_width + 5, y, - text_field_width, label_height); - - y += label_height + gap_between_labels; - - label = new Label(ASCIIToUTF16("Orange:")); - label->set_id(kOrangeLabelID); - left_container_->AddChildView(label); - label->SetBounds(label_x, y, label_width, label_height); - - text_field = new Textfield(); - text_field->set_id(kOrangeTextfieldID); - left_container_->AddChildView(text_field); - text_field->SetBounds(label_x + label_width + 5, y, - text_field_width, label_height); - - y += label_height + gap_between_labels; - - label = new Label(ASCIIToUTF16("Banana:")); - label->set_id(kBananaLabelID); - left_container_->AddChildView(label); - label->SetBounds(label_x, y, label_width, label_height); - - text_field = new Textfield(); - text_field->set_id(kBananaTextfieldID); - left_container_->AddChildView(text_field); - text_field->SetBounds(label_x + label_width + 5, y, - text_field_width, label_height); - - y += label_height + gap_between_labels; - - label = new Label(ASCIIToUTF16("Kiwi:")); - label->set_id(kKiwiLabelID); - left_container_->AddChildView(label); - label->SetBounds(label_x, y, label_width, label_height); - - text_field = new Textfield(); - text_field->set_id(kKiwiTextfieldID); - left_container_->AddChildView(text_field); - text_field->SetBounds(label_x + label_width + 5, y, - text_field_width, label_height); - - y += label_height + gap_between_labels; - - NativeTextButton* button = new NativeTextButton(NULL, - ASCIIToUTF16("Click me")); - button->SetBounds(label_x, y + 10, 80, 30); - button->set_id(kFruitButtonID); - left_container_->AddChildView(button); - y += 40; - - cb = new Checkbox(ASCIIToUTF16("This is another check box")); - cb->SetBounds(label_x + label_width + 5, y, 180, 20); - cb->set_id(kFruitCheckBoxID); - left_container_->AddChildView(cb); - y += 20; - - Combobox* combobox = new Combobox(&combobox_model_); - combobox->SetBounds(label_x + label_width + 5, y, 150, 30); - combobox->set_id(kComboboxID); - left_container_->AddChildView(combobox); - - right_container_ = new PaneView(); - right_container_->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK)); - right_container_->set_background( - Background::CreateSolidBackground(240, 240, 240)); - right_container_->set_id(kRightContainerID); - content_view_->AddChildView(right_container_); - right_container_->SetBounds(270, 35, 300, 200); - - y = 10; - int radio_button_height = 18; - int gap_between_radio_buttons = 10; - RadioButton* radio_button = new RadioButton(ASCIIToUTF16("Asparagus"), 1); - radio_button->set_id(kAsparagusButtonID); - right_container_->AddChildView(radio_button); - radio_button->SetBounds(5, y, 70, radio_button_height); - radio_button->SetGroup(1); - y += radio_button_height + gap_between_radio_buttons; - radio_button = new RadioButton(ASCIIToUTF16("Broccoli"), 1); - radio_button->set_id(kBroccoliButtonID); - right_container_->AddChildView(radio_button); - radio_button->SetBounds(5, y, 70, radio_button_height); - radio_button->SetGroup(1); - RadioButton* radio_button_to_check = radio_button; - y += radio_button_height + gap_between_radio_buttons; - radio_button = new RadioButton(ASCIIToUTF16("Cauliflower"), 1); - radio_button->set_id(kCauliflowerButtonID); - right_container_->AddChildView(radio_button); - radio_button->SetBounds(5, y, 70, radio_button_height); - radio_button->SetGroup(1); - y += radio_button_height + gap_between_radio_buttons; - - View* inner_container = new View(); - inner_container->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK)); - inner_container->set_background( - Background::CreateSolidBackground(230, 230, 230)); - inner_container->set_id(kInnerContainerID); - right_container_->AddChildView(inner_container); - inner_container->SetBounds(100, 10, 150, 180); - - ScrollView* scroll_view = new ScrollView(); - scroll_view->set_id(kScrollViewID); - inner_container->AddChildView(scroll_view); - scroll_view->SetBounds(1, 1, 148, 178); - - View* scroll_content = new View(); - scroll_content->SetBounds(0, 0, 200, 200); - scroll_content->set_background( - Background::CreateSolidBackground(200, 200, 200)); - scroll_view->SetContents(scroll_content); - - static const char* const kTitles[] = { - "Rosetta", "Stupeur et tremblement", "The diner game", - "Ridicule", "Le placard", "Les Visiteurs", "Amelie", - "Joyeux Noel", "Camping", "Brice de Nice", - "Taxi", "Asterix" - }; - - static const int kIDs[] = { - kRosettaLinkID, kStupeurEtTremblementLinkID, kDinerGameLinkID, - kRidiculeLinkID, kClosetLinkID, kVisitingLinkID, kAmelieLinkID, - kJoyeuxNoelLinkID, kCampingLinkID, kBriceDeNiceLinkID, - kTaxiLinkID, kAsterixLinkID - }; - - DCHECK(arraysize(kTitles) == arraysize(kIDs)); - - y = 5; - for (size_t i = 0; i < arraysize(kTitles); ++i) { - Link* link = new Link(ASCIIToUTF16(kTitles[i])); - link->SetHorizontalAlignment(Label::ALIGN_LEFT); - link->set_id(kIDs[i]); - scroll_content->AddChildView(link); - link->SetBounds(5, y, 300, 15); - y += 15; - } - - y = 250; - int width = 60; - button = new NativeTextButton(NULL, ASCIIToUTF16("OK")); - button->set_id(kOKButtonID); - button->SetIsDefault(true); - - content_view_->AddChildView(button); - button->SetBounds(150, y, width, 30); - - button = new NativeTextButton(NULL, ASCIIToUTF16("Cancel")); - button->set_id(kCancelButtonID); - content_view_->AddChildView(button); - button->SetBounds(220, y, width, 30); - - button = new NativeTextButton(NULL, ASCIIToUTF16("Help")); - button->set_id(kHelpButtonID); - content_view_->AddChildView(button); - button->SetBounds(290, y, width, 30); - - y += 40; - - // Left bottom box with style checkboxes. - View* contents = new View(); - contents->set_background(Background::CreateSolidBackground(SK_ColorWHITE)); - cb = new Checkbox(ASCIIToUTF16("Bold")); - contents->AddChildView(cb); - cb->SetBounds(10, 10, 50, 20); - cb->set_id(kBoldCheckBoxID); - - cb = new Checkbox(ASCIIToUTF16("Italic")); - contents->AddChildView(cb); - cb->SetBounds(70, 10, 50, 20); - cb->set_id(kItalicCheckBoxID); - - cb = new Checkbox(ASCIIToUTF16("Underlined")); - contents->AddChildView(cb); - cb->SetBounds(130, 10, 70, 20); - cb->set_id(kUnderlinedCheckBoxID); - - Link* link = new Link(ASCIIToUTF16("Help")); - contents->AddChildView(link); - link->SetBounds(10, 35, 70, 10); - link->set_id(kStyleHelpLinkID); - - text_field = new Textfield(); - contents->AddChildView(text_field); - text_field->SetBounds(10, 50, 100, 20); - text_field->set_id(kStyleTextEditID); - - style_tab_ = new TabbedPane(); - style_tab_->set_id(kStyleContainerID); - content_view_->AddChildView(style_tab_); - style_tab_->SetBounds(10, y, 210, 100); - style_tab_->AddTab(ASCIIToUTF16("Style"), contents); - style_tab_->AddTab(ASCIIToUTF16("Other"), new View()); - - // Right bottom box with search. - contents = new View(); - contents->set_background(Background::CreateSolidBackground(SK_ColorWHITE)); - text_field = new Textfield(); - contents->AddChildView(text_field); - text_field->SetBounds(10, 10, 100, 20); - text_field->set_id(kSearchTextfieldID); - - button = new NativeTextButton(NULL, ASCIIToUTF16("Search")); - contents->AddChildView(button); - button->SetBounds(112, 5, 60, 30); - button->set_id(kSearchButtonID); - - link = new Link(ASCIIToUTF16("Help")); - link->SetHorizontalAlignment(Label::ALIGN_LEFT); - link->set_id(kHelpLinkID); - contents->AddChildView(link); - link->SetBounds(175, 10, 30, 20); - - search_border_view_ = new BorderView(contents); - search_border_view_->set_id(kSearchContainerID); - - content_view_->AddChildView(search_border_view_); - search_border_view_->SetBounds(300, y, 240, 50); - - y += 60; - - contents = new View(); - contents->set_focusable(true); - contents->set_background(Background::CreateSolidBackground(SK_ColorBLUE)); - contents->set_id(kThumbnailContainerID); - button = new NativeTextButton(NULL, ASCIIToUTF16("Star")); - contents->AddChildView(button); - button->SetBounds(5, 5, 50, 30); - button->set_id(kThumbnailStarID); - button = new NativeTextButton(NULL, ASCIIToUTF16("SuperStar")); - contents->AddChildView(button); - button->SetBounds(60, 5, 100, 30); - button->set_id(kThumbnailSuperStarID); - - content_view_->AddChildView(contents); - contents->SetBounds(250, y, 200, 50); - // We can only call RadioButton::SetChecked() on the radio-button is part of - // the view hierarchy. - radio_button_to_check->SetChecked(true); -} - -//////////////////////////////////////////////////////////////////////////////// -// The tests -//////////////////////////////////////////////////////////////////////////////// - enum FocusTestEventType { ON_FOCUS = 0, ON_BLUR @@ -795,8 +67,8 @@ TEST_F(FocusManagerTest, ViewFocusCallbacks) { SimpleTestView* view1 = new SimpleTestView(&event_list, kView1ID); SimpleTestView* view2 = new SimpleTestView(&event_list, kView2ID); - content_view_->AddChildView(view1); - content_view_->AddChildView(view2); + GetContentsView()->AddChildView(view1); + GetContentsView()->AddChildView(view2); view1->RequestFocus(); ASSERT_EQ(1, static_cast<int>(event_list.size())); @@ -818,30 +90,13 @@ TEST_F(FocusManagerTest, ViewFocusCallbacks) { EXPECT_EQ(kView2ID, event_list[0].view_id); } -typedef std::pair<View*, View*> ViewPair; -class TestFocusChangeListener : public FocusChangeListener { - public: - virtual void OnWillChangeFocus(View* focused_before, View* focused_now) { - focus_changes_.push_back(ViewPair(focused_before, focused_now)); - } - virtual void OnDidChangeFocus(View* focused_before, View* focused_now) { - } - - const std::vector<ViewPair>& focus_changes() const { return focus_changes_; } - void ClearFocusChanges() { focus_changes_.clear(); } - - private: - // A vector of which views lost/gained focus. - std::vector<ViewPair> focus_changes_; -}; - TEST_F(FocusManagerTest, FocusChangeListener) { View* view1 = new View(); view1->set_focusable(true); View* view2 = new View(); view2->set_focusable(true); - content_view_->AddChildView(view1); - content_view_->AddChildView(view2); + GetContentsView()->AddChildView(view1); + GetContentsView()->AddChildView(view2); TestFocusChangeListener listener; AddFocusChangeListener(&listener); @@ -870,179 +125,49 @@ TEST_F(FocusManagerTest, FocusChangeListener) { EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(view2, null_view)); } -class TestNativeButton : public NativeTextButton { - public: - explicit TestNativeButton(const string16& text) - : NativeTextButton(NULL, text) { - }; - virtual gfx::NativeView TestGetNativeControlView() { - return GetWidget()->GetNativeView(); - } -}; - -class TestCheckbox : public Checkbox { - public: - explicit TestCheckbox(const string16& text) : Checkbox(text) { - }; - virtual gfx::NativeView TestGetNativeControlView() { - return GetWidget()->GetNativeView(); - } -}; - -class TestRadioButton : public RadioButton { - public: - explicit TestRadioButton(const string16& text) - : RadioButton(text, 1) { - } - virtual gfx::NativeView TestGetNativeControlView() { - return GetWidget()->GetNativeView(); - } -}; - +#if !defined(USE_AURA) class TestTextfield : public Textfield { public: - TestTextfield() { } + TestTextfield() {} virtual gfx::NativeView TestGetNativeControlView() { return native_wrapper_->GetTestingHandle(); } }; -class TestCombobox : public Combobox, public ui::ComboboxModel { - public: - TestCombobox() : Combobox(this) { } - virtual gfx::NativeView TestGetNativeControlView() { - return native_wrapper_->GetTestingHandle(); - } - virtual int GetItemCount() { - return 10; - } - virtual string16 GetItemAt(int index) { - return ASCIIToUTF16("Hello combo"); - } -}; - class TestTabbedPane : public TabbedPane { public: - TestTabbedPane() { } + TestTabbedPane() {} virtual gfx::NativeView TestGetNativeControlView() { return native_tabbed_pane_->GetTestingHandle(); } }; -#if !defined(TOUCH_UI) -// TODO(oshima): replace TOUCH_UI with PURE_VIEWS - -// Tests that NativeControls do set the focus View appropriately on the +// Tests that NativeControls do set the focused View appropriately on the // FocusManager. TEST_F(FocusManagerTest, FAILS_FocusNativeControls) { TestTextfield* textfield = new TestTextfield(); TestTabbedPane* tabbed_pane = new TestTabbedPane(); TestTextfield* textfield2 = new TestTextfield(); - content_view_->AddChildView(textfield); - content_view_->AddChildView(tabbed_pane); + GetContentsView()->AddChildView(textfield); + GetContentsView()->AddChildView(tabbed_pane); tabbed_pane->AddTab(ASCIIToUTF16("Awesome textfield"), textfield2); // Simulate the native view getting the native focus (such as by user click). - FocusNativeView(textfield->TestGetNativeControlView()); + GetWidget()->FocusNativeView(textfield->TestGetNativeControlView()); EXPECT_EQ(textfield, GetFocusManager()->GetFocusedView()); - FocusNativeView(tabbed_pane->TestGetNativeControlView()); + GetWidget()->FocusNativeView(tabbed_pane->TestGetNativeControlView()); EXPECT_EQ(tabbed_pane, GetFocusManager()->GetFocusedView()); - FocusNativeView(textfield2->TestGetNativeControlView()); + GetWidget()->FocusNativeView(textfield2->TestGetNativeControlView()); EXPECT_EQ(textfield2, GetFocusManager()->GetFocusedView()); } #endif -// On linux, we don't store/restore focused view because gtk handles -// this (and pure views will be the same). -#if defined(OS_WIN) - -// Test that when activating/deactivating the top window, the focus is stored/ -// restored properly. -TEST_F(FocusManagerTest, FocusStoreRestore) { - // Simulate an activate, otherwise the deactivate isn't going to do anything. - SimulateActivateWindow(); - - NativeTextButton* button = new NativeTextButton(NULL, - ASCIIToUTF16("Press me")); - View* view = new View(); - view->set_focusable(true); - - content_view_->AddChildView(button); - button->SetBounds(10, 10, 200, 30); - content_view_->AddChildView(view); - RunPendingMessages(); - - TestFocusChangeListener listener; - AddFocusChangeListener(&listener); - - view->RequestFocus(); - RunPendingMessages(); - // MessageLoopForUI::current()->RunWithDispatcher(new AcceleratorHandler()); - - // Visual Studio 2010 has problems converting NULL to the null pointer for - // std::pair. See http://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair - // It will work if we pass nullptr. -#if defined(_MSC_VER) && _MSC_VER >= 1600 - views::View* null_view = nullptr; -#else - views::View* null_view = NULL; -#endif - - // Deacivate the window, it should store its focus. - SimulateDeactivateWindow(); - EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView()); - ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size())); - EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view)); - EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(view, null_view)); - listener.ClearFocusChanges(); - - // Reactivate, focus should come-back to the previously focused view. - SimulateActivateWindow(); - EXPECT_EQ(view, GetFocusManager()->GetFocusedView()); - ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); - EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view)); - listener.ClearFocusChanges(); - - // Same test with a NativeControl. - button->RequestFocus(); - SimulateDeactivateWindow(); - EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView()); - ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size())); - EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(view, button)); - EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(button, null_view)); - listener.ClearFocusChanges(); - - SimulateActivateWindow(); - EXPECT_EQ(button, GetFocusManager()->GetFocusedView()); - ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); - EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, button)); - listener.ClearFocusChanges(); - - /* - // Now test that while the window is inactive we can change the focused view - // (we do that in several places). - SimulateDeactivateWindow(); - // TODO: would have to mock the window being inactive (with a TestWidgetWin - // that would return false on IsActive()). - GetFocusManager()->SetFocusedView(view); - ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_ACTIVE, NULL); - - EXPECT_EQ(view, GetFocusManager()->GetFocusedView()); - ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size())); - EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(button, null_view)); - EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(null_view, view)); - */ -} -#endif - -#if !defined(TOUCH_UI) -// TODO(oshima): There is no tabbed pane in pure views. Replace it -// with different implementation. - +// There is no tabbed pane in Aura. +#if !defined(USE_AURA) TEST_F(FocusManagerTest, ContainsView) { View* view = new View(); scoped_ptr<View> detached_view(new View()); @@ -1051,8 +176,8 @@ TEST_F(FocusManagerTest, ContainsView) { NativeTextButton* tab_button = new NativeTextButton( NULL, ASCIIToUTF16("tab button")); - content_view_->AddChildView(view); - content_view_->AddChildView(tabbed_pane); + GetContentsView()->AddChildView(view); + GetContentsView()->AddChildView(tabbed_pane); // Adding a View inside a TabbedPane to test the case of nested root view. tabbed_pane->AddTab(ASCIIToUTF16("Awesome tab"), nested_tabbed_pane); @@ -1066,231 +191,6 @@ TEST_F(FocusManagerTest, ContainsView) { } #endif -TEST_F(FocusTraversalTest, NormalTraversal) { - const int kTraversalIDs[] = { kTopCheckBoxID, kAppleTextfieldID, - kOrangeTextfieldID, kBananaTextfieldID, kKiwiTextfieldID, - kFruitButtonID, kFruitCheckBoxID, kComboboxID, kBroccoliButtonID, - kRosettaLinkID, kStupeurEtTremblementLinkID, - kDinerGameLinkID, kRidiculeLinkID, kClosetLinkID, kVisitingLinkID, - kAmelieLinkID, kJoyeuxNoelLinkID, kCampingLinkID, kBriceDeNiceLinkID, - kTaxiLinkID, kAsterixLinkID, kOKButtonID, kCancelButtonID, kHelpButtonID, - kStyleContainerID, kBoldCheckBoxID, kItalicCheckBoxID, - kUnderlinedCheckBoxID, kStyleHelpLinkID, kStyleTextEditID, - kSearchTextfieldID, kSearchButtonID, kHelpLinkID, - kThumbnailContainerID, kThumbnailStarID, kThumbnailSuperStarID }; - - // Uncomment the following line if you want to test manually the UI of this - // test. - // MessageLoopForUI::current()->RunWithDispatcher(new AcceleratorHandler()); - - // Let's traverse the whole focus hierarchy (several times, to make sure it - // loops OK). - GetFocusManager()->ClearFocus(); - for (int i = 0; i < 3; ++i) { - for (size_t j = 0; j < arraysize(kTraversalIDs); j++) { - GetFocusManager()->AdvanceFocus(false); - View* focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kTraversalIDs[j], focused_view->id()); - } - } - - // Let's traverse in reverse order. - GetFocusManager()->ClearFocus(); - for (int i = 0; i < 3; ++i) { - for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) { - GetFocusManager()->AdvanceFocus(true); - View* focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kTraversalIDs[j], focused_view->id()); - } - } -} - -TEST_F(FocusTraversalTest, TraversalWithNonEnabledViews) { - const int kDisabledIDs[] = { - kBananaTextfieldID, kFruitCheckBoxID, kComboboxID, kAsparagusButtonID, - kCauliflowerButtonID, kClosetLinkID, kVisitingLinkID, kBriceDeNiceLinkID, - kTaxiLinkID, kAsterixLinkID, kHelpButtonID, kBoldCheckBoxID, - kSearchTextfieldID, kHelpLinkID }; - - const int kTraversalIDs[] = { kTopCheckBoxID, kAppleTextfieldID, - kOrangeTextfieldID, kKiwiTextfieldID, kFruitButtonID, kBroccoliButtonID, - kRosettaLinkID, kStupeurEtTremblementLinkID, kDinerGameLinkID, - kRidiculeLinkID, kAmelieLinkID, kJoyeuxNoelLinkID, kCampingLinkID, - kOKButtonID, kCancelButtonID, kStyleContainerID, kItalicCheckBoxID, - kUnderlinedCheckBoxID, kStyleHelpLinkID, kStyleTextEditID, - kSearchButtonID, kThumbnailContainerID, kThumbnailStarID, - kThumbnailSuperStarID }; - - // Let's disable some views. - for (size_t i = 0; i < arraysize(kDisabledIDs); i++) { - View* v = FindViewByID(kDisabledIDs[i]); - ASSERT_TRUE(v != NULL); - v->SetEnabled(false); - } - - // Uncomment the following line if you want to test manually the UI of this - // test. - // MessageLoopForUI::current()->RunWithDispatcher(new AcceleratorHandler()); - - View* focused_view; - // Let's do one traversal (several times, to make sure it loops ok). - GetFocusManager()->ClearFocus(); - for (int i = 0; i < 3; ++i) { - for (size_t j = 0; j < arraysize(kTraversalIDs); j++) { - GetFocusManager()->AdvanceFocus(false); - focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kTraversalIDs[j], focused_view->id()); - } - } - - // Same thing in reverse. - GetFocusManager()->ClearFocus(); - for (int i = 0; i < 3; ++i) { - for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) { - GetFocusManager()->AdvanceFocus(true); - focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kTraversalIDs[j], focused_view->id()); - } - } -} - -TEST_F(FocusTraversalTest, TraversalWithInvisibleViews) { - const int kInvisibleIDs[] = { kTopCheckBoxID, kOKButtonID, - kThumbnailContainerID }; - - const int kTraversalIDs[] = { kAppleTextfieldID, kOrangeTextfieldID, - kBananaTextfieldID, kKiwiTextfieldID, kFruitButtonID, kFruitCheckBoxID, - kComboboxID, kBroccoliButtonID, kRosettaLinkID, - kStupeurEtTremblementLinkID, kDinerGameLinkID, kRidiculeLinkID, - kClosetLinkID, kVisitingLinkID, kAmelieLinkID, kJoyeuxNoelLinkID, - kCampingLinkID, kBriceDeNiceLinkID, kTaxiLinkID, kAsterixLinkID, - kCancelButtonID, kHelpButtonID, kStyleContainerID, kBoldCheckBoxID, - kItalicCheckBoxID, kUnderlinedCheckBoxID, kStyleHelpLinkID, - kStyleTextEditID, kSearchTextfieldID, kSearchButtonID, kHelpLinkID }; - - - // Let's make some views invisible. - for (size_t i = 0; i < arraysize(kInvisibleIDs); i++) { - View* v = FindViewByID(kInvisibleIDs[i]); - ASSERT_TRUE(v != NULL); - v->SetVisible(false); - } - - // Uncomment the following line if you want to test manually the UI of this - // test. - // MessageLoopForUI::current()->RunWithDispatcher(new AcceleratorHandler()); - - View* focused_view; - // Let's do one traversal (several times, to make sure it loops ok). - GetFocusManager()->ClearFocus(); - for (int i = 0; i < 3; ++i) { - for (size_t j = 0; j < arraysize(kTraversalIDs); j++) { - GetFocusManager()->AdvanceFocus(false); - focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kTraversalIDs[j], focused_view->id()); - } - } - - // Same thing in reverse. - GetFocusManager()->ClearFocus(); - for (int i = 0; i < 3; ++i) { - for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) { - GetFocusManager()->AdvanceFocus(true); - focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kTraversalIDs[j], focused_view->id()); - } - } -} - -TEST_F(FocusTraversalTest, PaneTraversal) { - // Tests trapping the traversal within a pane - useful for full - // keyboard accessibility for toolbars. - - // First test the left container. - const int kLeftTraversalIDs[] = { - kAppleTextfieldID, - kOrangeTextfieldID, kBananaTextfieldID, kKiwiTextfieldID, - kFruitButtonID, kFruitCheckBoxID, kComboboxID }; - - FocusSearch focus_search_left(left_container_, true, false); - left_container_->EnablePaneFocus(&focus_search_left); - FindViewByID(kComboboxID)->RequestFocus(); - - // Traverse the focus hierarchy within the pane several times. - for (int i = 0; i < 3; ++i) { - for (size_t j = 0; j < arraysize(kLeftTraversalIDs); j++) { - GetFocusManager()->AdvanceFocus(false); - View* focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kLeftTraversalIDs[j], focused_view->id()); - } - } - - // Traverse in reverse order. - FindViewByID(kAppleTextfieldID)->RequestFocus(); - for (int i = 0; i < 3; ++i) { - for (int j = arraysize(kLeftTraversalIDs) - 1; j >= 0; --j) { - GetFocusManager()->AdvanceFocus(true); - View* focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kLeftTraversalIDs[j], focused_view->id()); - } - } - - // Now test the right container, but this time with accessibility mode. - // Make some links not focusable, but mark one of them as - // "accessibility focusable", so it should show up in the traversal. - const int kRightTraversalIDs[] = { - kBroccoliButtonID, kDinerGameLinkID, kRidiculeLinkID, - kClosetLinkID, kVisitingLinkID, kAmelieLinkID, kJoyeuxNoelLinkID, - kCampingLinkID, kBriceDeNiceLinkID, kTaxiLinkID, kAsterixLinkID }; - - FocusSearch focus_search_right(right_container_, true, true); - right_container_->EnablePaneFocus(&focus_search_right); - FindViewByID(kRosettaLinkID)->set_focusable(false); - FindViewByID(kStupeurEtTremblementLinkID)->set_focusable(false); - FindViewByID(kDinerGameLinkID)->set_accessibility_focusable(true); - FindViewByID(kDinerGameLinkID)->set_focusable(false); - FindViewByID(kAsterixLinkID)->RequestFocus(); - - // Traverse the focus hierarchy within the pane several times. - for (int i = 0; i < 3; ++i) { - for (size_t j = 0; j < arraysize(kRightTraversalIDs); j++) { - GetFocusManager()->AdvanceFocus(false); - View* focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kRightTraversalIDs[j], focused_view->id()); - } - } - - // Traverse in reverse order. - FindViewByID(kBroccoliButtonID)->RequestFocus(); - for (int i = 0; i < 3; ++i) { - for (int j = arraysize(kRightTraversalIDs) - 1; j >= 0; --j) { - GetFocusManager()->AdvanceFocus(true); - View* focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kRightTraversalIDs[j], focused_view->id()); - } - } -} - // Counts accelerator calls. class TestAcceleratorTarget : public ui::AcceleratorTarget { public: @@ -1453,199 +353,6 @@ TEST_F(FocusManagerTest, CallsSelfDeletingAcceleratorTarget) { EXPECT_EQ(target.accelerator_count(), 1); } -class MessageTrackingView : public View { - public: - MessageTrackingView() : accelerator_pressed_(false) { - } - - virtual bool OnKeyPressed(const KeyEvent& e) { - keys_pressed_.push_back(e.key_code()); - return true; - } - - virtual bool OnKeyReleased(const KeyEvent& e) { - keys_released_.push_back(e.key_code()); - return true; - } - - virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) { - accelerator_pressed_ = true; - return true; - } - - void Reset() { - accelerator_pressed_ = false; - keys_pressed_.clear(); - keys_released_.clear(); - } - - const std::vector<ui::KeyboardCode>& keys_pressed() const { - return keys_pressed_; - } - - const std::vector<ui::KeyboardCode>& keys_released() const { - return keys_released_; - } - - bool accelerator_pressed() const { - return accelerator_pressed_; - } - - private: - bool accelerator_pressed_; - std::vector<ui::KeyboardCode> keys_pressed_; - std::vector<ui::KeyboardCode> keys_released_; - - DISALLOW_COPY_AND_ASSIGN(MessageTrackingView); -}; - -#if defined(OS_WIN) -// This test is now Windows only. Linux Views port does not handle accelerator -// keys in AcceleratorHandler anymore. The logic has been moved into -// NativeWidgetGtk::OnKeyEvent(). -// Tests that the keyup messages are eaten for accelerators. -TEST_F(FocusManagerTest, IgnoreKeyupForAccelerators) { - FocusManager* focus_manager = GetFocusManager(); - MessageTrackingView* mtv = new MessageTrackingView(); - mtv->AddAccelerator(ui::Accelerator(ui::VKEY_0, false, false, false)); - mtv->AddAccelerator(ui::Accelerator(ui::VKEY_1, false, false, false)); - content_view_->AddChildView(mtv); - focus_manager->SetFocusedView(mtv); - - // First send a non-accelerator key sequence. - PostKeyDown(ui::VKEY_9); - PostKeyUp(ui::VKEY_9); - AcceleratorHandler accelerator_handler; - MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); - MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler); - // Make sure we get a key-up and key-down. - ASSERT_EQ(1U, mtv->keys_pressed().size()); - EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[0]); - ASSERT_EQ(1U, mtv->keys_released().size()); - EXPECT_EQ(ui::VKEY_9, mtv->keys_released()[0]); - EXPECT_FALSE(mtv->accelerator_pressed()); - mtv->Reset(); - - // Same thing with repeat and more than one key at once. - PostKeyDown(ui::VKEY_9); - PostKeyDown(ui::VKEY_9); - PostKeyDown(ui::VKEY_8); - PostKeyDown(ui::VKEY_9); - PostKeyDown(ui::VKEY_7); - PostKeyUp(ui::VKEY_9); - PostKeyUp(ui::VKEY_7); - PostKeyUp(ui::VKEY_8); - MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); - MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler); - // Make sure we get a key-up and key-down. - ASSERT_EQ(5U, mtv->keys_pressed().size()); - EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[0]); - EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[1]); - EXPECT_EQ(ui::VKEY_8, mtv->keys_pressed()[2]); - EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[3]); - EXPECT_EQ(ui::VKEY_7, mtv->keys_pressed()[4]); - ASSERT_EQ(3U, mtv->keys_released().size()); - EXPECT_EQ(ui::VKEY_9, mtv->keys_released()[0]); - EXPECT_EQ(ui::VKEY_7, mtv->keys_released()[1]); - EXPECT_EQ(ui::VKEY_8, mtv->keys_released()[2]); - EXPECT_FALSE(mtv->accelerator_pressed()); - mtv->Reset(); - - // Now send an accelerator key sequence. - PostKeyDown(ui::VKEY_0); - PostKeyUp(ui::VKEY_0); - MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); - MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler); - EXPECT_TRUE(mtv->keys_pressed().empty()); - EXPECT_TRUE(mtv->keys_released().empty()); - EXPECT_TRUE(mtv->accelerator_pressed()); - mtv->Reset(); - - // Same thing with repeat and more than one key at once. - PostKeyDown(ui::VKEY_0); - PostKeyDown(ui::VKEY_1); - PostKeyDown(ui::VKEY_1); - PostKeyDown(ui::VKEY_0); - PostKeyDown(ui::VKEY_0); - PostKeyUp(ui::VKEY_1); - PostKeyUp(ui::VKEY_0); - MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); - MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler); - EXPECT_TRUE(mtv->keys_pressed().empty()); - EXPECT_TRUE(mtv->keys_released().empty()); - EXPECT_TRUE(mtv->accelerator_pressed()); - mtv->Reset(); -} -#endif - -#if defined(OS_WIN) && !defined(USE_AURA) -// Test that the focus manager is created successfully for the first view -// window parented to a native dialog. -TEST_F(FocusManagerTest, CreationForNativeRoot) { - // Create a window class. - WNDCLASSEX class_ex; - memset(&class_ex, 0, sizeof(class_ex)); - class_ex.cbSize = sizeof(WNDCLASSEX); - class_ex.lpfnWndProc = &DefWindowProc; - class_ex.lpszClassName = L"TestWindow"; - ATOM atom = RegisterClassEx(&class_ex); - ASSERT_TRUE(atom); - - // Create a native dialog window. - HWND hwnd = CreateWindowEx(0, class_ex.lpszClassName, NULL, - WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, - NULL, NULL, NULL, NULL); - ASSERT_TRUE(hwnd); - - // Create a view window parented to native dialog. - scoped_ptr<Widget> widget1(new Widget); - Widget::InitParams params(Widget::InitParams::TYPE_CONTROL); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.parent = hwnd; - params.bounds = gfx::Rect(0, 0, 100, 100); - params.top_level = true; // This is top level in views hierarchy. - widget1->Init(params); - - // Get the focus manager directly from the first window. Should exist - // because the first window is the root widget. - views::FocusManager* focus_manager1 = widget1->GetFocusManager(); - EXPECT_TRUE(focus_manager1); - - // Create another view window parented to the first view window. - scoped_ptr<Widget> widget2(new Widget); - params.parent = widget1->GetNativeView(); - params.top_level = false; // This is child widget. - widget2->Init(params); - - // Access the shared focus manager directly from the second window. - views::FocusManager* focus_manager2 = widget2->GetFocusManager(); - EXPECT_EQ(focus_manager2, focus_manager1); - - // Access the shared focus manager indirectly from the first window handle. - gfx::NativeWindow native_window = widget1->GetNativeWindow(); - views::Widget* widget = - views::Widget::GetWidgetForNativeWindow(native_window); - EXPECT_EQ(widget->GetFocusManager(), focus_manager1); - - // Access the shared focus manager indirectly from the second window handle. - native_window = widget2->GetNativeWindow(); - widget = views::Widget::GetWidgetForNativeWindow(native_window); - EXPECT_EQ(widget->GetFocusManager(), focus_manager1); - - // Access the shared focus manager indirectly from the first view handle. - gfx::NativeView native_view = widget1->GetNativeView(); - widget = views::Widget::GetTopLevelWidgetForNativeView(native_view); - EXPECT_EQ(widget->GetFocusManager(), focus_manager1); - - // Access the shared focus manager indirectly from the second view handle. - native_view = widget2->GetNativeView(); - widget = views::Widget::GetTopLevelWidgetForNativeView(native_view); - EXPECT_EQ(widget->GetFocusManager(), focus_manager1); - - DestroyWindow(hwnd); -} -#endif - class FocusManagerDtorTest : public FocusManagerTest { protected: typedef std::vector<std::string> DtorTrackVector; @@ -1713,22 +420,18 @@ class FocusManagerDtorTest : public FocusManagerTest { ViewsTestBase::SetUp(); FocusManagerFactory::Install(new TestFocusManagerFactory(&dtor_tracker_)); // Create WindowDtorTracked that uses FocusManagerDtorTracked. - window_ = new WindowDtorTracked(&dtor_tracker_); + Widget* widget = new WindowDtorTracked(&dtor_tracker_); Widget::InitParams params; params.delegate = this; params.bounds = gfx::Rect(0, 0, 100, 100); - window_->Init(params); + widget->Init(params); tracked_focus_manager_ = static_cast<FocusManagerDtorTracked*>(GetFocusManager()); - window_->Show(); + widget->Show(); } virtual void TearDown() { - if (window_) { - window_->Close(); - RunPendingMessages(); - } FocusManagerFactory::Install(NULL); ViewsTestBase::TearDown(); } @@ -1737,17 +440,18 @@ class FocusManagerDtorTest : public FocusManagerTest { DtorTrackVector dtor_tracker_; }; +#if !defined(USE_AURA) TEST_F(FocusManagerDtorTest, FocusManagerDestructedLast) { // Setup views hierarchy. TabbedPane* tabbed_pane = new TabbedPane(); - content_view_->AddChildView(tabbed_pane); + GetContentsView()->AddChildView(tabbed_pane); NativeButtonDtorTracked* button = new NativeButtonDtorTracked( ASCIIToUTF16("button"), &dtor_tracker_); tabbed_pane->AddTab(ASCIIToUTF16("Awesome tab"), button); // Close the window. - window_->Close(); + GetWidget()->Close(); RunPendingMessages(); // Test window, button and focus manager should all be destructed. @@ -1755,9 +459,7 @@ TEST_F(FocusManagerDtorTest, FocusManagerDestructedLast) { // Focus manager should be the last one to destruct. ASSERT_STREQ("FocusManagerDtorTracked", dtor_tracker_[2].c_str()); - - // Clear window_ so that we don't try to close it again. - window_ = NULL; } +#endif } // namespace views diff --git a/ui/views/focus/focus_manager_unittest_win.cc b/ui/views/focus/focus_manager_unittest_win.cc new file mode 100644 index 0000000..4744d8d --- /dev/null +++ b/ui/views/focus/focus_manager_unittest_win.cc @@ -0,0 +1,285 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/views/focus/focus_manager.h" + +#include "base/utf_string_conversions.h" +#include "ui/views/focus/accelerator_handler.h" +#include "ui/views/focus/focus_manager_test.h" +#include "ui/views/widget/widget.h" +#include "views/controls/button/text_button.h" + +namespace views { + +namespace { + +class MessageTrackingView : public View { + public: + MessageTrackingView() : accelerator_pressed_(false) { + } + + void Reset() { + accelerator_pressed_ = false; + keys_pressed_.clear(); + keys_released_.clear(); + } + + const std::vector<ui::KeyboardCode>& keys_pressed() const { + return keys_pressed_; + } + + const std::vector<ui::KeyboardCode>& keys_released() const { + return keys_released_; + } + + bool accelerator_pressed() const { + return accelerator_pressed_; + } + + // Overridden from View: + virtual bool OnKeyPressed(const KeyEvent& e) OVERRIDE { + keys_pressed_.push_back(e.key_code()); + return true; + } + virtual bool OnKeyReleased(const KeyEvent& e) OVERRIDE { + keys_released_.push_back(e.key_code()); + return true; + } + virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE { + accelerator_pressed_ = true; + return true; + } + + private: + bool accelerator_pressed_; + std::vector<ui::KeyboardCode> keys_pressed_; + std::vector<ui::KeyboardCode> keys_released_; + + DISALLOW_COPY_AND_ASSIGN(MessageTrackingView); +}; + +} // namespace + +// Test that when activating/deactivating the top window, the focus is stored/ +// restored properly. +TEST_F(FocusManagerTest, FocusStoreRestore) { + // Simulate an activate, otherwise the deactivate isn't going to do anything. + SimulateActivateWindow(); + + NativeTextButton* button = new NativeTextButton(NULL, + ASCIIToUTF16("Press me")); + View* view = new View(); + view->set_focusable(true); + + GetContentsView()->AddChildView(button); + button->SetBounds(10, 10, 200, 30); + GetContentsView()->AddChildView(view); + RunPendingMessages(); + + TestFocusChangeListener listener; + AddFocusChangeListener(&listener); + + view->RequestFocus(); + RunPendingMessages(); + // MessageLoopForUI::current()->RunWithDispatcher(new AcceleratorHandler()); + + // Visual Studio 2010 has problems converting NULL to the null pointer for + // std::pair. See http://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair + // It will work if we pass nullptr. +#if defined(_MSC_VER) && _MSC_VER >= 1600 + views::View* null_view = nullptr; +#else + views::View* null_view = NULL; +#endif + + // Deacivate the window, it should store its focus. + SimulateDeactivateWindow(); + EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView()); + ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size())); + EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view)); + EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(view, null_view)); + listener.ClearFocusChanges(); + + // Reactivate, focus should come-back to the previously focused view. + SimulateActivateWindow(); + EXPECT_EQ(view, GetFocusManager()->GetFocusedView()); + ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); + EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view)); + listener.ClearFocusChanges(); + + // Same test with a NativeControl. + button->RequestFocus(); + SimulateDeactivateWindow(); + EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView()); + ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size())); + EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(view, button)); + EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(button, null_view)); + listener.ClearFocusChanges(); + + SimulateActivateWindow(); + EXPECT_EQ(button, GetFocusManager()->GetFocusedView()); + ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); + EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, button)); + listener.ClearFocusChanges(); + + /* + // Now test that while the window is inactive we can change the focused view + // (we do that in several places). + SimulateDeactivateWindow(); + // TODO: would have to mock the window being inactive (with a TestWidgetWin + // that would return false on IsActive()). + GetFocusManager()->SetFocusedView(view); + ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_ACTIVE, NULL); + + EXPECT_EQ(view, GetFocusManager()->GetFocusedView()); + ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size())); + EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(button, null_view)); + EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(null_view, view)); + */ +} + +// Test that the focus manager is created successfully for the first view +// window parented to a native dialog. +TEST_F(FocusManagerTest, CreationForNativeRoot) { + // Create a window class. + WNDCLASSEX class_ex; + memset(&class_ex, 0, sizeof(class_ex)); + class_ex.cbSize = sizeof(WNDCLASSEX); + class_ex.lpfnWndProc = &DefWindowProc; + class_ex.lpszClassName = L"TestWindow"; + ATOM atom = RegisterClassEx(&class_ex); + ASSERT_TRUE(atom); + + // Create a native dialog window. + HWND hwnd = CreateWindowEx(0, class_ex.lpszClassName, NULL, + WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, + NULL, NULL, NULL, NULL); + ASSERT_TRUE(hwnd); + + // Create a view window parented to native dialog. + scoped_ptr<Widget> widget1(new Widget); + Widget::InitParams params(Widget::InitParams::TYPE_CONTROL); + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.parent = hwnd; + params.bounds = gfx::Rect(0, 0, 100, 100); + params.top_level = true; // This is top level in views hierarchy. + widget1->Init(params); + + // Get the focus manager directly from the first window. Should exist + // because the first window is the root widget. + views::FocusManager* focus_manager1 = widget1->GetFocusManager(); + EXPECT_TRUE(focus_manager1); + + // Create another view window parented to the first view window. + scoped_ptr<Widget> widget2(new Widget); + params.parent = widget1->GetNativeView(); + params.top_level = false; // This is child widget. + widget2->Init(params); + + // Access the shared focus manager directly from the second window. + views::FocusManager* focus_manager2 = widget2->GetFocusManager(); + EXPECT_EQ(focus_manager2, focus_manager1); + + // Access the shared focus manager indirectly from the first window handle. + gfx::NativeWindow native_window = widget1->GetNativeWindow(); + views::Widget* widget = + views::Widget::GetWidgetForNativeWindow(native_window); + EXPECT_EQ(widget->GetFocusManager(), focus_manager1); + + // Access the shared focus manager indirectly from the second window handle. + native_window = widget2->GetNativeWindow(); + widget = views::Widget::GetWidgetForNativeWindow(native_window); + EXPECT_EQ(widget->GetFocusManager(), focus_manager1); + + // Access the shared focus manager indirectly from the first view handle. + gfx::NativeView native_view = widget1->GetNativeView(); + widget = views::Widget::GetTopLevelWidgetForNativeView(native_view); + EXPECT_EQ(widget->GetFocusManager(), focus_manager1); + + // Access the shared focus manager indirectly from the second view handle. + native_view = widget2->GetNativeView(); + widget = views::Widget::GetTopLevelWidgetForNativeView(native_view); + EXPECT_EQ(widget->GetFocusManager(), focus_manager1); + + DestroyWindow(hwnd); +} + +// Tests that the keyup messages are eaten for accelerators. +// Windows-only, Windows is the only platform that handles accelerators in +// AcceleratorHandler. NativeWidgetAura/NativeWidgetGtk::OnKeyEvent handles +// them in other configurations. +TEST_F(FocusManagerTest, IgnoreKeyupForAccelerators) { + FocusManager* focus_manager = GetFocusManager(); + MessageTrackingView* mtv = new MessageTrackingView(); + mtv->AddAccelerator(ui::Accelerator(ui::VKEY_0, false, false, false)); + mtv->AddAccelerator(ui::Accelerator(ui::VKEY_1, false, false, false)); + GetContentsView()->AddChildView(mtv); + focus_manager->SetFocusedView(mtv); + + // First send a non-accelerator key sequence. + PostKeyDown(ui::VKEY_9); + PostKeyUp(ui::VKEY_9); + AcceleratorHandler accelerator_handler; + MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler); + // Make sure we get a key-up and key-down. + ASSERT_EQ(1U, mtv->keys_pressed().size()); + EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[0]); + ASSERT_EQ(1U, mtv->keys_released().size()); + EXPECT_EQ(ui::VKEY_9, mtv->keys_released()[0]); + EXPECT_FALSE(mtv->accelerator_pressed()); + mtv->Reset(); + + // Same thing with repeat and more than one key at once. + PostKeyDown(ui::VKEY_9); + PostKeyDown(ui::VKEY_9); + PostKeyDown(ui::VKEY_8); + PostKeyDown(ui::VKEY_9); + PostKeyDown(ui::VKEY_7); + PostKeyUp(ui::VKEY_9); + PostKeyUp(ui::VKEY_7); + PostKeyUp(ui::VKEY_8); + MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler); + // Make sure we get a key-up and key-down. + ASSERT_EQ(5U, mtv->keys_pressed().size()); + EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[0]); + EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[1]); + EXPECT_EQ(ui::VKEY_8, mtv->keys_pressed()[2]); + EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[3]); + EXPECT_EQ(ui::VKEY_7, mtv->keys_pressed()[4]); + ASSERT_EQ(3U, mtv->keys_released().size()); + EXPECT_EQ(ui::VKEY_9, mtv->keys_released()[0]); + EXPECT_EQ(ui::VKEY_7, mtv->keys_released()[1]); + EXPECT_EQ(ui::VKEY_8, mtv->keys_released()[2]); + EXPECT_FALSE(mtv->accelerator_pressed()); + mtv->Reset(); + + // Now send an accelerator key sequence. + PostKeyDown(ui::VKEY_0); + PostKeyUp(ui::VKEY_0); + MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler); + EXPECT_TRUE(mtv->keys_pressed().empty()); + EXPECT_TRUE(mtv->keys_released().empty()); + EXPECT_TRUE(mtv->accelerator_pressed()); + mtv->Reset(); + + // Same thing with repeat and more than one key at once. + PostKeyDown(ui::VKEY_0); + PostKeyDown(ui::VKEY_1); + PostKeyDown(ui::VKEY_1); + PostKeyDown(ui::VKEY_0); + PostKeyDown(ui::VKEY_0); + PostKeyUp(ui::VKEY_1); + PostKeyUp(ui::VKEY_0); + MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler); + EXPECT_TRUE(mtv->keys_pressed().empty()); + EXPECT_TRUE(mtv->keys_released().empty()); + EXPECT_TRUE(mtv->accelerator_pressed()); + mtv->Reset(); +} + +} // namespace views diff --git a/ui/views/focus/focus_traversal_unittest.cc b/ui/views/focus/focus_traversal_unittest.cc new file mode 100644 index 0000000..87bfc26 --- /dev/null +++ b/ui/views/focus/focus_traversal_unittest.cc @@ -0,0 +1,812 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/views/focus/focus_manager.h" + +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "ui/base/models/combobox_model.h" +#include "ui/views/focus/focus_manager_test.h" +#include "ui/views/widget/root_view.h" +#include "ui/views/widget/widget.h" +#include "views/controls/button/checkbox.h" +#include "views/controls/button/radio_button.h" +#include "views/controls/button/text_button.h" +#include "views/controls/combobox/combobox.h" +#include "views/controls/label.h" +#include "views/controls/link.h" +#include "views/controls/native/native_view_host.h" +#include "views/controls/scroll_view.h" +#include "views/controls/textfield/textfield.h" + +#if !defined(USE_AURA) +#include "views/controls/tabbed_pane/tabbed_pane.h" +#endif + +namespace views { + +namespace { + +int count = 1; + +const int kTopCheckBoxID = count++; // 1 +const int kLeftContainerID = count++; +const int kAppleLabelID = count++; +const int kAppleTextfieldID = count++; +const int kOrangeLabelID = count++; // 5 +const int kOrangeTextfieldID = count++; +const int kBananaLabelID = count++; +const int kBananaTextfieldID = count++; +const int kKiwiLabelID = count++; +const int kKiwiTextfieldID = count++; // 10 +const int kFruitButtonID = count++; +const int kFruitCheckBoxID = count++; +const int kComboboxID = count++; + +const int kRightContainerID = count++; +const int kAsparagusButtonID = count++; // 15 +const int kBroccoliButtonID = count++; +const int kCauliflowerButtonID = count++; + +const int kInnerContainerID = count++; +const int kScrollViewID = count++; +const int kRosettaLinkID = count++; // 20 +const int kStupeurEtTremblementLinkID = count++; +const int kDinerGameLinkID = count++; +const int kRidiculeLinkID = count++; +const int kClosetLinkID = count++; +const int kVisitingLinkID = count++; // 25 +const int kAmelieLinkID = count++; +const int kJoyeuxNoelLinkID = count++; +const int kCampingLinkID = count++; +const int kBriceDeNiceLinkID = count++; +const int kTaxiLinkID = count++; // 30 +const int kAsterixLinkID = count++; + +const int kOKButtonID = count++; +const int kCancelButtonID = count++; +const int kHelpButtonID = count++; + +#if !defined(USE_AURA) +const int kStyleContainerID = count++; // 35 +const int kBoldCheckBoxID = count++; +const int kItalicCheckBoxID = count++; +const int kUnderlinedCheckBoxID = count++; +const int kStyleHelpLinkID = count++; +const int kStyleTextEditID = count++; // 40 +#endif + +const int kSearchContainerID = count++; +const int kSearchTextfieldID = count++; +const int kSearchButtonID = count++; +const int kHelpLinkID = count++; + +const int kThumbnailContainerID = count++; // 45 +const int kThumbnailStarID = count++; +const int kThumbnailSuperStarID = count++; + +class DummyComboboxModel : public ui::ComboboxModel { + public: + virtual int GetItemCount() { return 10; } + + virtual string16 GetItemAt(int index) { + return ASCIIToUTF16("Item ") + base::IntToString16(index); + } +}; + +// A View that can act as a pane. +class PaneView : public View, public FocusTraversable { + public: + PaneView() : focus_search_(NULL) {} + + // If this method is called, this view will use GetPaneFocusTraversable to + // have this provided FocusSearch used instead of the default one, allowing + // you to trap focus within the pane. + void EnablePaneFocus(FocusSearch* focus_search) { + focus_search_ = focus_search; + } + + // Overridden from views::View: + virtual FocusTraversable* GetPaneFocusTraversable() { + if (focus_search_) + return this; + else + return NULL; + } + + // Overridden from views::FocusTraversable: + virtual views::FocusSearch* GetFocusSearch() { + return focus_search_; + } + virtual FocusTraversable* GetFocusTraversableParent() { + return NULL; + } + virtual View* GetFocusTraversableParentView() { + return NULL; + } + + private: + FocusSearch* focus_search_; +}; + +// BorderView is a view containing a native window with its own view hierarchy. +// It is interesting to test focus traversal from a view hierarchy to an inner +// view hierarchy. +class BorderView : public NativeViewHost { + public: + explicit BorderView(View* child) : child_(child), widget_(NULL) { + DCHECK(child); + set_focusable(false); + } + + virtual ~BorderView() {} + + virtual internal::RootView* GetContentsRootView() { + return static_cast<internal::RootView*>(widget_->GetRootView()); + } + + virtual FocusTraversable* GetFocusTraversable() { + return static_cast<internal::RootView*>(widget_->GetRootView()); + } + + virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child) { + NativeViewHost::ViewHierarchyChanged(is_add, parent, child); + + if (child == this && is_add) { + if (!widget_) { + widget_ = new Widget; + Widget::InitParams params(Widget::InitParams::TYPE_CONTROL); +#if defined(OS_WIN) || defined(USE_AURA) + params.parent = parent->GetWidget()->GetNativeView(); +#elif defined(TOOLKIT_USES_GTK) + params.parent = native_view(); +#else + NOTREACHED(); +#endif + widget_->Init(params); + widget_->SetFocusTraversableParentView(this); + widget_->SetContentsView(child_); + } + + // We have been added to a view hierarchy, attach the native view. + Attach(widget_->GetNativeView()); + // Also update the FocusTraversable parent so the focus traversal works. + static_cast<internal::RootView*>(widget_->GetRootView())-> + SetFocusTraversableParent(GetWidget()->GetFocusTraversable()); + } + } + + private: + View* child_; + Widget* widget_; + + DISALLOW_COPY_AND_ASSIGN(BorderView); +}; + +} // namespace + +class FocusTraversalTest : public FocusManagerTest { + public: + ~FocusTraversalTest(); + + virtual void InitContentView() OVERRIDE; + + protected: + FocusTraversalTest(); + + View* FindViewByID(int id) { + View* view = GetContentsView()->GetViewByID(id); + if (view) + return view; +#if !defined(USE_AURA) + if (style_tab_) + view = style_tab_->GetSelectedTab()->GetViewByID(id); +#endif + if (view) + return view; + view = search_border_view_->GetContentsRootView()->GetViewByID(id); + if (view) + return view; + return NULL; + } + + protected: +#if !defined(USE_AURA) + TabbedPane* style_tab_; +#endif + BorderView* search_border_view_; + DummyComboboxModel combobox_model_; + PaneView* left_container_; + PaneView* right_container_; + + DISALLOW_COPY_AND_ASSIGN(FocusTraversalTest); +}; + +FocusTraversalTest::FocusTraversalTest() + : +#if !defined(USE_AURA) + style_tab_(NULL), +#endif + search_border_view_(NULL) { +} + +FocusTraversalTest::~FocusTraversalTest() { +} + +void FocusTraversalTest::InitContentView() { + // Create a complicated view hierarchy with lots of control types for + // use by all of the focus traversal tests. + // + // Class name, ID, and asterisk next to focusable views: + // + // View + // Checkbox * kTopCheckBoxID + // PaneView kLeftContainerID + // Label kAppleLabelID + // Textfield * kAppleTextfieldID + // Label kOrangeLabelID + // Textfield * kOrangeTextfieldID + // Label kBananaLabelID + // Textfield * kBananaTextfieldID + // Label kKiwiLabelID + // Textfield * kKiwiTextfieldID + // NativeButton * kFruitButtonID + // Checkbox * kFruitCheckBoxID + // Combobox * kComboboxID + // PaneView kRightContainerID + // RadioButton * kAsparagusButtonID + // RadioButton * kBroccoliButtonID + // RadioButton * kCauliflowerButtonID + // View kInnerContainerID + // ScrollView kScrollViewID + // View + // Link * kRosettaLinkID + // Link * kStupeurEtTremblementLinkID + // Link * kDinerGameLinkID + // Link * kRidiculeLinkID + // Link * kClosetLinkID + // Link * kVisitingLinkID + // Link * kAmelieLinkID + // Link * kJoyeuxNoelLinkID + // Link * kCampingLinkID + // Link * kBriceDeNiceLinkID + // Link * kTaxiLinkID + // Link * kAsterixLinkID + // NativeButton * kOKButtonID + // NativeButton * kCancelButtonID + // NativeButton * kHelpButtonID + // #if !defined(USE_AURA) + // TabbedPane * kStyleContainerID + // View + // Checkbox * kBoldCheckBoxID + // Checkbox * kItalicCheckBoxID + // Checkbox * kUnderlinedCheckBoxID + // Link * kStyleHelpLinkID + // Textfield * kStyleTextEditID + // Other + // #endif + // BorderView kSearchContainerID + // View + // Textfield * kSearchTextfieldID + // NativeButton * kSearchButtonID + // Link * kHelpLinkID + // View * kThumbnailContainerID + // NativeButton * kThumbnailStarID + // NativeButton * kThumbnailSuperStarID + + GetContentsView()->set_background( + Background::CreateSolidBackground(SK_ColorWHITE)); + + Checkbox* cb = new Checkbox(ASCIIToUTF16("This is a checkbox")); + GetContentsView()->AddChildView(cb); + // In this fast paced world, who really has time for non hard-coded layout? + cb->SetBounds(10, 10, 200, 20); + cb->set_id(kTopCheckBoxID); + + left_container_ = new PaneView(); + left_container_->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK)); + left_container_->set_background( + Background::CreateSolidBackground(240, 240, 240)); + left_container_->set_id(kLeftContainerID); + GetContentsView()->AddChildView(left_container_); + left_container_->SetBounds(10, 35, 250, 200); + + int label_x = 5; + int label_width = 50; + int label_height = 15; + int text_field_width = 150; + int y = 10; + int gap_between_labels = 10; + + Label* label = new Label(ASCIIToUTF16("Apple:")); + label->set_id(kAppleLabelID); + left_container_->AddChildView(label); + label->SetBounds(label_x, y, label_width, label_height); + + Textfield* text_field = new Textfield(); + text_field->set_id(kAppleTextfieldID); + left_container_->AddChildView(text_field); + text_field->SetBounds(label_x + label_width + 5, y, + text_field_width, label_height); + + y += label_height + gap_between_labels; + + label = new Label(ASCIIToUTF16("Orange:")); + label->set_id(kOrangeLabelID); + left_container_->AddChildView(label); + label->SetBounds(label_x, y, label_width, label_height); + + text_field = new Textfield(); + text_field->set_id(kOrangeTextfieldID); + left_container_->AddChildView(text_field); + text_field->SetBounds(label_x + label_width + 5, y, + text_field_width, label_height); + + y += label_height + gap_between_labels; + + label = new Label(ASCIIToUTF16("Banana:")); + label->set_id(kBananaLabelID); + left_container_->AddChildView(label); + label->SetBounds(label_x, y, label_width, label_height); + + text_field = new Textfield(); + text_field->set_id(kBananaTextfieldID); + left_container_->AddChildView(text_field); + text_field->SetBounds(label_x + label_width + 5, y, + text_field_width, label_height); + + y += label_height + gap_between_labels; + + label = new Label(ASCIIToUTF16("Kiwi:")); + label->set_id(kKiwiLabelID); + left_container_->AddChildView(label); + label->SetBounds(label_x, y, label_width, label_height); + + text_field = new Textfield(); + text_field->set_id(kKiwiTextfieldID); + left_container_->AddChildView(text_field); + text_field->SetBounds(label_x + label_width + 5, y, + text_field_width, label_height); + + y += label_height + gap_between_labels; + + NativeTextButton* button = new NativeTextButton(NULL, + ASCIIToUTF16("Click me")); + button->SetBounds(label_x, y + 10, 80, 30); + button->set_id(kFruitButtonID); + left_container_->AddChildView(button); + y += 40; + + cb = new Checkbox(ASCIIToUTF16("This is another check box")); + cb->SetBounds(label_x + label_width + 5, y, 180, 20); + cb->set_id(kFruitCheckBoxID); + left_container_->AddChildView(cb); + y += 20; + + Combobox* combobox = new Combobox(&combobox_model_); + combobox->SetBounds(label_x + label_width + 5, y, 150, 30); + combobox->set_id(kComboboxID); + left_container_->AddChildView(combobox); + + right_container_ = new PaneView(); + right_container_->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK)); + right_container_->set_background( + Background::CreateSolidBackground(240, 240, 240)); + right_container_->set_id(kRightContainerID); + GetContentsView()->AddChildView(right_container_); + right_container_->SetBounds(270, 35, 300, 200); + + y = 10; + int radio_button_height = 18; + int gap_between_radio_buttons = 10; + RadioButton* radio_button = new RadioButton(ASCIIToUTF16("Asparagus"), 1); + radio_button->set_id(kAsparagusButtonID); + right_container_->AddChildView(radio_button); + radio_button->SetBounds(5, y, 70, radio_button_height); + radio_button->SetGroup(1); + y += radio_button_height + gap_between_radio_buttons; + radio_button = new RadioButton(ASCIIToUTF16("Broccoli"), 1); + radio_button->set_id(kBroccoliButtonID); + right_container_->AddChildView(radio_button); + radio_button->SetBounds(5, y, 70, radio_button_height); + radio_button->SetGroup(1); + RadioButton* radio_button_to_check = radio_button; + y += radio_button_height + gap_between_radio_buttons; + radio_button = new RadioButton(ASCIIToUTF16("Cauliflower"), 1); + radio_button->set_id(kCauliflowerButtonID); + right_container_->AddChildView(radio_button); + radio_button->SetBounds(5, y, 70, radio_button_height); + radio_button->SetGroup(1); + y += radio_button_height + gap_between_radio_buttons; + + View* inner_container = new View(); + inner_container->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK)); + inner_container->set_background( + Background::CreateSolidBackground(230, 230, 230)); + inner_container->set_id(kInnerContainerID); + right_container_->AddChildView(inner_container); + inner_container->SetBounds(100, 10, 150, 180); + + ScrollView* scroll_view = new ScrollView(); + scroll_view->set_id(kScrollViewID); + inner_container->AddChildView(scroll_view); + scroll_view->SetBounds(1, 1, 148, 178); + + View* scroll_content = new View(); + scroll_content->SetBounds(0, 0, 200, 200); + scroll_content->set_background( + Background::CreateSolidBackground(200, 200, 200)); + scroll_view->SetContents(scroll_content); + + static const char* const kTitles[] = { + "Rosetta", "Stupeur et tremblement", "The diner game", + "Ridicule", "Le placard", "Les Visiteurs", "Amelie", + "Joyeux Noel", "Camping", "Brice de Nice", + "Taxi", "Asterix" + }; + + static const int kIDs[] = { + kRosettaLinkID, kStupeurEtTremblementLinkID, kDinerGameLinkID, + kRidiculeLinkID, kClosetLinkID, kVisitingLinkID, kAmelieLinkID, + kJoyeuxNoelLinkID, kCampingLinkID, kBriceDeNiceLinkID, + kTaxiLinkID, kAsterixLinkID + }; + + DCHECK(arraysize(kTitles) == arraysize(kIDs)); + + y = 5; + for (size_t i = 0; i < arraysize(kTitles); ++i) { + Link* link = new Link(ASCIIToUTF16(kTitles[i])); + link->SetHorizontalAlignment(Label::ALIGN_LEFT); + link->set_id(kIDs[i]); + scroll_content->AddChildView(link); + link->SetBounds(5, y, 300, 15); + y += 15; + } + + y = 250; + int width = 60; + button = new NativeTextButton(NULL, ASCIIToUTF16("OK")); + button->set_id(kOKButtonID); + button->SetIsDefault(true); + + GetContentsView()->AddChildView(button); + button->SetBounds(150, y, width, 30); + + button = new NativeTextButton(NULL, ASCIIToUTF16("Cancel")); + button->set_id(kCancelButtonID); + GetContentsView()->AddChildView(button); + button->SetBounds(220, y, width, 30); + + button = new NativeTextButton(NULL, ASCIIToUTF16("Help")); + button->set_id(kHelpButtonID); + GetContentsView()->AddChildView(button); + button->SetBounds(290, y, width, 30); + + y += 40; + + View* contents = NULL; + Link* link = NULL; + +#if !defined(USE_AURA) + // Left bottom box with style checkboxes. + contents = new View(); + contents->set_background(Background::CreateSolidBackground(SK_ColorWHITE)); + cb = new Checkbox(ASCIIToUTF16("Bold")); + contents->AddChildView(cb); + cb->SetBounds(10, 10, 50, 20); + cb->set_id(kBoldCheckBoxID); + + cb = new Checkbox(ASCIIToUTF16("Italic")); + contents->AddChildView(cb); + cb->SetBounds(70, 10, 50, 20); + cb->set_id(kItalicCheckBoxID); + + cb = new Checkbox(ASCIIToUTF16("Underlined")); + contents->AddChildView(cb); + cb->SetBounds(130, 10, 70, 20); + cb->set_id(kUnderlinedCheckBoxID); + + link = new Link(ASCIIToUTF16("Help")); + contents->AddChildView(link); + link->SetBounds(10, 35, 70, 10); + link->set_id(kStyleHelpLinkID); + + text_field = new Textfield(); + contents->AddChildView(text_field); + text_field->SetBounds(10, 50, 100, 20); + text_field->set_id(kStyleTextEditID); + + style_tab_ = new TabbedPane(); + style_tab_->set_id(kStyleContainerID); + GetContentsView()->AddChildView(style_tab_); + style_tab_->SetBounds(10, y, 210, 100); + style_tab_->AddTab(ASCIIToUTF16("Style"), contents); + style_tab_->AddTab(ASCIIToUTF16("Other"), new View()); +#endif + + // Right bottom box with search. + contents = new View(); + contents->set_background(Background::CreateSolidBackground(SK_ColorWHITE)); + text_field = new Textfield(); + contents->AddChildView(text_field); + text_field->SetBounds(10, 10, 100, 20); + text_field->set_id(kSearchTextfieldID); + + button = new NativeTextButton(NULL, ASCIIToUTF16("Search")); + contents->AddChildView(button); + button->SetBounds(112, 5, 60, 30); + button->set_id(kSearchButtonID); + + link = new Link(ASCIIToUTF16("Help")); + link->SetHorizontalAlignment(Label::ALIGN_LEFT); + link->set_id(kHelpLinkID); + contents->AddChildView(link); + link->SetBounds(175, 10, 30, 20); + + search_border_view_ = new BorderView(contents); + search_border_view_->set_id(kSearchContainerID); + + GetContentsView()->AddChildView(search_border_view_); + search_border_view_->SetBounds(300, y, 240, 50); + + y += 60; + + contents = new View(); + contents->set_focusable(true); + contents->set_background(Background::CreateSolidBackground(SK_ColorBLUE)); + contents->set_id(kThumbnailContainerID); + button = new NativeTextButton(NULL, ASCIIToUTF16("Star")); + contents->AddChildView(button); + button->SetBounds(5, 5, 50, 30); + button->set_id(kThumbnailStarID); + button = new NativeTextButton(NULL, ASCIIToUTF16("SuperStar")); + contents->AddChildView(button); + button->SetBounds(60, 5, 100, 30); + button->set_id(kThumbnailSuperStarID); + + GetContentsView()->AddChildView(contents); + contents->SetBounds(250, y, 200, 50); + // We can only call RadioButton::SetChecked() on the radio-button is part of + // the view hierarchy. + radio_button_to_check->SetChecked(true); +} + +TEST_F(FocusTraversalTest, NormalTraversal) { + const int kTraversalIDs[] = { kTopCheckBoxID, kAppleTextfieldID, + kOrangeTextfieldID, kBananaTextfieldID, kKiwiTextfieldID, + kFruitButtonID, kFruitCheckBoxID, kComboboxID, kBroccoliButtonID, + kRosettaLinkID, kStupeurEtTremblementLinkID, + kDinerGameLinkID, kRidiculeLinkID, kClosetLinkID, kVisitingLinkID, + kAmelieLinkID, kJoyeuxNoelLinkID, kCampingLinkID, kBriceDeNiceLinkID, + kTaxiLinkID, kAsterixLinkID, kOKButtonID, kCancelButtonID, kHelpButtonID, +#if !defined(USE_AURA) + kStyleContainerID, kBoldCheckBoxID, kItalicCheckBoxID, + kUnderlinedCheckBoxID, kStyleHelpLinkID, kStyleTextEditID, +#endif + kSearchTextfieldID, kSearchButtonID, kHelpLinkID, + kThumbnailContainerID, kThumbnailStarID, kThumbnailSuperStarID }; + + // Uncomment the following line if you want to test manually the UI of this + // test. + // MessageLoopForUI::current()->RunWithDispatcher(new AcceleratorHandler()); + + // Let's traverse the whole focus hierarchy (several times, to make sure it + // loops OK). + GetFocusManager()->ClearFocus(); + for (int i = 0; i < 3; ++i) { + for (size_t j = 0; j < arraysize(kTraversalIDs); j++) { + GetFocusManager()->AdvanceFocus(false); + View* focused_view = GetFocusManager()->GetFocusedView(); + EXPECT_TRUE(focused_view != NULL); + if (focused_view) + EXPECT_EQ(kTraversalIDs[j], focused_view->id()); + } + } + + // Let's traverse in reverse order. + GetFocusManager()->ClearFocus(); + for (int i = 0; i < 3; ++i) { + for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) { + GetFocusManager()->AdvanceFocus(true); + View* focused_view = GetFocusManager()->GetFocusedView(); + EXPECT_TRUE(focused_view != NULL); + if (focused_view) + EXPECT_EQ(kTraversalIDs[j], focused_view->id()); + } + } +} + +TEST_F(FocusTraversalTest, TraversalWithNonEnabledViews) { + const int kDisabledIDs[] = { + kBananaTextfieldID, kFruitCheckBoxID, kComboboxID, kAsparagusButtonID, + kCauliflowerButtonID, kClosetLinkID, kVisitingLinkID, kBriceDeNiceLinkID, + kTaxiLinkID, kAsterixLinkID, kHelpButtonID, +#if !defined(USE_AURA) + kBoldCheckBoxID, +#endif + kSearchTextfieldID, kHelpLinkID }; + + const int kTraversalIDs[] = { kTopCheckBoxID, kAppleTextfieldID, + kOrangeTextfieldID, kKiwiTextfieldID, kFruitButtonID, kBroccoliButtonID, + kRosettaLinkID, kStupeurEtTremblementLinkID, kDinerGameLinkID, + kRidiculeLinkID, kAmelieLinkID, kJoyeuxNoelLinkID, kCampingLinkID, + kOKButtonID, kCancelButtonID, +#if !defined(USE_AURA) + kStyleContainerID, kItalicCheckBoxID, kUnderlinedCheckBoxID, + kStyleHelpLinkID, kStyleTextEditID, +#endif + kSearchButtonID, kThumbnailContainerID, kThumbnailStarID, + kThumbnailSuperStarID }; + + // Let's disable some views. + for (size_t i = 0; i < arraysize(kDisabledIDs); i++) { + View* v = FindViewByID(kDisabledIDs[i]); + ASSERT_TRUE(v != NULL); + v->SetEnabled(false); + } + + // Uncomment the following line if you want to test manually the UI of this + // test. + // MessageLoopForUI::current()->RunWithDispatcher(new AcceleratorHandler()); + + View* focused_view; + // Let's do one traversal (several times, to make sure it loops ok). + GetFocusManager()->ClearFocus(); + for (int i = 0; i < 3; ++i) { + for (size_t j = 0; j < arraysize(kTraversalIDs); j++) { + GetFocusManager()->AdvanceFocus(false); + focused_view = GetFocusManager()->GetFocusedView(); + EXPECT_TRUE(focused_view != NULL); + if (focused_view) + EXPECT_EQ(kTraversalIDs[j], focused_view->id()); + } + } + + // Same thing in reverse. + GetFocusManager()->ClearFocus(); + for (int i = 0; i < 3; ++i) { + for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) { + GetFocusManager()->AdvanceFocus(true); + focused_view = GetFocusManager()->GetFocusedView(); + EXPECT_TRUE(focused_view != NULL); + if (focused_view) + EXPECT_EQ(kTraversalIDs[j], focused_view->id()); + } + } +} + +TEST_F(FocusTraversalTest, TraversalWithInvisibleViews) { + const int kInvisibleIDs[] = { kTopCheckBoxID, kOKButtonID, + kThumbnailContainerID }; + + const int kTraversalIDs[] = { kAppleTextfieldID, kOrangeTextfieldID, + kBananaTextfieldID, kKiwiTextfieldID, kFruitButtonID, kFruitCheckBoxID, + kComboboxID, kBroccoliButtonID, kRosettaLinkID, + kStupeurEtTremblementLinkID, kDinerGameLinkID, kRidiculeLinkID, + kClosetLinkID, kVisitingLinkID, kAmelieLinkID, kJoyeuxNoelLinkID, + kCampingLinkID, kBriceDeNiceLinkID, kTaxiLinkID, kAsterixLinkID, + kCancelButtonID, kHelpButtonID, +#if !defined(USE_AURA) + kStyleContainerID, kBoldCheckBoxID, kItalicCheckBoxID, + kUnderlinedCheckBoxID, kStyleHelpLinkID, kStyleTextEditID, +#endif + kSearchTextfieldID, kSearchButtonID, kHelpLinkID }; + + + // Let's make some views invisible. + for (size_t i = 0; i < arraysize(kInvisibleIDs); i++) { + View* v = FindViewByID(kInvisibleIDs[i]); + ASSERT_TRUE(v != NULL); + v->SetVisible(false); + } + + // Uncomment the following line if you want to test manually the UI of this + // test. + // MessageLoopForUI::current()->RunWithDispatcher(new AcceleratorHandler()); + + View* focused_view; + // Let's do one traversal (several times, to make sure it loops ok). + GetFocusManager()->ClearFocus(); + for (int i = 0; i < 3; ++i) { + for (size_t j = 0; j < arraysize(kTraversalIDs); j++) { + GetFocusManager()->AdvanceFocus(false); + focused_view = GetFocusManager()->GetFocusedView(); + EXPECT_TRUE(focused_view != NULL); + if (focused_view) + EXPECT_EQ(kTraversalIDs[j], focused_view->id()); + } + } + + // Same thing in reverse. + GetFocusManager()->ClearFocus(); + for (int i = 0; i < 3; ++i) { + for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) { + GetFocusManager()->AdvanceFocus(true); + focused_view = GetFocusManager()->GetFocusedView(); + EXPECT_TRUE(focused_view != NULL); + if (focused_view) + EXPECT_EQ(kTraversalIDs[j], focused_view->id()); + } + } +} + +TEST_F(FocusTraversalTest, PaneTraversal) { + // Tests trapping the traversal within a pane - useful for full + // keyboard accessibility for toolbars. + + // First test the left container. + const int kLeftTraversalIDs[] = { + kAppleTextfieldID, + kOrangeTextfieldID, kBananaTextfieldID, kKiwiTextfieldID, + kFruitButtonID, kFruitCheckBoxID, kComboboxID }; + + FocusSearch focus_search_left(left_container_, true, false); + left_container_->EnablePaneFocus(&focus_search_left); + FindViewByID(kComboboxID)->RequestFocus(); + + // Traverse the focus hierarchy within the pane several times. + for (int i = 0; i < 3; ++i) { + for (size_t j = 0; j < arraysize(kLeftTraversalIDs); j++) { + GetFocusManager()->AdvanceFocus(false); + View* focused_view = GetFocusManager()->GetFocusedView(); + EXPECT_TRUE(focused_view != NULL); + if (focused_view) + EXPECT_EQ(kLeftTraversalIDs[j], focused_view->id()); + } + } + + // Traverse in reverse order. + FindViewByID(kAppleTextfieldID)->RequestFocus(); + for (int i = 0; i < 3; ++i) { + for (int j = arraysize(kLeftTraversalIDs) - 1; j >= 0; --j) { + GetFocusManager()->AdvanceFocus(true); + View* focused_view = GetFocusManager()->GetFocusedView(); + EXPECT_TRUE(focused_view != NULL); + if (focused_view) + EXPECT_EQ(kLeftTraversalIDs[j], focused_view->id()); + } + } + + // Now test the right container, but this time with accessibility mode. + // Make some links not focusable, but mark one of them as + // "accessibility focusable", so it should show up in the traversal. + const int kRightTraversalIDs[] = { + kBroccoliButtonID, kDinerGameLinkID, kRidiculeLinkID, + kClosetLinkID, kVisitingLinkID, kAmelieLinkID, kJoyeuxNoelLinkID, + kCampingLinkID, kBriceDeNiceLinkID, kTaxiLinkID, kAsterixLinkID }; + + FocusSearch focus_search_right(right_container_, true, true); + right_container_->EnablePaneFocus(&focus_search_right); + FindViewByID(kRosettaLinkID)->set_focusable(false); + FindViewByID(kStupeurEtTremblementLinkID)->set_focusable(false); + FindViewByID(kDinerGameLinkID)->set_accessibility_focusable(true); + FindViewByID(kDinerGameLinkID)->set_focusable(false); + FindViewByID(kAsterixLinkID)->RequestFocus(); + + // Traverse the focus hierarchy within the pane several times. + for (int i = 0; i < 3; ++i) { + for (size_t j = 0; j < arraysize(kRightTraversalIDs); j++) { + GetFocusManager()->AdvanceFocus(false); + View* focused_view = GetFocusManager()->GetFocusedView(); + EXPECT_TRUE(focused_view != NULL); + if (focused_view) + EXPECT_EQ(kRightTraversalIDs[j], focused_view->id()); + } + } + + // Traverse in reverse order. + FindViewByID(kBroccoliButtonID)->RequestFocus(); + for (int i = 0; i < 3; ++i) { + for (int j = arraysize(kRightTraversalIDs) - 1; j >= 0; --j) { + GetFocusManager()->AdvanceFocus(true); + View* focused_view = GetFocusManager()->GetFocusedView(); + EXPECT_TRUE(focused_view != NULL); + if (focused_view) + EXPECT_EQ(kRightTraversalIDs[j], focused_view->id()); + } + } +} + +} // namespace views diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index d8859c0..a49416c 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc @@ -510,8 +510,7 @@ void NativeWidgetAura::ClearNativeFocus() { } void NativeWidgetAura::FocusNativeView(gfx::NativeView native_view) { - // http://crbug.com/102572 - NOTIMPLEMENTED(); + window_->GetFocusManager()->SetFocusedWindow(native_view); } gfx::Rect NativeWidgetAura::GetWorkAreaBoundsInScreen() const { |