| Index: ui/views/focus/focus_manager_unittest_win.cc
|
| ===================================================================
|
| --- ui/views/focus/focus_manager_unittest_win.cc (revision 0)
|
| +++ ui/views/focus/focus_manager_unittest_win.cc (revision 0)
|
| @@ -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
|
|
|
| Property changes on: ui\views\focus\focus_manager_unittest_win.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|