// Copyright (c) 2009 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.

// Disabled right now as this won't work on BuildBots right now as this test
// require the box it runs on to be unlocked (and no screen-savers).
// The test actually simulates mouse and key events, so if the screen is locked,
// the events don't go to the Chrome window.
#include "testing/gtest/include/gtest/gtest.h"

#include "app/combobox_model.h"
#include "app/resource_bundle.h"
#include "base/keyboard_codes.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "gfx/rect.h"
#include "third_party/skia/include/core/SkColor.h"
#include "views/background.h"
#include "views/border.h"
#include "views/controls/button/checkbox.h"
#include "views/controls/button/native_button.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/textfield/textfield.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/focus/accelerator_handler.h"
#include "views/widget/root_view.h"
#include "views/window/window.h"
#include "views/window/window_delegate.h"

#if defined(OS_WIN)
#include "views/widget/widget_win.h"
#include "views/window/window_win.h"
#elif defined(OS_LINUX)
#include "base/keyboard_code_conversion_gtk.h"
#include "views/window/window_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 views {

class FocusManagerTest : public testing::Test, public WindowDelegate {
 public:
  FocusManagerTest()
      : window_(NULL),
        content_view_(NULL),
        focus_change_listener_(NULL) {
#if defined(OS_WIN)
    OleInitialize(NULL);
#endif
  }

  ~FocusManagerTest() {
#if defined(OS_WIN)
    OleUninitialize();
#endif
  }

  virtual void SetUp() {
    window_ = Window::CreateChromeWindow(NULL, bounds(), this);
    InitContentView();
    window_->Show();
  }

  virtual void TearDown() {
    if (focus_change_listener_)
      GetFocusManager()->RemoveFocusChangeListener(focus_change_listener_);
    window_->Close();

    // Flush the message loop to make Purify happy.
    message_loop()->RunAllPending();
  }

  FocusManager* GetFocusManager() {
#if defined(OS_WIN)
    return static_cast<WindowWin*>(window_)->GetFocusManager();
#elif defined(OS_LINUX)
    return static_cast<WindowGtk*>(window_)->GetFocusManager();
#else
    NOTIMPLEMENTED();
#endif
  }

  void FocusNativeView(gfx::NativeView native_view) {
#if 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
  }

  // WindowDelegate Implementation.
  virtual View* GetContentsView() {
    if (!content_view_)
      content_view_ = new View();
    return content_view_;
  }

  virtual void InitContentView() {
  }

 protected:
  virtual gfx::Rect bounds() {
    return gfx::Rect(0, 0, 500, 500);
  }

  // Mocks activating/deactivating the window.
  void SimulateActivateWindow() {
#if 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(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
  }

  MessageLoopForUI* message_loop() { return &message_loop_; }

  Window* window_;
  View* content_view_;

  void AddFocusChangeListener(FocusChangeListener* listener) {
    ASSERT_FALSE(focus_change_listener_);
    focus_change_listener_ = listener;
    GetFocusManager()->AddFocusChangeListener(listener);
  }

#if defined(OS_WIN)
  void PostKeyDown(base::KeyboardCode key_code) {
    ::PostMessage(window_->GetNativeWindow(), WM_KEYDOWN, key_code, 0);
  }

  void PostKeyUp(base::KeyboardCode key_code) {
    ::PostMessage(window_->GetNativeWindow(), WM_KEYUP, key_code, 0);
  }
#elif defined(OS_LINUX)
  void PostKeyDown(base::KeyboardCode key_code) {
    PostKeyEvent(key_code, true);
  }

  void PostKeyUp(base::KeyboardCode key_code) {
    PostKeyEvent(key_code, false);
  }

