Infobar material design refresh: layout
[chromium-blink-merge.git] / chrome / browser / ui / views / menu_view_drag_and_drop_test.cc
blob9e6e484a0f2592cc72a979f73534890ebb45c29d
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/strings/utf_string_conversions.h"
6 #include "chrome/browser/ui/views/menu_test_base.h"
7 #include "chrome/test/base/interactive_test_utils.h"
8 #include "ui/base/dragdrop/drag_drop_types.h"
9 #include "ui/base/dragdrop/os_exchange_data.h"
10 #include "ui/views/controls/menu/menu_controller.h"
11 #include "ui/views/controls/menu/menu_item_view.h"
12 #include "ui/views/controls/menu/menu_runner.h"
13 #include "ui/views/controls/menu/submenu_view.h"
14 #include "ui/views/view.h"
16 namespace {
18 const char kTestNestedDragData[] = "test_nested_drag_data";
19 const char kTestTopLevelDragData[] = "test_top_level_drag_data";
21 // A simple view which can be dragged.
22 class TestDragView : public views::View {
23 public:
24 TestDragView();
25 ~TestDragView() override;
27 private:
28 // views::View:
29 int GetDragOperations(const gfx::Point& point) override;
30 void WriteDragData(const gfx::Point& point,
31 ui::OSExchangeData* data) override;
33 DISALLOW_COPY_AND_ASSIGN(TestDragView);
36 TestDragView::TestDragView() {
39 TestDragView::~TestDragView() {
42 int TestDragView::GetDragOperations(const gfx::Point& point) {
43 return ui::DragDropTypes::DRAG_MOVE;
46 void TestDragView::WriteDragData(const gfx::Point& point,
47 ui::OSExchangeData* data) {
48 data->SetString(base::ASCIIToUTF16(kTestNestedDragData));
51 // A simple view to serve as a drop target.
52 class TestTargetView : public views::View {
53 public:
54 TestTargetView();
55 ~TestTargetView() override;
57 // Initializes this view to have the same bounds as |parent| and two draggable
58 // child views.
59 void Init(views::View* parent);
60 bool dragging() const { return dragging_; }
61 bool dropped() const { return dropped_; }
63 private:
64 // views::View:
65 bool GetDropFormats(
66 int* formats,
67 std::set<OSExchangeData::CustomFormat>* custom_formats) override;
68 bool AreDropTypesRequired() override;
69 bool CanDrop(const OSExchangeData& data) override;
70 void OnDragEntered(const ui::DropTargetEvent& event) override;
71 int OnDragUpdated(const ui::DropTargetEvent& event) override;
72 int OnPerformDrop(const ui::DropTargetEvent& event) override;
73 void OnDragExited() override;
75 // Whether or not we are currently dragging.
76 bool dragging_;
78 // Whether or not a drop has been performed on the view.
79 bool dropped_;
81 DISALLOW_COPY_AND_ASSIGN(TestTargetView);
84 TestTargetView::TestTargetView() : dragging_(false), dropped_(false) {
87 void TestTargetView::Init(views::View* parent) {
88 // First, match the parent's size.
89 SetSize(parent->size());
91 // Then add two draggable views, each 10x2.
92 views::View* first = new TestDragView();
93 AddChildView(first);
94 first->SetBounds(2, 2, 10, 2);
96 views::View* second = new TestDragView();
97 AddChildView(second);
98 second->SetBounds(15, 2, 10, 2);
101 TestTargetView::~TestTargetView() {
104 bool TestTargetView::GetDropFormats(
105 int* formats, std::set<OSExchangeData::CustomFormat>* custom_formats) {
106 *formats = ui::OSExchangeData::STRING;
107 return true;
110 bool TestTargetView::AreDropTypesRequired() {
111 return true;
114 bool TestTargetView::CanDrop(const OSExchangeData& data) {
115 base::string16 contents;
116 return data.GetString(&contents) &&
117 contents == base::ASCIIToUTF16(kTestNestedDragData);
120 void TestTargetView::OnDragEntered(const ui::DropTargetEvent& event) {
121 dragging_ = true;
124 int TestTargetView::OnDragUpdated(const ui::DropTargetEvent& event) {
125 return ui::DragDropTypes::DRAG_MOVE;
128 int TestTargetView::OnPerformDrop(const ui::DropTargetEvent& event) {
129 dragging_ = false;
130 dropped_ = true;
131 return ui::DragDropTypes::DRAG_MOVE;
134 void TestTargetView::OnDragExited() {
135 dragging_ = false;
138 } // namespace
140 class MenuViewDragAndDropTest : public MenuTestBase {
141 public:
142 MenuViewDragAndDropTest();
143 ~MenuViewDragAndDropTest() override;
145 protected:
146 TestTargetView* target_view() { return target_view_; }
147 bool asked_to_close() const { return asked_to_close_; }
148 bool performed_in_menu_drop() const { return performed_in_menu_drop_; }
150 private:
151 // MenuTestBase:
152 void BuildMenu(views::MenuItemView* menu) override;
154 // views::MenuDelegate:
155 bool GetDropFormats(
156 views::MenuItemView* menu,
157 int* formats,
158 std::set<ui::OSExchangeData::CustomFormat>* custom_formats) override;
159 bool AreDropTypesRequired(views::MenuItemView* menu) override;
160 bool CanDrop(views::MenuItemView* menu,
161 const ui::OSExchangeData& data) override;
162 int GetDropOperation(views::MenuItemView* item,
163 const ui::DropTargetEvent& event,
164 DropPosition* position) override;
165 int OnPerformDrop(views::MenuItemView* menu,
166 DropPosition position,
167 const ui::DropTargetEvent& event) override;
168 bool CanDrag(views::MenuItemView* menu) override;
169 void WriteDragData(views::MenuItemView* sender,
170 ui::OSExchangeData* data) override;
171 int GetDragOperations(views::MenuItemView* sender) override;
172 bool ShouldCloseOnDragComplete() override;
174 // The special view in the menu, which supports its own drag and drop.
175 TestTargetView* target_view_;
177 // Whether or not we have been asked to close on drag complete.
178 bool asked_to_close_;
180 // Whether or not a drop was performed in-menu (i.e., not including drops
181 // in separate child views).
182 bool performed_in_menu_drop_;
184 DISALLOW_COPY_AND_ASSIGN(MenuViewDragAndDropTest);
187 MenuViewDragAndDropTest::MenuViewDragAndDropTest()
188 : target_view_(NULL),
189 asked_to_close_(false),
190 performed_in_menu_drop_(false) {
193 MenuViewDragAndDropTest::~MenuViewDragAndDropTest() {
196 void MenuViewDragAndDropTest::BuildMenu(views::MenuItemView* menu) {
197 // Build a menu item that has a nested view that supports its own drag and
198 // drop...
199 views::MenuItemView* menu_item_view =
200 menu->AppendMenuItem(1,
201 base::ASCIIToUTF16("item 1"),
202 views::MenuItemView::NORMAL);
203 target_view_ = new TestTargetView();
204 menu_item_view->AddChildView(target_view_);
205 // ... as well as two other, normal items.
206 menu->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("item 2"));
207 menu->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("item 3"));
210 bool MenuViewDragAndDropTest::GetDropFormats(
211 views::MenuItemView* menu,
212 int* formats,
213 std::set<ui::OSExchangeData::CustomFormat>* custom_formats) {
214 *formats = ui::OSExchangeData::STRING;
215 return true;
218 bool MenuViewDragAndDropTest::AreDropTypesRequired(views::MenuItemView* menu) {
219 return true;
222 bool MenuViewDragAndDropTest::CanDrop(views::MenuItemView* menu,
223 const ui::OSExchangeData& data) {
224 base::string16 contents;
225 return data.GetString(&contents) &&
226 contents == base::ASCIIToUTF16(kTestTopLevelDragData);
229 int MenuViewDragAndDropTest::GetDropOperation(views::MenuItemView* item,
230 const ui::DropTargetEvent& event,
231 DropPosition* position) {
232 return ui::DragDropTypes::DRAG_MOVE;
236 int MenuViewDragAndDropTest::OnPerformDrop(views::MenuItemView* menu,
237 DropPosition position,
238 const ui::DropTargetEvent& event) {
239 performed_in_menu_drop_ = true;
240 return ui::DragDropTypes::DRAG_MOVE;
243 bool MenuViewDragAndDropTest::CanDrag(views::MenuItemView* menu) {
244 return true;
247 void MenuViewDragAndDropTest::WriteDragData(
248 views::MenuItemView* sender, ui::OSExchangeData* data) {
249 data->SetString(base::ASCIIToUTF16(kTestTopLevelDragData));
252 int MenuViewDragAndDropTest::GetDragOperations(views::MenuItemView* sender) {
253 return ui::DragDropTypes::DRAG_MOVE;
256 bool MenuViewDragAndDropTest::ShouldCloseOnDragComplete() {
257 asked_to_close_ = true;
258 return false;
261 class MenuViewDragAndDropTestTestInMenuDrag : public MenuViewDragAndDropTest {
262 public:
263 MenuViewDragAndDropTestTestInMenuDrag() {}
264 ~MenuViewDragAndDropTestTestInMenuDrag() override {}
266 private:
267 // MenuViewDragAndDropTest:
268 void DoTestWithMenuOpen() override;
270 void Step2();
271 void Step3();
272 void Step4();
275 void MenuViewDragAndDropTestTestInMenuDrag::DoTestWithMenuOpen() {
276 // A few sanity checks to make sure the menu built correctly.
277 views::SubmenuView* submenu = menu()->GetSubmenu();
278 ASSERT_TRUE(submenu);
279 ASSERT_TRUE(submenu->IsShowing());
280 ASSERT_EQ(3, submenu->GetMenuItemCount());
282 // We do this here (instead of in BuildMenu()) so that the menu is already
283 // built and the bounds are correct.
284 target_view()->Init(submenu->GetMenuItemAt(0));
286 // We're going to drag the second menu element.
287 views::MenuItemView* drag_view = submenu->GetMenuItemAt(1);
288 ASSERT_TRUE(drag_view != NULL);
290 // Move mouse to center of menu and press button.
291 ui_test_utils::MoveMouseToCenterAndPress(
292 drag_view,
293 ui_controls::LEFT,
294 ui_controls::DOWN,
295 CreateEventTask(this, &MenuViewDragAndDropTestTestInMenuDrag::Step2));
298 void MenuViewDragAndDropTestTestInMenuDrag::Step2() {
299 views::MenuItemView* drop_target = menu()->GetSubmenu()->GetMenuItemAt(2);
300 gfx::Point loc(1, drop_target->height() - 1);
301 views::View::ConvertPointToScreen(drop_target, &loc);
303 // Start a drag.
304 ui_controls::SendMouseMoveNotifyWhenDone(
305 loc.x() + 10,
306 loc.y(),
307 CreateEventTask(this, &MenuViewDragAndDropTestTestInMenuDrag::Step3));
309 ScheduleMouseMoveInBackground(loc.x(), loc.y());
312 void MenuViewDragAndDropTestTestInMenuDrag::Step3() {
313 // Drop the item on the target.
314 views::MenuItemView* drop_target = menu()->GetSubmenu()->GetMenuItemAt(2);
315 gfx::Point loc(1, drop_target->height() - 2);
316 views::View::ConvertPointToScreen(drop_target, &loc);
317 ui_controls::SendMouseMove(loc.x(), loc.y());
319 ui_controls::SendMouseEventsNotifyWhenDone(
320 ui_controls::LEFT,
321 ui_controls::UP,
322 CreateEventTask(this, &MenuViewDragAndDropTestTestInMenuDrag::Step4));
325 void MenuViewDragAndDropTestTestInMenuDrag::Step4() {
326 // Verify our state.
327 // We should have performed an in-menu drop, and the nested view should not
328 // have had a drag and drop. Since the drag happened in menu code, the
329 // delegate should not have been asked whether or not to close, and the menu
330 // should simply be closed.
331 EXPECT_TRUE(performed_in_menu_drop());
332 EXPECT_FALSE(target_view()->dropped());
333 EXPECT_FALSE(asked_to_close());
334 EXPECT_FALSE(menu()->GetSubmenu()->IsShowing());
336 Done();
339 // Test that an in-menu (i.e., entirely implemented in the menu code) closes the
340 // menu automatically once the drag is complete, and does not ask the delegate
341 // to stay open.
342 // Disabled on all platforms for being flaky. Tracked in:
343 // TODO(erg): Fix DND tests on linux_aura. http://crbug.com/163931.
344 // Windows: http://crbug.com/401226.
345 // TODO(tapted): De-flake and run on Mac. http://crbug.com/449058.
346 VIEW_TEST(MenuViewDragAndDropTestTestInMenuDrag, DISABLED_TestInMenuDrag)
348 class MenuViewDragAndDropTestNestedDrag : public MenuViewDragAndDropTest {
349 public:
350 MenuViewDragAndDropTestNestedDrag() {}
351 ~MenuViewDragAndDropTestNestedDrag() override {}
353 private:
354 // MenuViewDragAndDropTest:
355 void DoTestWithMenuOpen() override;
357 void Step2();
358 void Step3();
359 void Step4();
362 void MenuViewDragAndDropTestNestedDrag::DoTestWithMenuOpen() {
363 // Sanity checks: We should be showing the menu, it should have three
364 // children, and the first of those children should have a nested view of the
365 // TestTargetView.
366 views::SubmenuView* submenu = menu()->GetSubmenu();
367 ASSERT_TRUE(submenu);
368 ASSERT_TRUE(submenu->IsShowing());
369 ASSERT_EQ(3, submenu->GetMenuItemCount());
370 views::View* first_view = submenu->GetMenuItemAt(0);
371 ASSERT_EQ(1, first_view->child_count());
372 views::View* child_view = first_view->child_at(0);
373 ASSERT_EQ(child_view, target_view());
375 // We do this here (instead of in BuildMenu()) so that the menu is already
376 // built and the bounds are correct.
377 target_view()->Init(submenu->GetMenuItemAt(0));
379 // The target view should now have two children.
380 ASSERT_EQ(2, target_view()->child_count());
382 views::View* drag_view = target_view()->child_at(0);
383 ASSERT_TRUE(drag_view != NULL);
385 // Move mouse to center of menu and press button.
386 ui_test_utils::MoveMouseToCenterAndPress(
387 drag_view,
388 ui_controls::LEFT,
389 ui_controls::DOWN,
390 CreateEventTask(this, &MenuViewDragAndDropTestNestedDrag::Step2));
393 void MenuViewDragAndDropTestNestedDrag::Step2() {
394 views::View* drop_target = target_view()->child_at(1);
395 gfx::Point loc(2, 0);
396 views::View::ConvertPointToScreen(drop_target, &loc);
398 // Start a drag.
399 ui_controls::SendMouseMoveNotifyWhenDone(
400 loc.x() + 3,
401 loc.y(),
402 CreateEventTask(this, &MenuViewDragAndDropTestNestedDrag::Step3));
404 ScheduleMouseMoveInBackground(loc.x(), loc.y());
407 void MenuViewDragAndDropTestNestedDrag::Step3() {
408 // The view should be dragging now.
409 EXPECT_TRUE(target_view()->dragging());
411 // Drop the item so that it's now the second item.
412 views::View* drop_target = target_view()->child_at(1);
413 gfx::Point loc(5, 0);
414 views::View::ConvertPointToScreen(drop_target, &loc);
415 ui_controls::SendMouseMove(loc.x(), loc.y());
417 ui_controls::SendMouseEventsNotifyWhenDone(
418 ui_controls::LEFT,
419 ui_controls::UP,
420 CreateEventTask(this, &MenuViewDragAndDropTestNestedDrag::Step4));
423 void MenuViewDragAndDropTestNestedDrag::Step4() {
424 // Check our state.
425 // The target view should have finished its drag, and should have dropped the
426 // view. The main menu should not have done any drag, and the delegate should
427 // have been asked if it wanted to close. Since the delegate did not want to
428 // close, the menu should still be open.
429 EXPECT_FALSE(target_view()->dragging());
430 EXPECT_TRUE(target_view()->dropped());
431 EXPECT_FALSE(performed_in_menu_drop());
432 EXPECT_TRUE(asked_to_close());
433 EXPECT_TRUE(menu()->GetSubmenu()->IsShowing());
435 // Clean up.
436 menu()->GetSubmenu()->Close();
438 Done();
441 // Test that a nested drag (i.e. one via a child view, and not entirely
442 // implemented in menu code) will consult the delegate before closing the view
443 // after the drag.
444 // Disabled on all platforms for being flaky. Tracked in:
445 // TODO(erg): Fix DND tests on linux_aura. http://crbug.com/163931.
446 // Windows: http://crbug.com/401226.
447 // TODO(tapted): De-flake and run on Mac. http://crbug.com/449058.
448 VIEW_TEST(MenuViewDragAndDropTestNestedDrag,
449 DISABLED_MenuViewDragAndDropNestedDrag)
451 class MenuViewDragAndDropForDropStayOpen : public MenuViewDragAndDropTest {
452 public:
453 MenuViewDragAndDropForDropStayOpen() {}
454 ~MenuViewDragAndDropForDropStayOpen() override {}
456 private:
457 // MenuViewDragAndDropTest:
458 int GetMenuRunnerFlags() override;
459 void DoTestWithMenuOpen() override;
462 int MenuViewDragAndDropForDropStayOpen::GetMenuRunnerFlags() {
463 return views::MenuRunner::HAS_MNEMONICS |
464 views::MenuRunner::NESTED_DRAG |
465 views::MenuRunner::FOR_DROP;
468 void MenuViewDragAndDropForDropStayOpen::DoTestWithMenuOpen() {
469 views::SubmenuView* submenu = menu()->GetSubmenu();
470 ASSERT_TRUE(submenu);
471 ASSERT_TRUE(submenu->IsShowing());
473 views::MenuController* controller = menu()->GetMenuController();
474 ASSERT_TRUE(controller);
475 EXPECT_FALSE(controller->IsCancelAllTimerRunningForTest());
477 Done();
480 #if defined(OS_WIN)
481 // flaky on Windows - http://crbug.com/523255
482 #define MAYBE_MenuViewStaysOpenForNestedDrag DISABLED_MenuViewStaysOpenForNestedDrag
483 #else
484 #define MAYBE_MenuViewStaysOpenForNestedDrag MenuViewStaysOpenForNestedDrag
485 #endif
486 // Test that if a menu is opened for a drop which is handled by a child view
487 // that the menu does not immediately try to close.
488 VIEW_TEST(MenuViewDragAndDropForDropStayOpen,
489 MAYBE_MenuViewStaysOpenForNestedDrag)
491 class MenuViewDragAndDropForDropCancel : public MenuViewDragAndDropTest {
492 public:
493 MenuViewDragAndDropForDropCancel() {}
494 ~MenuViewDragAndDropForDropCancel() override {}
496 private:
497 // MenuViewDragAndDropTest:
498 int GetMenuRunnerFlags() override;
499 void DoTestWithMenuOpen() override;
502 int MenuViewDragAndDropForDropCancel::GetMenuRunnerFlags() {
503 return views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::FOR_DROP;
506 void MenuViewDragAndDropForDropCancel::DoTestWithMenuOpen() {
507 views::SubmenuView* submenu = menu()->GetSubmenu();
508 ASSERT_TRUE(submenu);
509 ASSERT_TRUE(submenu->IsShowing());
511 views::MenuController* controller = menu()->GetMenuController();
512 ASSERT_TRUE(controller);
513 EXPECT_TRUE(controller->IsCancelAllTimerRunningForTest());
515 Done();
518 // Test that if a menu is opened for a drop handled entirely by menu code, the
519 // menu will try to close if it does not receive any drag updates.
520 VIEW_TEST(MenuViewDragAndDropForDropCancel, MenuViewCancelsForOwnDrag)