| // Copyright (c) 2012 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 <utility> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "ui/aura/client/focus_client.h" |
| #include "ui/aura/window.h" |
| #include "ui/base/accelerators/accelerator.h" |
| #include "ui/base/ime/dummy_text_input_client.h" |
| #include "ui/base/ime/text_input_focus_manager.h" |
| #include "ui/base/ui_base_switches.h" |
| #include "ui/events/keycodes/keyboard_codes.h" |
| #include "ui/views/accessible_pane_view.h" |
| #include "ui/views/controls/button/label_button.h" |
| #include "ui/views/focus/focus_manager_factory.h" |
| #include "ui/views/focus/focus_manager_test.h" |
| #include "ui/views/focus/widget_focus_manager.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace views { |
| |
| enum FocusTestEventType { |
| ON_FOCUS = 0, |
| ON_BLUR |
| }; |
| |
| struct FocusTestEvent { |
| FocusTestEvent(FocusTestEventType type, int view_id) |
| : type(type), |
| view_id(view_id) { |
| } |
| |
| FocusTestEventType type; |
| int view_id; |
| }; |
| |
| class SimpleTestView : public View { |
| public: |
| SimpleTestView(std::vector<FocusTestEvent>* event_list, int view_id) |
| : event_list_(event_list) { |
| SetFocusable(true); |
| set_id(view_id); |
| } |
| |
| virtual void OnFocus() OVERRIDE { |
| event_list_->push_back(FocusTestEvent(ON_FOCUS, id())); |
| } |
| |
| virtual void OnBlur() OVERRIDE { |
| event_list_->push_back(FocusTestEvent(ON_BLUR, id())); |
| } |
| |
| private: |
| std::vector<FocusTestEvent>* event_list_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SimpleTestView); |
| }; |
| |
| // Tests that the appropriate Focus related methods are called when a View |
| // gets/loses focus. |
| TEST_F(FocusManagerTest, ViewFocusCallbacks) { |
| std::vector<FocusTestEvent> event_list; |
| const int kView1ID = 1; |
| const int kView2ID = 2; |
| |
| SimpleTestView* view1 = new SimpleTestView(&event_list, kView1ID); |
| SimpleTestView* view2 = new SimpleTestView(&event_list, kView2ID); |
| GetContentsView()->AddChildView(view1); |
| GetContentsView()->AddChildView(view2); |
| |
| view1->RequestFocus(); |
| ASSERT_EQ(1, static_cast<int>(event_list.size())); |
| EXPECT_EQ(ON_FOCUS, event_list[0].type); |
| EXPECT_EQ(kView1ID, event_list[0].view_id); |
| |
| event_list.clear(); |
| view2->RequestFocus(); |
| ASSERT_EQ(2, static_cast<int>(event_list.size())); |
| EXPECT_EQ(ON_BLUR, event_list[0].type); |
| EXPECT_EQ(kView1ID, event_list[0].view_id); |
| EXPECT_EQ(ON_FOCUS, event_list[1].type); |
| EXPECT_EQ(kView2ID, event_list[1].view_id); |
| |
| event_list.clear(); |
| GetFocusManager()->ClearFocus(); |
| ASSERT_EQ(1, static_cast<int>(event_list.size())); |
| EXPECT_EQ(ON_BLUR, event_list[0].type); |
| EXPECT_EQ(kView2ID, event_list[0].view_id); |
| } |
| |
| TEST_F(FocusManagerTest, FocusChangeListener) { |
| View* view1 = new View(); |
| view1->SetFocusable(true); |
| View* view2 = new View(); |
| view2->SetFocusable(true); |
| GetContentsView()->AddChildView(view1); |
| GetContentsView()->AddChildView(view2); |
| |
| TestFocusChangeListener listener; |
| AddFocusChangeListener(&listener); |
| |
| // Required for VS2010: http://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair |
| views::View* null_view = NULL; |
| |
| view1->RequestFocus(); |
| ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); |
| EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view1)); |
| listener.ClearFocusChanges(); |
| |
| view2->RequestFocus(); |
| ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); |
| EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(view1, view2)); |
| listener.ClearFocusChanges(); |
| |
| GetFocusManager()->ClearFocus(); |
| ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size())); |
| EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(view2, null_view)); |
| } |
| |
| TEST_F(FocusManagerTest, WidgetFocusChangeListener) { |
| TestWidgetFocusChangeListener widget_listener; |
| AddWidgetFocusChangeListener(&widget_listener); |
| |
| Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); |
| params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| params.bounds = gfx::Rect(10, 10, 100, 100); |
| params.parent = GetWidget()->GetNativeView(); |
| |
| scoped_ptr<Widget> widget1(new Widget); |
| widget1->Init(params); |
| widget1->Show(); |
| |
| scoped_ptr<Widget> widget2(new Widget); |
| widget2->Init(params); |
| widget2->Show(); |
| |
| widget_listener.ClearFocusChanges(); |
| gfx::NativeView native_view1 = widget1->GetNativeView(); |
| aura::client::GetFocusClient(native_view1)->FocusWindow(native_view1); |
| ASSERT_EQ(2, static_cast<int>(widget_listener.focus_changes().size())); |
| EXPECT_EQ(native_view1, widget_listener.focus_changes()[0].second); |
| EXPECT_EQ(native_view1, widget_listener.focus_changes()[1].second); |
| |
| widget_listener.ClearFocusChanges(); |
| gfx::NativeView native_view2 = widget2->GetNativeView(); |
| aura::client::GetFocusClient(native_view2)->FocusWindow(native_view2); |
| ASSERT_EQ(2, static_cast<int>(widget_listener.focus_changes().size())); |
| EXPECT_EQ(NativeViewPair(native_view1, native_view2), |
| widget_listener.focus_changes()[0]); |
| EXPECT_EQ(NativeViewPair(native_view1, native_view2), |
| widget_listener.focus_changes()[1]); |
| } |
| |
| // Counts accelerator calls. |
| class TestAcceleratorTarget : public ui::AcceleratorTarget { |
| public: |
| explicit TestAcceleratorTarget(bool process_accelerator) |
| : accelerator_count_(0), |
| process_accelerator_(process_accelerator), |
| can_handle_accelerators_(true) {} |
| |
| virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE { |
| ++accelerator_count_; |
| return process_accelerator_; |
| } |
| |
| virtual bool CanHandleAccelerators() const OVERRIDE { |
| return can_handle_accelerators_; |
| } |
| |
| int accelerator_count() const { return accelerator_count_; } |
| |
| void set_can_handle_accelerators(bool can_handle_accelerators) { |
| can_handle_accelerators_ = can_handle_accelerators; |
| } |
| |
| private: |
| int accelerator_count_; // number of times that the accelerator is activated |
| bool process_accelerator_; // return value of AcceleratorPressed |
| bool can_handle_accelerators_; // return value of CanHandleAccelerators |
| |
| DISALLOW_COPY_AND_ASSIGN(TestAcceleratorTarget); |
| }; |
| |
| TEST_F(FocusManagerTest, CallsNormalAcceleratorTarget) { |
| FocusManager* focus_manager = GetFocusManager(); |
| ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE); |
| ui::Accelerator escape_accelerator(ui::VKEY_ESCAPE, ui::EF_NONE); |
| |
| TestAcceleratorTarget return_target(true); |
| TestAcceleratorTarget escape_target(true); |
| EXPECT_EQ(return_target.accelerator_count(), 0); |
| EXPECT_EQ(escape_target.accelerator_count(), 0); |
| EXPECT_EQ(NULL, |
| focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); |
| EXPECT_EQ(NULL, |
| focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); |
| |
| // Register targets. |
| focus_manager->RegisterAccelerator(return_accelerator, |
| ui::AcceleratorManager::kNormalPriority, |
| &return_target); |
| focus_manager->RegisterAccelerator(escape_accelerator, |
| ui::AcceleratorManager::kNormalPriority, |
| &escape_target); |
| |
| // Checks if the correct target is registered. |
| EXPECT_EQ(&return_target, |
| focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); |
| EXPECT_EQ(&escape_target, |
| focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); |
| |
| // Hitting the return key. |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); |
| EXPECT_EQ(return_target.accelerator_count(), 1); |
| EXPECT_EQ(escape_target.accelerator_count(), 0); |
| |
| // Hitting the escape key. |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator)); |
| EXPECT_EQ(return_target.accelerator_count(), 1); |
| EXPECT_EQ(escape_target.accelerator_count(), 1); |
| |
| // Register another target for the return key. |
| TestAcceleratorTarget return_target2(true); |
| EXPECT_EQ(return_target2.accelerator_count(), 0); |
| focus_manager->RegisterAccelerator(return_accelerator, |
| ui::AcceleratorManager::kNormalPriority, |
| &return_target2); |
| EXPECT_EQ(&return_target2, |
| focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); |
| |
| // Hitting the return key; return_target2 has the priority. |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); |
| EXPECT_EQ(return_target.accelerator_count(), 1); |
| EXPECT_EQ(return_target2.accelerator_count(), 1); |
| |
| // Register a target that does not process the accelerator event. |
| TestAcceleratorTarget return_target3(false); |
| EXPECT_EQ(return_target3.accelerator_count(), 0); |
| focus_manager->RegisterAccelerator(return_accelerator, |
| ui::AcceleratorManager::kNormalPriority, |
| &return_target3); |
| EXPECT_EQ(&return_target3, |
| focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); |
| |
| // Hitting the return key. |
| // Since the event handler of return_target3 returns false, return_target2 |
| // should be called too. |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); |
| EXPECT_EQ(return_target.accelerator_count(), 1); |
| EXPECT_EQ(return_target2.accelerator_count(), 2); |
| EXPECT_EQ(return_target3.accelerator_count(), 1); |
| |
| // Unregister return_target2. |
| focus_manager->UnregisterAccelerator(return_accelerator, &return_target2); |
| EXPECT_EQ(&return_target3, |
| focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); |
| |
| // Hitting the return key. return_target3 and return_target should be called. |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); |
| EXPECT_EQ(return_target.accelerator_count(), 2); |
| EXPECT_EQ(return_target2.accelerator_count(), 2); |
| EXPECT_EQ(return_target3.accelerator_count(), 2); |
| |
| // Unregister targets. |
| focus_manager->UnregisterAccelerator(return_accelerator, &return_target); |
| focus_manager->UnregisterAccelerator(return_accelerator, &return_target3); |
| focus_manager->UnregisterAccelerator(escape_accelerator, &escape_target); |
| |
| // Now there is no target registered. |
| EXPECT_EQ(NULL, |
| focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); |
| EXPECT_EQ(NULL, |
| focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); |
| |
| // Hitting the return key and the escape key. Nothing should happen. |
| EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); |
| EXPECT_EQ(return_target.accelerator_count(), 2); |
| EXPECT_EQ(return_target2.accelerator_count(), 2); |
| EXPECT_EQ(return_target3.accelerator_count(), 2); |
| EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator)); |
| EXPECT_EQ(escape_target.accelerator_count(), 1); |
| } |
| |
| TEST_F(FocusManagerTest, HighPriorityHandlers) { |
| FocusManager* focus_manager = GetFocusManager(); |
| ui::Accelerator escape_accelerator(ui::VKEY_ESCAPE, ui::EF_NONE); |
| |
| TestAcceleratorTarget escape_target_high(true); |
| TestAcceleratorTarget escape_target_normal(true); |
| EXPECT_EQ(escape_target_high.accelerator_count(), 0); |
| EXPECT_EQ(escape_target_normal.accelerator_count(), 0); |
| EXPECT_EQ(NULL, |
| focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); |
| EXPECT_FALSE(focus_manager->HasPriorityHandler(escape_accelerator)); |
| |
| // Register high priority target. |
| focus_manager->RegisterAccelerator(escape_accelerator, |
| ui::AcceleratorManager::kHighPriority, |
| &escape_target_high); |
| EXPECT_EQ(&escape_target_high, |
| focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); |
| EXPECT_TRUE(focus_manager->HasPriorityHandler(escape_accelerator)); |
| |
| // Hit the escape key. |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator)); |
| EXPECT_EQ(escape_target_high.accelerator_count(), 1); |
| EXPECT_EQ(escape_target_normal.accelerator_count(), 0); |
| |
| // Add a normal priority target and make sure it doesn't see the key. |
| focus_manager->RegisterAccelerator(escape_accelerator, |
| ui::AcceleratorManager::kNormalPriority, |
| &escape_target_normal); |
| |
| // Checks if the correct target is registered (same as before, the high |
| // priority one). |
| EXPECT_EQ(&escape_target_high, |
| focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); |
| EXPECT_TRUE(focus_manager->HasPriorityHandler(escape_accelerator)); |
| |
| // Hit the escape key. |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator)); |
| EXPECT_EQ(escape_target_high.accelerator_count(), 2); |
| EXPECT_EQ(escape_target_normal.accelerator_count(), 0); |
| |
| // Unregister the high priority accelerator. |
| focus_manager->UnregisterAccelerator(escape_accelerator, &escape_target_high); |
| EXPECT_EQ(&escape_target_normal, |
| focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); |
| EXPECT_FALSE(focus_manager->HasPriorityHandler(escape_accelerator)); |
| |
| // Hit the escape key. |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator)); |
| EXPECT_EQ(escape_target_high.accelerator_count(), 2); |
| EXPECT_EQ(escape_target_normal.accelerator_count(), 1); |
| |
| // Add the high priority target back and make sure it starts seeing the key. |
| focus_manager->RegisterAccelerator(escape_accelerator, |
| ui::AcceleratorManager::kHighPriority, |
| &escape_target_high); |
| EXPECT_EQ(&escape_target_high, |
| focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); |
| EXPECT_TRUE(focus_manager->HasPriorityHandler(escape_accelerator)); |
| |
| // Hit the escape key. |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator)); |
| EXPECT_EQ(escape_target_high.accelerator_count(), 3); |
| EXPECT_EQ(escape_target_normal.accelerator_count(), 1); |
| |
| // Unregister the normal priority accelerator. |
| focus_manager->UnregisterAccelerator( |
| escape_accelerator, &escape_target_normal); |
| EXPECT_EQ(&escape_target_high, |
| focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); |
| EXPECT_TRUE(focus_manager->HasPriorityHandler(escape_accelerator)); |
| |
| // Hit the escape key. |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator)); |
| EXPECT_EQ(escape_target_high.accelerator_count(), 4); |
| EXPECT_EQ(escape_target_normal.accelerator_count(), 1); |
| |
| // Unregister the high priority accelerator. |
| focus_manager->UnregisterAccelerator(escape_accelerator, &escape_target_high); |
| EXPECT_EQ(NULL, |
| focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); |
| EXPECT_FALSE(focus_manager->HasPriorityHandler(escape_accelerator)); |
| |
| // Hit the escape key (no change, no targets registered). |
| EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator)); |
| EXPECT_EQ(escape_target_high.accelerator_count(), 4); |
| EXPECT_EQ(escape_target_normal.accelerator_count(), 1); |
| } |
| |
| TEST_F(FocusManagerTest, CallsEnabledAcceleratorTargetsOnly) { |
| FocusManager* focus_manager = GetFocusManager(); |
| ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE); |
| |
| TestAcceleratorTarget return_target1(true); |
| TestAcceleratorTarget return_target2(true); |
| |
| focus_manager->RegisterAccelerator(return_accelerator, |
| ui::AcceleratorManager::kNormalPriority, |
| &return_target1); |
| focus_manager->RegisterAccelerator(return_accelerator, |
| ui::AcceleratorManager::kNormalPriority, |
| &return_target2); |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); |
| EXPECT_EQ(0, return_target1.accelerator_count()); |
| EXPECT_EQ(1, return_target2.accelerator_count()); |
| |
| // If CanHandleAccelerators() return false, FocusManager shouldn't call |
| // AcceleratorPressed(). |
| return_target2.set_can_handle_accelerators(false); |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); |
| EXPECT_EQ(1, return_target1.accelerator_count()); |
| EXPECT_EQ(1, return_target2.accelerator_count()); |
| |
| // If no accelerator targets are enabled, ProcessAccelerator() should fail. |
| return_target1.set_can_handle_accelerators(false); |
| EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); |
| EXPECT_EQ(1, return_target1.accelerator_count()); |
| EXPECT_EQ(1, return_target2.accelerator_count()); |
| |
| // Enabling the target again causes the accelerators to be processed again. |
| return_target1.set_can_handle_accelerators(true); |
| return_target2.set_can_handle_accelerators(true); |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); |
| EXPECT_EQ(1, return_target1.accelerator_count()); |
| EXPECT_EQ(2, return_target2.accelerator_count()); |
| } |
| |
| // Unregisters itself when its accelerator is invoked. |
| class SelfUnregisteringAcceleratorTarget : public ui::AcceleratorTarget { |
| public: |
| SelfUnregisteringAcceleratorTarget(ui::Accelerator accelerator, |
| FocusManager* focus_manager) |
| : accelerator_(accelerator), |
| focus_manager_(focus_manager), |
| accelerator_count_(0) { |
| } |
| |
| virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE { |
| ++accelerator_count_; |
| focus_manager_->UnregisterAccelerator(accelerator, this); |
| return true; |
| } |
| |
| virtual bool CanHandleAccelerators() const OVERRIDE { |
| return true; |
| } |
| |
| int accelerator_count() const { return accelerator_count_; } |
| |
| private: |
| ui::Accelerator accelerator_; |
| FocusManager* focus_manager_; |
| int accelerator_count_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SelfUnregisteringAcceleratorTarget); |
| }; |
| |
| TEST_F(FocusManagerTest, CallsSelfDeletingAcceleratorTarget) { |
| FocusManager* focus_manager = GetFocusManager(); |
| ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE); |
| SelfUnregisteringAcceleratorTarget target(return_accelerator, focus_manager); |
| EXPECT_EQ(target.accelerator_count(), 0); |
| EXPECT_EQ(NULL, |
| focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); |
| |
| // Register the target. |
| focus_manager->RegisterAccelerator(return_accelerator, |
| ui::AcceleratorManager::kNormalPriority, |
| &target); |
| EXPECT_EQ(&target, |
| focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); |
| |
| // Hitting the return key. The target will be unregistered. |
| EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); |
| EXPECT_EQ(target.accelerator_count(), 1); |
| EXPECT_EQ(NULL, |
| focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); |
| |
| // Hitting the return key again; nothing should happen. |
| EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); |
| EXPECT_EQ(target.accelerator_count(), 1); |
| } |
| |
| class FocusManagerDtorTest : public FocusManagerTest { |
| protected: |
| typedef std::vector<std::string> DtorTrackVector; |
| |
| class FocusManagerDtorTracked : public FocusManager { |
| public: |
| FocusManagerDtorTracked(Widget* widget, DtorTrackVector* dtor_tracker) |
| : FocusManager(widget, NULL /* delegate */), |
| dtor_tracker_(dtor_tracker) { |
| } |
| |
| virtual ~FocusManagerDtorTracked() { |
| dtor_tracker_->push_back("FocusManagerDtorTracked"); |
| } |
| |
| DtorTrackVector* dtor_tracker_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(FocusManagerDtorTracked); |
| }; |
| |
| class TestFocusManagerFactory : public FocusManagerFactory { |
| public: |
| explicit TestFocusManagerFactory(DtorTrackVector* dtor_tracker) |
| : dtor_tracker_(dtor_tracker) { |
| } |
| |
| virtual FocusManager* CreateFocusManager(Widget* widget, |
| bool desktop_widget) OVERRIDE { |
| return new FocusManagerDtorTracked(widget, dtor_tracker_); |
| } |
| |
| private: |
| DtorTrackVector* dtor_tracker_; |
| DISALLOW_COPY_AND_ASSIGN(TestFocusManagerFactory); |
| }; |
| |
| class LabelButtonDtorTracked : public LabelButton { |
| public: |
| LabelButtonDtorTracked(const base::string16& text, |
| DtorTrackVector* dtor_tracker) |
| : LabelButton(NULL, text), |
| dtor_tracker_(dtor_tracker) { |
| SetStyle(STYLE_BUTTON); |
| }; |
| virtual ~LabelButtonDtorTracked() { |
| dtor_tracker_->push_back("LabelButtonDtorTracked"); |
| } |
| |
| DtorTrackVector* dtor_tracker_; |
| }; |
| |
| class WindowDtorTracked : public Widget { |
| public: |
| explicit WindowDtorTracked(DtorTrackVector* dtor_tracker) |
| : dtor_tracker_(dtor_tracker) { |
| } |
| |
| virtual ~WindowDtorTracked() { |
| dtor_tracker_->push_back("WindowDtorTracked"); |
| } |
| |
| DtorTrackVector* dtor_tracker_; |
| }; |
| |
| virtual void SetUp() { |
| ViewsTestBase::SetUp(); |
| FocusManagerFactory::Install(new TestFocusManagerFactory(&dtor_tracker_)); |
| // Create WindowDtorTracked that uses FocusManagerDtorTracked. |
| Widget* widget = new WindowDtorTracked(&dtor_tracker_); |
| Widget::InitParams params; |
| params.delegate = this; |
| params.bounds = gfx::Rect(0, 0, 100, 100); |
| widget->Init(params); |
| |
| tracked_focus_manager_ = |
| static_cast<FocusManagerDtorTracked*>(GetFocusManager()); |
| widget->Show(); |
| } |
| |
| virtual void TearDown() { |
| FocusManagerFactory::Install(NULL); |
| ViewsTestBase::TearDown(); |
| } |
| |
| FocusManager* tracked_focus_manager_; |
| DtorTrackVector dtor_tracker_; |
| }; |
| |
| namespace { |
| |
| class FocusInAboutToRequestFocusFromTabTraversalView : public View { |
| public: |
| FocusInAboutToRequestFocusFromTabTraversalView() : view_to_focus_(NULL) {} |
| |
| void set_view_to_focus(View* view) { view_to_focus_ = view; } |
| |
| virtual void AboutToRequestFocusFromTabTraversal(bool reverse) OVERRIDE { |
| view_to_focus_->RequestFocus(); |
| } |
| |
| private: |
| views::View* view_to_focus_; |
| |
| DISALLOW_COPY_AND_ASSIGN(FocusInAboutToRequestFocusFromTabTraversalView); |
| }; |
| } // namespace |
| |
| // Verifies a focus change done during a call to |
| // AboutToRequestFocusFromTabTraversal() is honored. |
| TEST_F(FocusManagerTest, FocusInAboutToRequestFocusFromTabTraversal) { |
| // Create 3 views focuses the 3 and advances to the second. The 2nd views |
| // implementation of AboutToRequestFocusFromTabTraversal() focuses the first. |
| views::View* v1 = new View; |
| v1->SetFocusable(true); |
| GetContentsView()->AddChildView(v1); |
| |
| FocusInAboutToRequestFocusFromTabTraversalView* v2 = |
| new FocusInAboutToRequestFocusFromTabTraversalView; |
| v2->SetFocusable(true); |
| v2->set_view_to_focus(v1); |
| GetContentsView()->AddChildView(v2); |
| |
| views::View* v3 = new View; |
| v3->SetFocusable(true); |
| GetContentsView()->AddChildView(v3); |
| |
| v3->RequestFocus(); |
| GetWidget()->GetFocusManager()->AdvanceFocus(true); |
| EXPECT_TRUE(v1->HasFocus()); |
| } |
| |
| TEST_F(FocusManagerTest, RotatePaneFocus) { |
| views::AccessiblePaneView* pane1 = new AccessiblePaneView(); |
| GetContentsView()->AddChildView(pane1); |
| |
| views::View* v1 = new View; |
| v1->SetFocusable(true); |
| pane1->AddChildView(v1); |
| |
| views::View* v2 = new View; |
| v2->SetFocusable(true); |
| pane1->AddChildView(v2); |
| |
| views::AccessiblePaneView* pane2 = new AccessiblePaneView(); |
| GetContentsView()->AddChildView(pane2); |
| |
| views::View* v3 = new View; |
| v3->SetFocusable(true); |
| pane2->AddChildView(v3); |
| |
| views::View* v4 = new View; |
| v4->SetFocusable(true); |
| pane2->AddChildView(v4); |
| |
| std::vector<views::View*> panes; |
| panes.push_back(pane1); |
| panes.push_back(pane2); |
| SetAccessiblePanes(panes); |
| |
| FocusManager* focus_manager = GetWidget()->GetFocusManager(); |
| |
| // Advance forwards. Focus should stay trapped within each pane. |
| EXPECT_TRUE(focus_manager->RotatePaneFocus( |
| FocusManager::kForward, FocusManager::kWrap)); |
| EXPECT_EQ(v1, focus_manager->GetFocusedView()); |
| focus_manager->AdvanceFocus(false); |
| EXPECT_EQ(v2, focus_manager->GetFocusedView()); |
| focus_manager->AdvanceFocus(false); |
| EXPECT_EQ(v1, focus_manager->GetFocusedView()); |
| |
| EXPECT_TRUE(focus_manager->RotatePaneFocus( |
| FocusManager::kForward, FocusManager::kWrap)); |
| EXPECT_EQ(v3, focus_manager->GetFocusedView()); |
| focus_manager->AdvanceFocus(false); |
| EXPECT_EQ(v4, focus_manager->GetFocusedView()); |
| focus_manager->AdvanceFocus(false); |
| EXPECT_EQ(v3, focus_manager->GetFocusedView()); |
| |
| EXPECT_TRUE(focus_manager->RotatePaneFocus( |
| FocusManager::kForward, FocusManager::kWrap)); |
| EXPECT_EQ(v1, focus_manager->GetFocusedView()); |
| |
| // Advance backwards. |
| EXPECT_TRUE(focus_manager->RotatePaneFocus( |
| FocusManager::kBackward, FocusManager::kWrap)); |
| EXPECT_EQ(v3, focus_manager->GetFocusedView()); |
| |
| EXPECT_TRUE(focus_manager->RotatePaneFocus( |
| FocusManager::kBackward, FocusManager::kWrap)); |
| EXPECT_EQ(v1, focus_manager->GetFocusedView()); |
| |
| // Advance without wrap. When it gets to the end of the list of |
| // panes, RotatePaneFocus should return false but the current |
| // focused view shouldn't change. |
| EXPECT_TRUE(focus_manager->RotatePaneFocus( |
| FocusManager::kForward, FocusManager::kNoWrap)); |
| EXPECT_EQ(v3, focus_manager->GetFocusedView()); |
| |
| EXPECT_FALSE(focus_manager->RotatePaneFocus( |
| FocusManager::kForward, FocusManager::kNoWrap)); |
| EXPECT_EQ(v3, focus_manager->GetFocusedView()); |
| } |
| |
| // Verifies the stored focus view tracks the focused view. |
| TEST_F(FocusManagerTest, ImplicitlyStoresFocus) { |
| views::View* v1 = new View; |
| v1->SetFocusable(true); |
| GetContentsView()->AddChildView(v1); |
| |
| views::View* v2 = new View; |
| v2->SetFocusable(true); |
| GetContentsView()->AddChildView(v2); |
| |
| // Verify a focus request on |v1| implicitly updates the stored focus view. |
| v1->RequestFocus(); |
| EXPECT_TRUE(v1->HasFocus()); |
| EXPECT_EQ(v1, GetWidget()->GetFocusManager()->GetStoredFocusView()); |
| |
| // Verify a focus request on |v2| implicitly updates the stored focus view. |
| v2->RequestFocus(); |
| EXPECT_TRUE(v2->HasFocus()); |
| EXPECT_EQ(v2, GetWidget()->GetFocusManager()->GetStoredFocusView()); |
| } |
| |
| namespace { |
| |
| class FocusManagerArrowKeyTraversalTest : public FocusManagerTest { |
| public: |
| FocusManagerArrowKeyTraversalTest() |
| : previous_arrow_key_traversal_enabled_(false) { |
| } |
| virtual ~FocusManagerArrowKeyTraversalTest() {} |
| |
| // FocusManagerTest overrides: |
| virtual void SetUp() OVERRIDE { |
| FocusManagerTest::SetUp(); |
| |
| previous_arrow_key_traversal_enabled_ = |
| FocusManager::arrow_key_traversal_enabled(); |
| } |
| virtual void TearDown() OVERRIDE { |
| FocusManager::set_arrow_key_traversal_enabled( |
| previous_arrow_key_traversal_enabled_); |
| FocusManagerTest::TearDown(); |
| } |
| |
| private: |
| bool previous_arrow_key_traversal_enabled_; |
| |
| DISALLOW_COPY_AND_ASSIGN(FocusManagerArrowKeyTraversalTest); |
| }; |
| |
| } // namespace |
| |
| TEST_F(FocusManagerArrowKeyTraversalTest, ArrowKeyTraversal) { |
| FocusManager* focus_manager = GetFocusManager(); |
| const ui::KeyEvent left_key( |
| ui::ET_KEY_PRESSED, ui::VKEY_LEFT, ui::EF_NONE, false); |
| const ui::KeyEvent right_key( |
| ui::ET_KEY_PRESSED, ui::VKEY_RIGHT, ui::EF_NONE, false); |
| const ui::KeyEvent up_key( |
| ui::ET_KEY_PRESSED, ui::VKEY_UP, ui::EF_NONE, false); |
| const ui::KeyEvent down_key( |
| ui::ET_KEY_PRESSED, ui::VKEY_DOWN, ui::EF_NONE, false); |
| |
| std::vector<views::View*> v; |
| for (size_t i = 0; i < 2; ++i) { |
| views::View* view = new View; |
| view->SetFocusable(true); |
| GetContentsView()->AddChildView(view); |
| v.push_back(view); |
| } |
| |
| // Arrow key traversal is off and arrow key does not change focus. |
| FocusManager::set_arrow_key_traversal_enabled(false); |
| v[0]->RequestFocus(); |
| focus_manager->OnKeyEvent(right_key); |
| EXPECT_EQ(v[0], focus_manager->GetFocusedView()); |
| focus_manager->OnKeyEvent(left_key); |
| EXPECT_EQ(v[0], focus_manager->GetFocusedView()); |
| focus_manager->OnKeyEvent(down_key); |
| EXPECT_EQ(v[0], focus_manager->GetFocusedView()); |
| focus_manager->OnKeyEvent(up_key); |
| EXPECT_EQ(v[0], focus_manager->GetFocusedView()); |
| |
| // Turn on arrow key traversal. |
| FocusManager::set_arrow_key_traversal_enabled(true); |
| v[0]->RequestFocus(); |
| focus_manager->OnKeyEvent(right_key); |
| EXPECT_EQ(v[1], focus_manager->GetFocusedView()); |
| focus_manager->OnKeyEvent(left_key); |
| EXPECT_EQ(v[0], focus_manager->GetFocusedView()); |
| focus_manager->OnKeyEvent(down_key); |
| EXPECT_EQ(v[1], focus_manager->GetFocusedView()); |
| focus_manager->OnKeyEvent(up_key); |
| EXPECT_EQ(v[0], focus_manager->GetFocusedView()); |
| } |
| |
| TEST_F(FocusManagerTest, StoreFocusedView) { |
| View view; |
| GetFocusManager()->SetFocusedView(&view); |
| GetFocusManager()->StoreFocusedView(false); |
| EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView()); |
| EXPECT_TRUE(GetFocusManager()->RestoreFocusedView()); |
| EXPECT_EQ(&view, GetFocusManager()->GetStoredFocusView()); |
| |
| // Repeat with |true|. |
| GetFocusManager()->SetFocusedView(&view); |
| GetFocusManager()->StoreFocusedView(true); |
| EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView()); |
| EXPECT_TRUE(GetFocusManager()->RestoreFocusedView()); |
| EXPECT_EQ(&view, GetFocusManager()->GetStoredFocusView()); |
| } |
| |
| class TextInputTestView : public View { |
| public: |
| TextInputTestView() {} |
| |
| virtual ui::TextInputClient* GetTextInputClient() OVERRIDE { |
| return &text_input_client_; |
| } |
| |
| private: |
| ui::DummyTextInputClient text_input_client_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TextInputTestView); |
| }; |
| |
| TEST_F(FocusManagerTest, TextInputClient) { |
| base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
| cmd_line->AppendSwitch(switches::kEnableTextInputFocusManager); |
| |
| View* view = new TextInputTestView; |
| ui::TextInputClient* text_input_client = view->GetTextInputClient(); |
| view->SetFocusable(true); |
| GetContentsView()->AddChildView(view); |
| ui::TextInputFocusManager* text_input_focus_manager = |
| ui::TextInputFocusManager::GetInstance(); |
| |
| GetFocusManager()->SetFocusedView(view); |
| EXPECT_EQ(view, GetFocusManager()->GetFocusedView()); |
| EXPECT_EQ(text_input_client, |
| text_input_focus_manager->GetFocusedTextInputClient()); |
| GetFocusManager()->StoreFocusedView(false); |
| EXPECT_TRUE(GetFocusManager()->RestoreFocusedView()); |
| EXPECT_EQ(text_input_client, |
| text_input_focus_manager->GetFocusedTextInputClient()); |
| |
| // Repeat with |true|. |
| GetFocusManager()->SetFocusedView(view); |
| EXPECT_EQ(view, GetFocusManager()->GetFocusedView()); |
| EXPECT_EQ(text_input_client, |
| text_input_focus_manager->GetFocusedTextInputClient()); |
| GetFocusManager()->StoreFocusedView(true); |
| EXPECT_TRUE(GetFocusManager()->RestoreFocusedView()); |
| EXPECT_EQ(text_input_client, |
| text_input_focus_manager->GetFocusedTextInputClient()); |
| |
| // Focus the view twice in a row. |
| GetFocusManager()->SetFocusedView(view); |
| EXPECT_EQ(text_input_client, |
| text_input_focus_manager->GetFocusedTextInputClient()); |
| ui::TextInputFocusManager::GetInstance()->FocusTextInputClient(NULL); |
| GetFocusManager()->SetFocusedView(view); |
| EXPECT_EQ(text_input_client, |
| text_input_focus_manager->GetFocusedTextInputClient()); |
| } |
| |
| namespace { |
| |
| // Trivial WidgetDelegate implementation that allows setting return value of |
| // ShouldAdvanceFocusToTopLevelWidget(). |
| class AdvanceFocusWidgetDelegate : public WidgetDelegate { |
| public: |
| explicit AdvanceFocusWidgetDelegate(Widget* widget) |
| : widget_(widget), |
| should_advance_focus_to_parent_(false) {} |
| virtual ~AdvanceFocusWidgetDelegate() {} |
| |
| void set_should_advance_focus_to_parent(bool value) { |
| should_advance_focus_to_parent_ = value; |
| } |
| |
| // WidgetDelegate overrides: |
| virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE { |
| return should_advance_focus_to_parent_; |
| } |
| virtual Widget* GetWidget() OVERRIDE { return widget_; } |
| virtual const Widget* GetWidget() const OVERRIDE { return widget_; } |
| |
| private: |
| Widget* widget_; |
| bool should_advance_focus_to_parent_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AdvanceFocusWidgetDelegate); |
| }; |
| |
| } // namespace |
| |
| // Verifies focus wrapping happens in the same widget. |
| TEST_F(FocusManagerTest, AdvanceFocusStaysInWidget) { |
| // Add |widget_view| as a child of the Widget. |
| View* widget_view = new View; |
| widget_view->SetFocusable(true); |
| widget_view->SetBounds(20, 0, 20, 20); |
| GetContentsView()->AddChildView(widget_view); |
| |
| // Create a widget with two views, focus the second. |
| scoped_ptr<AdvanceFocusWidgetDelegate> delegate; |
| Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); |
| params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| params.child = true; |
| params.bounds = gfx::Rect(10, 10, 100, 100); |
| params.parent = GetWidget()->GetNativeView(); |
| Widget child_widget; |
| delegate.reset(new AdvanceFocusWidgetDelegate(&child_widget)); |
| params.delegate = delegate.get(); |
| child_widget.Init(params); |
| View* view1 = new View; |
| view1->SetFocusable(true); |
| view1->SetBounds(0, 0, 20, 20); |
| View* view2 = new View; |
| view2->SetFocusable(true); |
| view2->SetBounds(20, 0, 20, 20); |
| child_widget.client_view()->AddChildView(view1); |
| child_widget.client_view()->AddChildView(view2); |
| child_widget.Show(); |
| view2->RequestFocus(); |
| EXPECT_EQ(view2, GetFocusManager()->GetFocusedView()); |
| |
| // Advance focus backwards, which should focus the first. |
| GetFocusManager()->AdvanceFocus(false); |
| EXPECT_EQ(view1, GetFocusManager()->GetFocusedView()); |
| |
| // Focus forward to |view2|. |
| GetFocusManager()->AdvanceFocus(true); |
| EXPECT_EQ(view2, GetFocusManager()->GetFocusedView()); |
| |
| // And forward again, wrapping back to |view1|. |
| GetFocusManager()->AdvanceFocus(true); |
| EXPECT_EQ(view1, GetFocusManager()->GetFocusedView()); |
| |
| // Allow focus to go to the parent, and focus backwards which should now move |
| // up |widget_view| (in the parent). |
| delegate->set_should_advance_focus_to_parent(true); |
| GetFocusManager()->AdvanceFocus(true); |
| EXPECT_EQ(widget_view, GetFocusManager()->GetFocusedView()); |
| } |
| |
| } // namespace views |