  void PostKeyEvent(base::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_;
  MessageLoopForUI message_loop_;

  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);
    SetFocusable(false);
  }

  virtual ~BorderView() {}

  virtual RootView* GetContentsRootView() {
    return widget_->GetRootView();
  }

  virtual FocusTraversable* GetFocusTraversable() {
    return 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_) {
#if defined(OS_WIN)
        WidgetWin* widget_win = new WidgetWin();
        widget_win->Init(parent->GetRootView()->GetWidget()->GetNativeView(),
                         gfx::Rect(0, 0, 0, 0));
        widget_win->SetFocusTraversableParentView(this);
        widget_ = widget_win;
#else
        WidgetGtk* widget_gtk = new WidgetGtk(WidgetGtk::TYPE_CHILD);
        widget_gtk->Init(native_view(), gfx::Rect(0, 0, 0, 0));
        widget_gtk->SetFocusTraversableParentView(this);
        widget_ = widget_gtk;
#endif
        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.
      widget_->GetRootView()->SetFocusTraversableParent(GetRootView());
    }
  }

 private:
  View* child_;
  Widget* widget_;

  DISALLOW_COPY_AND_ASSIGN(BorderView);
};

class DummyComboboxModel : public ComboboxModel {
 public:
  virtual int GetItemCount() { return 10; }

  virtual std::wstring GetItemAt(int index) {
    return L"Item " + IntToWString(index);
  }
};

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;
    view = style_tab_->GetSelectedTab()->GetViewByID(id);
    if (view)
      return view;
    view = search_border_view_->GetContentsRootView()->GetViewByID(id);
    if (view)
      return view;
    return NULL;
  }

 private:
  TabbedPane* style_tab_;
  BorderView* search_border_view_;
  DummyComboboxModel combobox_model_;

  DISALLOW_COPY_AND_ASSIGN(FocusTraversalTest);
};

////////////////////////////////////////////////////////////////////////////////
// FocusTraversalTest
////////////////////////////////////////////////////////////////////////////////

FocusTraversalTest::FocusTraversalTest()
  : style_tab_(NULL),
    search_border_view_(NULL) {
}

FocusTraversalTest::~FocusTraversalTest() {
}

