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