| Index: chrome/browser/ui/views/menu_view_drag_and_drop_test.cc
|
| diff --git a/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc b/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..17a6c4146fd5b076f023030727b76592f10f87b3
|
| --- /dev/null
|
| +++ b/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc
|
| @@ -0,0 +1,442 @@
|
| +// Copyright 2014 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 "base/strings/utf_string_conversions.h"
|
| +#include "chrome/browser/ui/views/menu_test_base.h"
|
| +#include "chrome/test/base/interactive_test_utils.h"
|
| +#include "ui/base/dragdrop/drag_drop_types.h"
|
| +#include "ui/base/dragdrop/os_exchange_data.h"
|
| +#include "ui/views/controls/menu/menu_item_view.h"
|
| +#include "ui/views/controls/menu/submenu_view.h"
|
| +#include "ui/views/view.h"
|
| +
|
| +namespace {
|
| +
|
| +// Borrowed from chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc,
|
| +// since these are also disabled on Linux for drag and drop.
|
| +// TODO(erg): Fix DND tests on linux_aura. crbug.com/163931
|
| +#if defined(OS_LINUX) && defined(USE_AURA)
|
| +#define MAYBE(x) DISABLED_##x
|
| +#else
|
| +#define MAYBE(x) x
|
| +#endif
|
| +
|
| +const char kTestNestedDragData[] = "test_nested_drag_data";
|
| +const char kTestTopLevelDragData[] = "test_top_level_drag_data";
|
| +
|
| +// A simple view which can be dragged.
|
| +class TestDragView : public views::View {
|
| + public:
|
| + TestDragView();
|
| + virtual ~TestDragView();
|
| +
|
| + private:
|
| + // views::View:
|
| + virtual int GetDragOperations(const gfx::Point& point) OVERRIDE;
|
| + virtual void WriteDragData(const gfx::Point& point,
|
| + ui::OSExchangeData* data) OVERRIDE;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestDragView);
|
| +};
|
| +
|
| +TestDragView::TestDragView() {
|
| +}
|
| +
|
| +TestDragView::~TestDragView() {
|
| +}
|
| +
|
| +int TestDragView::GetDragOperations(const gfx::Point& point) {
|
| + return ui::DragDropTypes::DRAG_MOVE;
|
| +}
|
| +
|
| +void TestDragView::WriteDragData(const gfx::Point& point,
|
| + ui::OSExchangeData* data) {
|
| + data->SetString(base::ASCIIToUTF16(kTestNestedDragData));
|
| +}
|
| +
|
| +// A simple view to serve as a drop target.
|
| +class TestTargetView : public views::View {
|
| + public:
|
| + TestTargetView();
|
| + virtual ~TestTargetView();
|
| +
|
| + // Initializes this view to have the same bounds as |parent| and two draggable
|
| + // child views.
|
| + void Init(views::View* parent);
|
| + bool dragging() const { return dragging_; }
|
| + bool dropped() const { return dropped_; }
|
| +
|
| + private:
|
| + // views::View:
|
| + virtual bool GetDropFormats(
|
| + int* formats,
|
| + std::set<OSExchangeData::CustomFormat>* custom_formats) OVERRIDE;
|
| + virtual bool AreDropTypesRequired() OVERRIDE;
|
| + virtual bool CanDrop(const OSExchangeData& data) OVERRIDE;
|
| + virtual void OnDragEntered(const ui::DropTargetEvent& event) OVERRIDE;
|
| + virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
|
| + virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
|
| + virtual void OnDragExited() OVERRIDE;
|
| +
|
| + // Whether or not we are currently dragging.
|
| + bool dragging_;
|
| +
|
| + // Whether or not a drop has been performed on the view.
|
| + bool dropped_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestTargetView);
|
| +};
|
| +
|
| +TestTargetView::TestTargetView() : dragging_(false), dropped_(false) {
|
| +}
|
| +
|
| +void TestTargetView::Init(views::View* parent) {
|
| + // First, match the parent's size.
|
| + SetSize(parent->size());
|
| +
|
| + // Then add two draggable views, each 10x2.
|
| + views::View* first = new TestDragView();
|
| + AddChildView(first);
|
| + first->SetBounds(2, 2, 10, 2);
|
| +
|
| + views::View* second = new TestDragView();
|
| + AddChildView(second);
|
| + second->SetBounds(15, 2, 10, 2);
|
| +}
|
| +
|
| +TestTargetView::~TestTargetView() {
|
| +}
|
| +
|
| +bool TestTargetView::GetDropFormats(
|
| + int* formats, std::set<OSExchangeData::CustomFormat>* custom_formats) {
|
| + *formats = ui::OSExchangeData::STRING;
|
| + return true;
|
| +}
|
| +
|
| +bool TestTargetView::AreDropTypesRequired() {
|
| + return true;
|
| +}
|
| +
|
| +bool TestTargetView::CanDrop(const OSExchangeData& data) {
|
| + base::string16 contents;
|
| + return data.GetString(&contents) &&
|
| + contents == base::ASCIIToUTF16(kTestNestedDragData);
|
| +}
|
| +
|
| +void TestTargetView::OnDragEntered(const ui::DropTargetEvent& event) {
|
| + dragging_ = true;
|
| +}
|
| +
|
| +int TestTargetView::OnDragUpdated(const ui::DropTargetEvent& event) {
|
| + return ui::DragDropTypes::DRAG_MOVE;
|
| +}
|
| +
|
| +int TestTargetView::OnPerformDrop(const ui::DropTargetEvent& event) {
|
| + dragging_ = false;
|
| + dropped_ = true;
|
| + return ui::DragDropTypes::DRAG_MOVE;
|
| +}
|
| +
|
| +void TestTargetView::OnDragExited() {
|
| + dragging_ = false;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +class MenuViewDragAndDropTest : public MenuTestBase {
|
| + public:
|
| + MenuViewDragAndDropTest();
|
| + virtual ~MenuViewDragAndDropTest();
|
| +
|
| + protected:
|
| + TestTargetView* target_view() { return target_view_; }
|
| + bool asked_to_close() const { return asked_to_close_; }
|
| + bool performed_in_menu_drop() const { return performed_in_menu_drop_; }
|
| +
|
| + private:
|
| + // MenuTestBase:
|
| + virtual void BuildMenu(views::MenuItemView* menu) OVERRIDE;
|
| +
|
| + // views::MenuDelegate:
|
| + virtual bool GetDropFormats(
|
| + views::MenuItemView* menu,
|
| + int* formats,
|
| + std::set<ui::OSExchangeData::CustomFormat>* custom_formats) OVERRIDE;
|
| + virtual bool AreDropTypesRequired(views::MenuItemView* menu) OVERRIDE;
|
| + virtual bool CanDrop(views::MenuItemView* menu,
|
| + const ui::OSExchangeData& data) OVERRIDE;
|
| + virtual int GetDropOperation(views::MenuItemView* item,
|
| + const ui::DropTargetEvent& event,
|
| + DropPosition* position) OVERRIDE;
|
| + virtual int OnPerformDrop(views::MenuItemView* menu,
|
| + DropPosition position,
|
| + const ui::DropTargetEvent& event) OVERRIDE;
|
| + virtual bool CanDrag(views::MenuItemView* menu) OVERRIDE;
|
| + virtual void WriteDragData(views::MenuItemView* sender,
|
| + ui::OSExchangeData* data) OVERRIDE;
|
| + virtual int GetDragOperations(views::MenuItemView* sender) OVERRIDE;
|
| + virtual bool ShouldCloseOnDragComplete() OVERRIDE;
|
| +
|
| + // The special view in the menu, which supports its own drag and drop.
|
| + TestTargetView* target_view_;
|
| +
|
| + // Whether or not we have been asked to close on drag complete.
|
| + bool asked_to_close_;
|
| +
|
| + // Whether or not a drop was performed in-menu (i.e., not including drops
|
| + // in separate child views).
|
| + bool performed_in_menu_drop_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(MenuViewDragAndDropTest);
|
| +};
|
| +
|
| +MenuViewDragAndDropTest::MenuViewDragAndDropTest()
|
| + : target_view_(NULL),
|
| + asked_to_close_(false),
|
| + performed_in_menu_drop_(false) {
|
| +}
|
| +
|
| +MenuViewDragAndDropTest::~MenuViewDragAndDropTest() {
|
| +}
|
| +
|
| +void MenuViewDragAndDropTest::BuildMenu(views::MenuItemView* menu) {
|
| + // Build a menu item that has a nested view that supports its own drag and
|
| + // drop...
|
| + views::MenuItemView* menu_item_view =
|
| + menu->AppendMenuItem(1,
|
| + base::ASCIIToUTF16("item 1"),
|
| + views::MenuItemView::NORMAL);
|
| + target_view_ = new TestTargetView();
|
| + menu_item_view->AddChildView(target_view_);
|
| + // ... as well as two other, normal items.
|
| + menu->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("item 2"));
|
| + menu->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("item 3"));
|
| +}
|
| +
|
| +bool MenuViewDragAndDropTest::GetDropFormats(
|
| + views::MenuItemView* menu,
|
| + int* formats,
|
| + std::set<ui::OSExchangeData::CustomFormat>* custom_formats) {
|
| + *formats = ui::OSExchangeData::STRING;
|
| + return true;
|
| +}
|
| +
|
| +bool MenuViewDragAndDropTest::AreDropTypesRequired(views::MenuItemView* menu) {
|
| + return true;
|
| +}
|
| +
|
| +bool MenuViewDragAndDropTest::CanDrop(views::MenuItemView* menu,
|
| + const ui::OSExchangeData& data) {
|
| + base::string16 contents;
|
| + return data.GetString(&contents) &&
|
| + contents == base::ASCIIToUTF16(kTestTopLevelDragData);
|
| +}
|
| +
|
| +int MenuViewDragAndDropTest::GetDropOperation(views::MenuItemView* item,
|
| + const ui::DropTargetEvent& event,
|
| + DropPosition* position) {
|
| + return ui::DragDropTypes::DRAG_MOVE;
|
| +}
|
| +
|
| +
|
| +int MenuViewDragAndDropTest::OnPerformDrop(views::MenuItemView* menu,
|
| + DropPosition position,
|
| + const ui::DropTargetEvent& event) {
|
| + performed_in_menu_drop_ = true;
|
| + return ui::DragDropTypes::DRAG_MOVE;
|
| +}
|
| +
|
| +bool MenuViewDragAndDropTest::CanDrag(views::MenuItemView* menu) {
|
| + return true;
|
| +}
|
| +
|
| +void MenuViewDragAndDropTest::WriteDragData(
|
| + views::MenuItemView* sender, ui::OSExchangeData* data) {
|
| + data->SetString(base::ASCIIToUTF16(kTestTopLevelDragData));
|
| +}
|
| +
|
| +int MenuViewDragAndDropTest::GetDragOperations(views::MenuItemView* sender) {
|
| + return ui::DragDropTypes::DRAG_MOVE;
|
| +}
|
| +
|
| +bool MenuViewDragAndDropTest::ShouldCloseOnDragComplete() {
|
| + asked_to_close_ = true;
|
| + return false;
|
| +}
|
| +
|
| +class MenuViewDragAndDropTestTestInMenuDrag : public MenuViewDragAndDropTest {
|
| + public:
|
| + MenuViewDragAndDropTestTestInMenuDrag() {}
|
| + virtual ~MenuViewDragAndDropTestTestInMenuDrag() {}
|
| +
|
| + private:
|
| + // MenuViewDragAndDropTest:
|
| + virtual void DoTestWithMenuOpen() OVERRIDE;
|
| +
|
| + void Step2();
|
| + void Step3();
|
| + void Step4();
|
| +};
|
| +
|
| +void MenuViewDragAndDropTestTestInMenuDrag::DoTestWithMenuOpen() {
|
| + // A few sanity checks to make sure the menu built correctly.
|
| + views::SubmenuView* submenu = menu()->GetSubmenu();
|
| + ASSERT_TRUE(submenu);
|
| + ASSERT_TRUE(submenu->IsShowing());
|
| + ASSERT_EQ(3, submenu->GetMenuItemCount());
|
| +
|
| + // We do this here (instead of in BuildMenu()) so that the menu is already
|
| + // built and the bounds are correct.
|
| + target_view()->Init(submenu->GetMenuItemAt(0));
|
| +
|
| + // We're going to drag the second menu element.
|
| + views::MenuItemView* drag_view = submenu->GetMenuItemAt(1);
|
| + ASSERT_TRUE(drag_view != NULL);
|
| +
|
| + // Move mouse to center of menu and press button.
|
| + ui_test_utils::MoveMouseToCenterAndPress(
|
| + drag_view,
|
| + ui_controls::LEFT,
|
| + ui_controls::DOWN,
|
| + CreateEventTask(this, &MenuViewDragAndDropTestTestInMenuDrag::Step2));
|
| +}
|
| +
|
| +void MenuViewDragAndDropTestTestInMenuDrag::Step2() {
|
| + views::MenuItemView* drop_target = menu()->GetSubmenu()->GetMenuItemAt(2);
|
| + gfx::Point loc(1, drop_target->height() - 1);
|
| + views::View::ConvertPointToScreen(drop_target, &loc);
|
| +
|
| + // Start a drag.
|
| + ui_controls::SendMouseMoveNotifyWhenDone(
|
| + loc.x() + 10,
|
| + loc.y(),
|
| + CreateEventTask(this, &MenuViewDragAndDropTestTestInMenuDrag::Step3));
|
| +
|
| + ScheduleMouseMoveInBackground(loc.x(), loc.y());
|
| +}
|
| +
|
| +void MenuViewDragAndDropTestTestInMenuDrag::Step3() {
|
| + // Drop the item on the target.
|
| + views::MenuItemView* drop_target = menu()->GetSubmenu()->GetMenuItemAt(2);
|
| + gfx::Point loc(1, drop_target->height() - 2);
|
| + views::View::ConvertPointToScreen(drop_target, &loc);
|
| + ui_controls::SendMouseMove(loc.x(), loc.y());
|
| +
|
| + ui_controls::SendMouseEventsNotifyWhenDone(
|
| + ui_controls::LEFT,
|
| + ui_controls::UP,
|
| + CreateEventTask(this, &MenuViewDragAndDropTestTestInMenuDrag::Step4));
|
| +}
|
| +
|
| +void MenuViewDragAndDropTestTestInMenuDrag::Step4() {
|
| + // Verify our state.
|
| + // We should have performed an in-menu drop, and the nested view should not
|
| + // have had a drag and drop. Since the drag happened in menu code, the
|
| + // delegate should not have been asked whether or not to close, and the menu
|
| + // should simply be closed.
|
| + EXPECT_TRUE(performed_in_menu_drop());
|
| + EXPECT_FALSE(target_view()->dropped());
|
| + EXPECT_FALSE(asked_to_close());
|
| + EXPECT_FALSE(menu()->GetSubmenu()->IsShowing());
|
| +
|
| + Done();
|
| +}
|
| +
|
| +VIEW_TEST(MenuViewDragAndDropTestTestInMenuDrag, MAYBE(TestInMenuDrag))
|
| +
|
| +class MenuViewDragAndDropTestNestedDrag : public MenuViewDragAndDropTest {
|
| + public:
|
| + MenuViewDragAndDropTestNestedDrag() {}
|
| + virtual ~MenuViewDragAndDropTestNestedDrag() {}
|
| +
|
| + private:
|
| + // MenuViewDragAndDropTest:
|
| + virtual void DoTestWithMenuOpen() OVERRIDE;
|
| +
|
| + void Step2();
|
| + void Step3();
|
| + void Step4();
|
| +};
|
| +
|
| +void MenuViewDragAndDropTestNestedDrag::DoTestWithMenuOpen() {
|
| + // Sanity checks: We should be showing the menu, it should have three
|
| + // children, and the first of those children should have a nested view of the
|
| + // TestTargetView.
|
| + views::SubmenuView* submenu = menu()->GetSubmenu();
|
| + ASSERT_TRUE(submenu);
|
| + ASSERT_TRUE(submenu->IsShowing());
|
| + ASSERT_EQ(3, submenu->GetMenuItemCount());
|
| + views::View* first_view = submenu->GetMenuItemAt(0);
|
| + ASSERT_EQ(1, first_view->child_count());
|
| + views::View* child_view = first_view->child_at(0);
|
| + ASSERT_EQ(child_view, target_view());
|
| +
|
| + // We do this here (instead of in BuildMenu()) so that the menu is already
|
| + // built and the bounds are correct.
|
| + target_view()->Init(submenu->GetMenuItemAt(0));
|
| +
|
| + // The target view should now have two children.
|
| + ASSERT_EQ(2, target_view()->child_count());
|
| +
|
| + views::View* drag_view = target_view()->child_at(0);
|
| + ASSERT_TRUE(drag_view != NULL);
|
| +
|
| + // Move mouse to center of menu and press button.
|
| + ui_test_utils::MoveMouseToCenterAndPress(
|
| + drag_view,
|
| + ui_controls::LEFT,
|
| + ui_controls::DOWN,
|
| + CreateEventTask(this, &MenuViewDragAndDropTestNestedDrag::Step2));
|
| +}
|
| +
|
| +void MenuViewDragAndDropTestNestedDrag::Step2() {
|
| + views::View* drop_target = target_view()->child_at(1);
|
| + gfx::Point loc(2, 0);
|
| + views::View::ConvertPointToScreen(drop_target, &loc);
|
| +
|
| + // Start a drag.
|
| + ui_controls::SendMouseMoveNotifyWhenDone(
|
| + loc.x() + 3,
|
| + loc.y(),
|
| + CreateEventTask(this, &MenuViewDragAndDropTestNestedDrag::Step3));
|
| +
|
| + ScheduleMouseMoveInBackground(loc.x(), loc.y());
|
| +}
|
| +
|
| +void MenuViewDragAndDropTestNestedDrag::Step3() {
|
| + // The view should be dragging now.
|
| + EXPECT_TRUE(target_view()->dragging());
|
| +
|
| + // Drop the item so that it's now the second item.
|
| + views::View* drop_target = target_view()->child_at(1);
|
| + gfx::Point loc(5, 0);
|
| + views::View::ConvertPointToScreen(drop_target, &loc);
|
| + ui_controls::SendMouseMove(loc.x(), loc.y());
|
| +
|
| + ui_controls::SendMouseEventsNotifyWhenDone(
|
| + ui_controls::LEFT,
|
| + ui_controls::UP,
|
| + CreateEventTask(this, &MenuViewDragAndDropTestNestedDrag::Step4));
|
| +}
|
| +
|
| +void MenuViewDragAndDropTestNestedDrag::Step4() {
|
| + // Check our state.
|
| + // The target view should have finished its drag, and should have dropped the
|
| + // view. The main menu should not have done any drag, and the delegate should
|
| + // have been asked if it wanted to close. Since the delegate did not want to
|
| + // close, the menu should still be open.
|
| + EXPECT_FALSE(target_view()->dragging());
|
| + EXPECT_TRUE(target_view()->dropped());
|
| + EXPECT_FALSE(performed_in_menu_drop());
|
| + EXPECT_TRUE(asked_to_close());
|
| + EXPECT_TRUE(menu()->GetSubmenu()->IsShowing());
|
| +
|
| + // Clean up.
|
| + menu()->GetSubmenu()->Close();
|
| +
|
| + Done();
|
| +}
|
| +
|
| +VIEW_TEST(MenuViewDragAndDropTestNestedDrag,
|
| + MAYBE(MenuViewDragAndDropNestedDrag))
|
|
|