void FocusTraversalTest::InitContentView() {
  content_view_->set_background(
      Background::CreateSolidBackground(SK_ColorWHITE));

  Checkbox* cb = new Checkbox(L"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->SetID(kTopCheckBoxID);

  View* left_container = new View();
  left_container->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK));
  left_container->set_background(
      Background::CreateSolidBackground(240, 240, 240));
  left_container->SetID(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(L"Apple:");
  label->SetID(kAppleLabelID);
  left_container->AddChildView(label);
  label->SetBounds(label_x, y, label_width, label_height);

  Textfield* text_field = new Textfield();
  text_field->SetID(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(L"Orange:");
  label->SetID(kOrangeLabelID);
  left_container->AddChildView(label);
  label->SetBounds(label_x, y, label_width, label_height);

  text_field = new Textfield();
  text_field->SetID(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(L"Banana:");
  label->SetID(kBananaLabelID);
  left_container->AddChildView(label);
  label->SetBounds(label_x, y, label_width, label_height);

  text_field = new Textfield();
  text_field->SetID(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(L"Kiwi:");
  label->SetID(kKiwiLabelID);
  left_container->AddChildView(label);
  label->SetBounds(label_x, y, label_width, label_height);

  text_field = new Textfield();
  text_field->SetID(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;

  NativeButton* button = new NativeButton(NULL, L"Click me");
  button->SetBounds(label_x, y + 10, 80, 30);
  button->SetID(kFruitButtonID);
  left_container->AddChildView(button);
  y += 40;

  cb =  new Checkbox(L"This is another check box");
  cb->SetBounds(label_x + label_width + 5, y, 180, 20);
  cb->SetID(kFruitCheckBoxID);
  left_container->AddChildView(cb);
  y += 20;

  Combobox* combobox =  new Combobox(&combobox_model_);
  combobox->SetBounds(label_x + label_width + 5, y, 150, 30);
  combobox->SetID(kComboboxID);
  left_container->AddChildView(combobox);

  View* right_container = new View();
  right_container->set_border(Border::CreateSolidBorder(1, SK_ColorBLACK));
  right_container->set_background(
      Background::CreateSolidBackground(240, 240, 240));
  right_container->SetID(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(L"Asparagus", 1);
  radio_button->SetID(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(L"Broccoli", 1);
  radio_button->SetID(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(L"Cauliflower", 1);
  radio_button->SetID(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->SetID(kInnerContainerID);
  right_container->AddChildView(inner_container);
  inner_container->SetBounds(100, 10, 150, 180);

  ScrollView* scroll_view = new ScrollView();
  scroll_view->SetID(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 wchar_t* const kTitles[] = {
      L"Rosetta", L"Stupeur et tremblement", L"The diner game",
      L"Ridicule", L"Le placard", L"Les Visiteurs", L"Amelie",
      L"Joyeux Noel", L"Camping", L"Brice de Nice",
      L"Taxi", L"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(kTitles[i]);
    link->SetHorizontalAlignment(Label::ALIGN_LEFT);
    link->SetID(kIDs[i]);
    scroll_content->AddChildView(link);
    link->SetBounds(5, y, 300, 15);
    y += 15;
  }

  y = 250;
  int width = 60;
  button = new NativeButton(NULL, L"OK");
  button->SetID(kOKButtonID);
  button->SetIsDefault(true);

  content_view_->AddChildView(button);
  button->SetBounds(150, y, width, 30);

  button = new NativeButton(NULL, L"Cancel");
  button->SetID(kCancelButtonID);
  content_view_->AddChildView(button);
  button->SetBounds(220, y, width, 30);

  button = new NativeButton(NULL, L"Help");
  button->SetID(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(L"Bold");
  contents->AddChildView(cb);
  cb->SetBounds(10, 10, 50, 20);
  cb->SetID(kBoldCheckBoxID);

  cb = new Checkbox(L"Italic");
  contents->AddChildView(cb);
  cb->SetBounds(70, 10, 50, 20);
  cb->SetID(kItalicCheckBoxID);

  cb = new Checkbox(L"Underlined");
  contents->AddChildView(cb);
  cb->SetBounds(130, 10, 70, 20);
  cb->SetID(kUnderlinedCheckBoxID);

  Link* link = new Link(L"Help");
  contents->AddChildView(link);
  link->SetBounds(10, 35, 70, 10);
  link->SetID(kStyleHelpLinkID);

  text_field = new Textfield();
  contents->AddChildView(text_field);
  text_field->SetBounds(10, 50, 100, 20);
  text_field->SetID(kStyleTextEditID);

  style_tab_ = new TabbedPane();
  style_tab_->SetID(kStyleContainerID);
  content_view_->AddChildView(style_tab_);
  style_tab_->SetBounds(10, y, 210, 100);
  style_tab_->AddTab(L"Style", contents);
  style_tab_->AddTab(L"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->SetID(kSearchTextfieldID);

  button = new NativeButton(NULL, L"Search");
  contents->AddChildView(button);
  button->SetBounds(112, 5, 60, 30);
  button->SetID(kSearchButtonID);

  link = new Link(L"Help");
  link->SetHorizontalAlignment(Label::ALIGN_LEFT);
  link->SetID(kHelpLinkID);
  contents->AddChildView(link);
  link->SetBounds(175, 10, 30, 20);

  search_border_view_ = new BorderView(contents);
  search_border_view_->SetID(kSearchContainerID);

  content_view_->AddChildView(search_border_view_);
  search_border_view_->SetBounds(300, y, 240, 50);

  y += 60;

  contents = new View();
  contents->SetFocusable(true);
  contents->set_background(Background::CreateSolidBackground(SK_ColorBLUE));
  contents->SetID(kThumbnailContainerID);
  button = new NativeButton(NULL, L"Star");
  contents->AddChildView(button);
  button->SetBounds(5, 5, 50, 30);
  button->SetID(kThumbnailStarID);
  button = new NativeButton(NULL, L"SuperStar");
  contents->AddChildView(button);
  button->SetBounds(60, 5, 100, 30);
  button->SetID(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 {
  WILL_GAIN_FOCUS = 0,
  DID_GAIN_FOCUS,
  WILL_LOSE_FOCUS
};

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);
    SetID(view_id);
  }

  virtual void WillGainFocus() {
    event_list_->push_back(FocusTestEvent(WILL_GAIN_FOCUS, GetID()));
  }

  virtual void DidGainFocus() {
    event_list_->push_back(FocusTestEvent(DID_GAIN_FOCUS, GetID()));
  }

  virtual void WillLoseFocus() {
    event_list_->push_back(FocusTestEvent(WILL_LOSE_FOCUS, GetID()));
  }

 private:
  std::vector<FocusTestEvent>* event_list_;
};

// 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);
  content_view_->AddChildView(view1);
  content_view_->AddChildView(view2);

  view1->RequestFocus();
  ASSERT_EQ(2, static_cast<int>(event_list.size()));
  EXPECT_EQ(WILL_GAIN_FOCUS, event_list[0].type);
  EXPECT_EQ(kView1ID, event_list[0].view_id);
  EXPECT_EQ(DID_GAIN_FOCUS, event_list[1].type);
  EXPECT_EQ(kView1ID, event_list[0].view_id);

  event_list.clear();
  view2->RequestFocus();
  ASSERT_EQ(3, static_cast<int>(event_list.size()));
  EXPECT_EQ(WILL_LOSE_FOCUS, event_list[0].type);
  EXPECT_EQ(kView1ID, event_list[0].view_id);
  EXPECT_EQ(WILL_GAIN_FOCUS, event_list[1].type);
  EXPECT_EQ(kView2ID, event_list[1].view_id);
  EXPECT_EQ(DID_GAIN_FOCUS, event_list[2].type);
  EXPECT_EQ(kView2ID, event_list[2].view_id);

  event_list.clear();
  GetFocusManager()->ClearFocus();
  ASSERT_EQ(1, static_cast<int>(event_list.size()));
  EXPECT_EQ(WILL_LOSE_FOCUS, event_list[0].type);
  EXPECT_EQ(kView2ID, event_list[0].view_id);
}

typedef std::pair<View*, View*> ViewPair;
class TestFocusChangeListener : public FocusChangeListener {
 public:
  virtual void FocusWillChange(View* focused_before, View* focused_now) {
    focus_changes_.push_back(ViewPair(focused_before, 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->SetFocusable(true);
  View* view2 = new View();
  view2->SetFocusable(true);
  content_view_->AddChildView(view1);
  content_view_->AddChildView(view2);

  TestFocusChangeListener listener;
  AddFocusChangeListener(&listener);

  view1->RequestFocus();
  ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size()));
  EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(NULL, 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));
}

class TestNativeButton : public NativeButton {
 public:
  explicit TestNativeButton(const std::wstring& text)
      : NativeButton(NULL, text) {
  };
  virtual gfx::NativeView TestGetNativeControlView() {
    return native_wrapper_->GetTestingHandle();
  }
};

class TestCheckbox : public Checkbox {
 public:
  explicit TestCheckbox(const std::wstring& text) : Checkbox(text) {
  };
  virtual gfx::NativeView TestGetNativeControlView() {
    return native_wrapper_->GetTestingHandle();
  }
};

class TestRadioButton : public RadioButton {
 public:
  explicit TestRadioButton(const std::wstring& text) : RadioButton(text, 1) {
  };
  virtual gfx::NativeView TestGetNativeControlView() {
    return native_wrapper_->GetTestingHandle();
  }
};

class TestTextfield : public Textfield {
 public:
  TestTextfield() { }
  virtual gfx::NativeView TestGetNativeControlView() {
    return native_wrapper_->GetTestingHandle();
  }
};

class TestCombobox : public Combobox, public ComboboxModel {
 public:
  TestCombobox() : Combobox(this) { }
  virtual gfx::NativeView TestGetNativeControlView() {
    return native_wrapper_->GetTestingHandle();
  }
  virtual int GetItemCount() {
    return 10;
  }
  virtual std::wstring GetItemAt(int index) {
    return L"Hello combo";
  }
};

class TestTabbedPane : public TabbedPane {
 public:
  TestTabbedPane() { }
  virtual gfx::NativeView TestGetNativeControlView() {
    return native_tabbed_pane_->GetTestingHandle();
  }
};

// Tests that NativeControls do set the focus View appropriately on the
// FocusManager.
TEST_F(FocusManagerTest, FocusNativeControls) {
  TestNativeButton* button = new TestNativeButton(L"Press me");
  TestCheckbox* checkbox = new TestCheckbox(L"Checkbox");
  TestRadioButton* radio_button = new TestRadioButton(L"RadioButton");
  TestTextfield* textfield = new TestTextfield();
  TestCombobox* combobox = new TestCombobox();
  TestTabbedPane* tabbed_pane = new TestTabbedPane();
  TestNativeButton* tab_button = new TestNativeButton(L"tab button");

  content_view_->AddChildView(button);
  content_view_->AddChildView(checkbox);
  content_view_->AddChildView(radio_button);
  content_view_->AddChildView(textfield);
  content_view_->AddChildView(combobox);
  content_view_->AddChildView(tabbed_pane);
  tabbed_pane->AddTab(L"Awesome tab", tab_button);

  // Simulate the native view getting the native focus (such as by user click).
  FocusNativeView(button->TestGetNativeControlView());
  EXPECT_EQ(button, GetFocusManager()->GetFocusedView());

  FocusNativeView(checkbox->TestGetNativeControlView());
  EXPECT_EQ(checkbox, GetFocusManager()->GetFocusedView());

  FocusNativeView(radio_button->TestGetNativeControlView());
  EXPECT_EQ(radio_button, GetFocusManager()->GetFocusedView());

  FocusNativeView(textfield->TestGetNativeControlView());
  EXPECT_EQ(textfield, GetFocusManager()->GetFocusedView());

  FocusNativeView(combobox->TestGetNativeControlView());
  EXPECT_EQ(combobox, GetFocusManager()->GetFocusedView());

  FocusNativeView(tabbed_pane->TestGetNativeControlView());
  EXPECT_EQ(tabbed_pane, GetFocusManager()->GetFocusedView());

  FocusNativeView(tab_button->TestGetNativeControlView());
  EXPECT_EQ(tab_button, GetFocusManager()->GetFocusedView());
}

// 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();

  NativeButton* button = new NativeButton(NULL, L"Press me");
  View* view = new View();
  view->SetFocusable(true);

  content_view_->AddChildView(button);
  button->SetBounds(10, 10, 200, 30);
  content_view_->AddChildView(view);
  message_loop()->RunAllPending();

  TestFocusChangeListener listener;
  AddFocusChangeListener(&listener);

  view->RequestFocus();
  message_loop()->RunAllPending();
  //  MessageLoopForUI::current()->Run(new AcceleratorHandler());

  // 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));
  EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(view, NULL));
  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));
  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));
  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, 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));
  EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(NULL, view));
  */
}

TEST_F(FocusManagerTest, ContainsView) {
  View* view = new View();
  scoped_ptr<View> detached_view(new View());
  TabbedPane* tabbed_pane = new TabbedPane();
  TabbedPane* nested_tabbed_pane = new TabbedPane();
  NativeButton* tab_button = new NativeButton(NULL, L"tab button");

  content_view_->AddChildView(view);
  content_view_->AddChildView(tabbed_pane);
  // Adding a View inside a TabbedPane to test the case of nested root view.

  tabbed_pane->AddTab(L"Awesome tab", nested_tabbed_pane);
  nested_tabbed_pane->AddTab(L"Awesomer tab", tab_button);

  EXPECT_TRUE(GetFocusManager()->ContainsView(view));
  EXPECT_TRUE(GetFocusManager()->ContainsView(tabbed_pane));
  EXPECT_TRUE(GetFocusManager()->ContainsView(nested_tabbed_pane));
  EXPECT_TRUE(GetFocusManager()->ContainsView(tab_button));
  EXPECT_FALSE(GetFocusManager()->ContainsView(detached_view.get()));
}

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()->Run(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->GetID());
    }
  }

  // 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->GetID());
    }
  }
}

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);
    if (v)
      v->SetEnabled(false);
  }

  // Uncomment the following line if you want to test manually the UI of this
  // test.
  // MessageLoopForUI::current()->Run(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->GetID());
    }
  }

  // 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->GetID());
    }
  }
}

// Counts accelerator calls.
class TestAcceleratorTarget : public AcceleratorTarget {
 public:
  explicit TestAcceleratorTarget(bool process_accelerator)
      : accelerator_count_(0), process_accelerator_(process_accelerator) {}

  virtual bool AcceleratorPressed(const Accelerator& accelerator) {
    ++accelerator_count_;
    return process_accelerator_;
  }

  int accelerator_count() const { return accelerator_count_; }

 private:
  int accelerator_count_;  // number of times that the accelerator is activated
  bool process_accelerator_;  // return value of AcceleratorPressed

  DISALLOW_COPY_AND_ASSIGN(TestAcceleratorTarget);
};

TEST_F(FocusManagerTest, CallsNormalAcceleratorTarget) {
  FocusManager* focus_manager = GetFocusManager();
  Accelerator return_accelerator(base::VKEY_RETURN, false, false, false);
  Accelerator escape_accelerator(base::VKEY_ESCAPE, false, false, false);

  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, &return_target);
  focus_manager->RegisterAccelerator(escape_accelerator, &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, &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, &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);
}

// Unregisters itself when its accelerator is invoked.
class SelfUnregisteringAcceleratorTarget : public AcceleratorTarget {
 public:
  SelfUnregisteringAcceleratorTarget(Accelerator accelerator,
                                     FocusManager* focus_manager)
      : accelerator_(accelerator),
        focus_manager_(focus_manager),
        accelerator_count_(0) {
  }

  virtual bool AcceleratorPressed(const Accelerator& accelerator) {
    ++accelerator_count_;
    focus_manager_->UnregisterAccelerator(accelerator, this);
    return true;
  }

  int accelerator_count() const { return accelerator_count_; }

 private:
  Accelerator accelerator_;
  FocusManager* focus_manager_;
  int accelerator_count_;

  DISALLOW_COPY_AND_ASSIGN(SelfUnregisteringAcceleratorTarget);
};

TEST_F(FocusManagerTest, CallsSelfDeletingAcceleratorTarget) {
  FocusManager* focus_manager = GetFocusManager();
  Accelerator return_accelerator(base::VKEY_RETURN, false, false, false);
  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, &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 MessageTrackingView : public View {
 public:
  MessageTrackingView() : accelerator_pressed_(false) {
 }

  virtual bool OnKeyPressed(const KeyEvent& e) {
    keys_pressed_.push_back(e.GetKeyCode());
    return true;
  }

  virtual bool OnKeyReleased(const KeyEvent& e) {
    keys_released_.push_back(e.GetKeyCode());
    return true;
  }

  virtual bool AcceleratorPressed(const Accelerator& accelerator) {
    accelerator_pressed_ = true;
    return true;
  }

  void Reset() {
    accelerator_pressed_ = false;
    keys_pressed_.clear();
    keys_released_.clear();
  }

  const std::vector<base::KeyboardCode>& keys_pressed() const {
    return keys_pressed_;
  }

  const std::vector<base::KeyboardCode>& keys_released() const {
    return keys_released_;
  }

  bool accelerator_pressed() const {
    return accelerator_pressed_;
  }

 private:
  bool accelerator_pressed_;
  std::vector<base::KeyboardCode> keys_pressed_;
  std::vector<base::KeyboardCode> keys_released_;

  DISALLOW_COPY_AND_ASSIGN(MessageTrackingView);
};

// Tests that the keyup messages are eaten for accelerators.
TEST_F(FocusManagerTest, IgnoreKeyupForAccelerators) {
  FocusManager* focus_manager = GetFocusManager();
  MessageTrackingView* mtv = new MessageTrackingView();
  mtv->AddAccelerator(Accelerator(base::VKEY_0, false, false, false));
  mtv->AddAccelerator(Accelerator(base::VKEY_1, false, false, false));
  content_view_->AddChildView(mtv);
  focus_manager->SetFocusedView(mtv);

  // First send a non-accelerator key sequence.
  PostKeyDown(base::VKEY_9);
  PostKeyUp(base::VKEY_9);
  AcceleratorHandler accelerator_handler;
  MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
  MessageLoopForUI::current()->Run(&accelerator_handler);
  // Make sure we get a key-up and key-down.
  ASSERT_EQ(1U, mtv->keys_pressed().size());
  EXPECT_EQ(base::VKEY_9, mtv->keys_pressed().at(0));
  ASSERT_EQ(1U, mtv->keys_released().size());
  EXPECT_EQ(base::VKEY_9, mtv->keys_released().at(0));
  EXPECT_FALSE(mtv->accelerator_pressed());
  mtv->Reset();

  // Same thing with repeat and more than one key at once.
  PostKeyDown(base::VKEY_9);
  PostKeyDown(base::VKEY_9);
  PostKeyDown(base::VKEY_8);
  PostKeyDown(base::VKEY_9);
  PostKeyDown(base::VKEY_7);
  PostKeyUp(base::VKEY_9);
  PostKeyUp(base::VKEY_7);
  PostKeyUp(base::VKEY_8);
  MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
  MessageLoopForUI::current()->Run(&accelerator_handler);
  // Make sure we get a key-up and key-down.
  ASSERT_EQ(5U, mtv->keys_pressed().size());
  EXPECT_EQ(base::VKEY_9, mtv->keys_pressed().at(0));
  EXPECT_EQ(base::VKEY_9, mtv->keys_pressed().at(1));
  EXPECT_EQ(base::VKEY_8, mtv->keys_pressed().at(2));
  EXPECT_EQ(base::VKEY_9, mtv->keys_pressed().at(3));
  EXPECT_EQ(base::VKEY_7, mtv->keys_pressed().at(4));
  ASSERT_EQ(3U, mtv->keys_released().size());
  EXPECT_EQ(base::VKEY_9, mtv->keys_released().at(0));
  EXPECT_EQ(base::VKEY_7, mtv->keys_released().at(1));
  EXPECT_EQ(base::VKEY_8, mtv->keys_released().at(2));
  EXPECT_FALSE(mtv->accelerator_pressed());
  mtv->Reset();

  // Now send an accelerator key sequence.
  PostKeyDown(base::VKEY_0);
  PostKeyUp(base::VKEY_0);
  MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
  MessageLoopForUI::current()->Run(&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(base::VKEY_0);
  PostKeyDown(base::VKEY_1);
  PostKeyDown(base::VKEY_1);
  PostKeyDown(base::VKEY_0);
  PostKeyDown(base::VKEY_0);
  PostKeyUp(base::VKEY_1);
  PostKeyUp(base::VKEY_0);
  MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
  MessageLoopForUI::current()->Run(&accelerator_handler);
#if defined(OS_WIN)
  // Linux eats only last accelerator's release event.
  // See http://crbug.com/23383 for details.
  EXPECT_TRUE(mtv->keys_pressed().empty());
  EXPECT_TRUE(mtv->keys_released().empty());
#endif
  EXPECT_TRUE(mtv->accelerator_pressed());
  mtv->Reset();
}

#if defined(OS_WIN)
// 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.
  WidgetWin window1;
  window1.set_delete_on_destroy(false);
  window1.set_window_style(WS_CHILD);
  window1.Init(hwnd, gfx::Rect(0, 0, 100, 100));

  // Get the focus manager directly from the first window.  Should exist
  // because the first window is the root widget.
  views::FocusManager* focus_manager_member1 = window1.GetFocusManager();
  EXPECT_TRUE(focus_manager_member1);

  // Create another view window parented to the first view window.
  WidgetWin window2;
  window2.set_delete_on_destroy(false);
  window2.set_window_style(WS_CHILD);
  window2.Init(window1.GetNativeView(), gfx::Rect(0, 0, 100, 100));

  // Get the focus manager directly from the second window. Should return the
  // first window's focus manager.
  views::FocusManager* focus_manager_member2 = window2.GetFocusManager();
  EXPECT_EQ(focus_manager_member2, focus_manager_member1);

  // Get the focus manager indirectly using the first window handle. Should
  // return the first window's focus manager.
  views::FocusManager* focus_manager_indirect =
      views::FocusManager::GetFocusManagerForNativeView(
          window1.GetNativeView());
  EXPECT_EQ(focus_manager_indirect, focus_manager_member1);

  // Get the focus manager indirectly using the second window handle. Should
  // return the first window's focus manager.
  focus_manager_indirect =
      views::FocusManager::GetFocusManagerForNativeView(
          window2.GetNativeView());
  EXPECT_EQ(focus_manager_indirect, focus_manager_member1);

  DestroyWindow(hwnd);
}
#endif

}  // namespace views