menu_view_drag_and_drop_test.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/menu_test_base.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/base/interactive_test_utils.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/base/dragdrop/drag_drop_types.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/dragdrop/os_exchange_data.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_controller.h"
117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ui/views/controls/menu/menu_item_view.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/views/controls/menu/menu_runner.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/submenu_view.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/view.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Borrowed from chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc,
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// since these are also disabled on Linux for drag and drop.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(erg): Fix DND tests on linux_aura. crbug.com/163931
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX) && defined(USE_AURA)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAYBE(x) DISABLED_##x
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAYBE(x) x
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kTestNestedDragData[] = "test_nested_drag_data";
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kTestTopLevelDragData[] = "test_top_level_drag_data";
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A simple view which can be dragged.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TestDragView : public views::View {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TestDragView();
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~TestDragView();
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views::View:
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual int GetDragOperations(const gfx::Point& point) OVERRIDE;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void WriteDragData(const gfx::Point& point,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             ui::OSExchangeData* data) OVERRIDE;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TestDragView);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TestDragView::TestDragView() {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TestDragView::~TestDragView() {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TestDragView::GetDragOperations(const gfx::Point& point) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::DragDropTypes::DRAG_MOVE;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestDragView::WriteDragData(const gfx::Point& point,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 ui::OSExchangeData* data) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data->SetString(base::ASCIIToUTF16(kTestNestedDragData));
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A simple view to serve as a drop target.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TestTargetView : public views::View {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TestTargetView();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~TestTargetView();
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initializes this view to have the same bounds as |parent| and two draggable
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // child views.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Init(views::View* parent);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool dragging() const { return dragging_; }
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool dropped() const { return dropped_; }
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views::View:
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetDropFormats(
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int* formats,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::set<OSExchangeData::CustomFormat>* custom_formats) OVERRIDE;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool AreDropTypesRequired() OVERRIDE;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool CanDrop(const OSExchangeData& data) OVERRIDE;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnDragEntered(const ui::DropTargetEvent& event) OVERRIDE;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnDragExited() OVERRIDE;
83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Whether or not we are currently dragging.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool dragging_;
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Whether or not a drop has been performed on the view.
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool dropped_;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TestTargetView);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TestTargetView::TestTargetView() : dragging_(false), dropped_(false) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestTargetView::Init(views::View* parent) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First, match the parent's size.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetSize(parent->size());
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Then add two draggable views, each 10x2.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* first = new TestDragView();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(first);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  first->SetBounds(2, 2, 10, 2);
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* second = new TestDragView();
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(second);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  second->SetBounds(15, 2, 10, 2);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TestTargetView::~TestTargetView() {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TestTargetView::GetDropFormats(
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int* formats, std::set<OSExchangeData::CustomFormat>* custom_formats) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *formats = ui::OSExchangeData::STRING;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TestTargetView::AreDropTypesRequired() {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TestTargetView::CanDrop(const OSExchangeData& data) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::string16 contents;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return data.GetString(&contents) &&
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         contents == base::ASCIIToUTF16(kTestNestedDragData);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestTargetView::OnDragEntered(const ui::DropTargetEvent& event) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dragging_ = true;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochint TestTargetView::OnDragUpdated(const ui::DropTargetEvent& event) {
1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return ui::DragDropTypes::DRAG_MOVE;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TestTargetView::OnPerformDrop(const ui::DropTargetEvent& event) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dragging_ = false;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dropped_ = true;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::DragDropTypes::DRAG_MOVE;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestTargetView::OnDragExited() {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dragging_ = false;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MenuViewDragAndDropTest : public MenuTestBase {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MenuViewDragAndDropTest();
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~MenuViewDragAndDropTest();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) protected:
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TestTargetView* target_view() { return target_view_; }
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool asked_to_close() const { return asked_to_close_; }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool performed_in_menu_drop() const { return performed_in_menu_drop_; }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // MenuTestBase:
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void BuildMenu(views::MenuItemView* menu) OVERRIDE;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views::MenuDelegate:
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetDropFormats(
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      views::MenuItemView* menu,
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int* formats,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::set<ui::OSExchangeData::CustomFormat>* custom_formats) OVERRIDE;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool AreDropTypesRequired(views::MenuItemView* menu) OVERRIDE;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool CanDrop(views::MenuItemView* menu,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const ui::OSExchangeData& data) OVERRIDE;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual int GetDropOperation(views::MenuItemView* item,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const ui::DropTargetEvent& event,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               DropPosition* position) OVERRIDE;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual int OnPerformDrop(views::MenuItemView* menu,
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            DropPosition position,
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            const ui::DropTargetEvent& event) OVERRIDE;
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual bool CanDrag(views::MenuItemView* menu) OVERRIDE;
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void WriteDragData(views::MenuItemView* sender,
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             ui::OSExchangeData* data) OVERRIDE;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual int GetDragOperations(views::MenuItemView* sender) OVERRIDE;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool ShouldCloseOnDragComplete() OVERRIDE;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The special view in the menu, which supports its own drag and drop.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TestTargetView* target_view_;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Whether or not we have been asked to close on drag complete.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool asked_to_close_;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Whether or not a drop was performed in-menu (i.e., not including drops
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in separate child views).
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool performed_in_menu_drop_;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MenuViewDragAndDropTest);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MenuViewDragAndDropTest::MenuViewDragAndDropTest()
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : target_view_(NULL),
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      asked_to_close_(false),
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      performed_in_menu_drop_(false) {
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MenuViewDragAndDropTest::~MenuViewDragAndDropTest() {
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MenuViewDragAndDropTest::BuildMenu(views::MenuItemView* menu) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Build a menu item that has a nested view that supports its own drag and
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // drop...
208  views::MenuItemView* menu_item_view =
209      menu->AppendMenuItem(1,
210                           base::ASCIIToUTF16("item 1"),
211                           views::MenuItemView::NORMAL);
212  target_view_ = new TestTargetView();
213  menu_item_view->AddChildView(target_view_);
214  // ... as well as two other, normal items.
215  menu->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("item 2"));
216  menu->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("item 3"));
217}
218
219bool MenuViewDragAndDropTest::GetDropFormats(
220    views::MenuItemView* menu,
221    int* formats,
222    std::set<ui::OSExchangeData::CustomFormat>* custom_formats) {
223  *formats = ui::OSExchangeData::STRING;
224  return true;
225}
226
227bool MenuViewDragAndDropTest::AreDropTypesRequired(views::MenuItemView* menu) {
228  return true;
229}
230
231bool MenuViewDragAndDropTest::CanDrop(views::MenuItemView* menu,
232                                      const ui::OSExchangeData& data) {
233  base::string16 contents;
234  return data.GetString(&contents) &&
235         contents == base::ASCIIToUTF16(kTestTopLevelDragData);
236}
237
238int MenuViewDragAndDropTest::GetDropOperation(views::MenuItemView* item,
239                                              const ui::DropTargetEvent& event,
240                                              DropPosition* position) {
241  return ui::DragDropTypes::DRAG_MOVE;
242}
243
244
245int MenuViewDragAndDropTest::OnPerformDrop(views::MenuItemView* menu,
246                                           DropPosition position,
247                                           const ui::DropTargetEvent& event) {
248  performed_in_menu_drop_ = true;
249  return ui::DragDropTypes::DRAG_MOVE;
250}
251
252bool MenuViewDragAndDropTest::CanDrag(views::MenuItemView* menu) {
253  return true;
254}
255
256void MenuViewDragAndDropTest::WriteDragData(
257    views::MenuItemView* sender, ui::OSExchangeData* data) {
258  data->SetString(base::ASCIIToUTF16(kTestTopLevelDragData));
259}
260
261int MenuViewDragAndDropTest::GetDragOperations(views::MenuItemView* sender) {
262  return ui::DragDropTypes::DRAG_MOVE;
263}
264
265bool MenuViewDragAndDropTest::ShouldCloseOnDragComplete() {
266  asked_to_close_ = true;
267  return false;
268}
269
270class MenuViewDragAndDropTestTestInMenuDrag : public MenuViewDragAndDropTest {
271 public:
272  MenuViewDragAndDropTestTestInMenuDrag() {}
273  virtual ~MenuViewDragAndDropTestTestInMenuDrag() {}
274
275 private:
276  // MenuViewDragAndDropTest:
277  virtual void DoTestWithMenuOpen() OVERRIDE;
278
279  void Step2();
280  void Step3();
281  void Step4();
282};
283
284void MenuViewDragAndDropTestTestInMenuDrag::DoTestWithMenuOpen() {
285  // A few sanity checks to make sure the menu built correctly.
286  views::SubmenuView* submenu = menu()->GetSubmenu();
287  ASSERT_TRUE(submenu);
288  ASSERT_TRUE(submenu->IsShowing());
289  ASSERT_EQ(3, submenu->GetMenuItemCount());
290
291  // We do this here (instead of in BuildMenu()) so that the menu is already
292  // built and the bounds are correct.
293  target_view()->Init(submenu->GetMenuItemAt(0));
294
295  // We're going to drag the second menu element.
296  views::MenuItemView* drag_view = submenu->GetMenuItemAt(1);
297  ASSERT_TRUE(drag_view != NULL);
298
299  // Move mouse to center of menu and press button.
300  ui_test_utils::MoveMouseToCenterAndPress(
301      drag_view,
302      ui_controls::LEFT,
303      ui_controls::DOWN,
304      CreateEventTask(this, &MenuViewDragAndDropTestTestInMenuDrag::Step2));
305}
306
307void MenuViewDragAndDropTestTestInMenuDrag::Step2() {
308  views::MenuItemView* drop_target = menu()->GetSubmenu()->GetMenuItemAt(2);
309  gfx::Point loc(1, drop_target->height() - 1);
310  views::View::ConvertPointToScreen(drop_target, &loc);
311
312  // Start a drag.
313  ui_controls::SendMouseMoveNotifyWhenDone(
314      loc.x() + 10,
315      loc.y(),
316      CreateEventTask(this, &MenuViewDragAndDropTestTestInMenuDrag::Step3));
317
318  ScheduleMouseMoveInBackground(loc.x(), loc.y());
319}
320
321void MenuViewDragAndDropTestTestInMenuDrag::Step3() {
322  // Drop the item on the target.
323  views::MenuItemView* drop_target = menu()->GetSubmenu()->GetMenuItemAt(2);
324  gfx::Point loc(1, drop_target->height() - 2);
325  views::View::ConvertPointToScreen(drop_target, &loc);
326  ui_controls::SendMouseMove(loc.x(), loc.y());
327
328  ui_controls::SendMouseEventsNotifyWhenDone(
329      ui_controls::LEFT,
330      ui_controls::UP,
331      CreateEventTask(this, &MenuViewDragAndDropTestTestInMenuDrag::Step4));
332}
333
334void MenuViewDragAndDropTestTestInMenuDrag::Step4() {
335  // Verify our state.
336  // We should have performed an in-menu drop, and the nested view should not
337  // have had a drag and drop. Since the drag happened in menu code, the
338  // delegate should not have been asked whether or not to close, and the menu
339  // should simply be closed.
340  EXPECT_TRUE(performed_in_menu_drop());
341  EXPECT_FALSE(target_view()->dropped());
342  EXPECT_FALSE(asked_to_close());
343  EXPECT_FALSE(menu()->GetSubmenu()->IsShowing());
344
345  Done();
346}
347
348// Test that an in-menu (i.e., entirely implemented in the menu code) closes the
349// menu automatically once the drag is complete, and does not ask the delegate
350// to stay open.
351VIEW_TEST(MenuViewDragAndDropTestTestInMenuDrag, MAYBE(TestInMenuDrag))
352
353class MenuViewDragAndDropTestNestedDrag : public MenuViewDragAndDropTest {
354 public:
355  MenuViewDragAndDropTestNestedDrag() {}
356  virtual ~MenuViewDragAndDropTestNestedDrag() {}
357
358 private:
359  // MenuViewDragAndDropTest:
360  virtual void DoTestWithMenuOpen() OVERRIDE;
361
362  void Step2();
363  void Step3();
364  void Step4();
365};
366
367void MenuViewDragAndDropTestNestedDrag::DoTestWithMenuOpen() {
368  // Sanity checks: We should be showing the menu, it should have three
369  // children, and the first of those children should have a nested view of the
370  // TestTargetView.
371  views::SubmenuView* submenu = menu()->GetSubmenu();
372  ASSERT_TRUE(submenu);
373  ASSERT_TRUE(submenu->IsShowing());
374  ASSERT_EQ(3, submenu->GetMenuItemCount());
375  views::View* first_view = submenu->GetMenuItemAt(0);
376  ASSERT_EQ(1, first_view->child_count());
377  views::View* child_view = first_view->child_at(0);
378  ASSERT_EQ(child_view, target_view());
379
380  // We do this here (instead of in BuildMenu()) so that the menu is already
381  // built and the bounds are correct.
382  target_view()->Init(submenu->GetMenuItemAt(0));
383
384  // The target view should now have two children.
385  ASSERT_EQ(2, target_view()->child_count());
386
387  views::View* drag_view = target_view()->child_at(0);
388  ASSERT_TRUE(drag_view != NULL);
389
390  // Move mouse to center of menu and press button.
391  ui_test_utils::MoveMouseToCenterAndPress(
392      drag_view,
393      ui_controls::LEFT,
394      ui_controls::DOWN,
395      CreateEventTask(this, &MenuViewDragAndDropTestNestedDrag::Step2));
396}
397
398void MenuViewDragAndDropTestNestedDrag::Step2() {
399  views::View* drop_target = target_view()->child_at(1);
400  gfx::Point loc(2, 0);
401  views::View::ConvertPointToScreen(drop_target, &loc);
402
403  // Start a drag.
404  ui_controls::SendMouseMoveNotifyWhenDone(
405      loc.x() + 3,
406      loc.y(),
407      CreateEventTask(this, &MenuViewDragAndDropTestNestedDrag::Step3));
408
409  ScheduleMouseMoveInBackground(loc.x(), loc.y());
410}
411
412void MenuViewDragAndDropTestNestedDrag::Step3() {
413  // The view should be dragging now.
414  EXPECT_TRUE(target_view()->dragging());
415
416  // Drop the item so that it's now the second item.
417  views::View* drop_target = target_view()->child_at(1);
418  gfx::Point loc(5, 0);
419  views::View::ConvertPointToScreen(drop_target, &loc);
420  ui_controls::SendMouseMove(loc.x(), loc.y());
421
422  ui_controls::SendMouseEventsNotifyWhenDone(
423      ui_controls::LEFT,
424      ui_controls::UP,
425      CreateEventTask(this, &MenuViewDragAndDropTestNestedDrag::Step4));
426}
427
428void MenuViewDragAndDropTestNestedDrag::Step4() {
429  // Check our state.
430  // The target view should have finished its drag, and should have dropped the
431  // view. The main menu should not have done any drag, and the delegate should
432  // have been asked if it wanted to close. Since the delegate did not want to
433  // close, the menu should still be open.
434  EXPECT_FALSE(target_view()->dragging());
435  EXPECT_TRUE(target_view()->dropped());
436  EXPECT_FALSE(performed_in_menu_drop());
437  EXPECT_TRUE(asked_to_close());
438  EXPECT_TRUE(menu()->GetSubmenu()->IsShowing());
439
440  // Clean up.
441  menu()->GetSubmenu()->Close();
442
443  Done();
444}
445
446// Test that a nested drag (i.e. one via a child view, and not entirely
447// implemented in menu code) will consult the delegate before closing the view
448// after the drag.
449VIEW_TEST(MenuViewDragAndDropTestNestedDrag,
450          MAYBE(MenuViewDragAndDropNestedDrag))
451
452class MenuViewDragAndDropForDropStayOpen : public MenuViewDragAndDropTest {
453 public:
454  MenuViewDragAndDropForDropStayOpen() {}
455  virtual ~MenuViewDragAndDropForDropStayOpen() {}
456
457 private:
458  // MenuViewDragAndDropTest:
459  virtual int GetMenuRunnerFlags() OVERRIDE;
460  virtual void DoTestWithMenuOpen() OVERRIDE;
461};
462
463int MenuViewDragAndDropForDropStayOpen::GetMenuRunnerFlags() {
464  return views::MenuRunner::HAS_MNEMONICS |
465         views::MenuRunner::NESTED_DRAG |
466         views::MenuRunner::FOR_DROP;
467}
468
469void MenuViewDragAndDropForDropStayOpen::DoTestWithMenuOpen() {
470  views::SubmenuView* submenu = menu()->GetSubmenu();
471  ASSERT_TRUE(submenu);
472  ASSERT_TRUE(submenu->IsShowing());
473
474  views::MenuController* controller = menu()->GetMenuController();
475  ASSERT_TRUE(controller);
476  EXPECT_FALSE(controller->IsCancelAllTimerRunningForTest());
477
478  Done();
479}
480
481// Test that if a menu is opened for a drop which is handled by a child view
482// that the menu does not immediately try to close.
483VIEW_TEST(MenuViewDragAndDropForDropStayOpen, MenuViewStaysOpenForNestedDrag)
484
485class MenuViewDragAndDropForDropCancel : public MenuViewDragAndDropTest {
486 public:
487  MenuViewDragAndDropForDropCancel() {}
488  virtual ~MenuViewDragAndDropForDropCancel() {}
489
490 private:
491  // MenuViewDragAndDropTest:
492  virtual int GetMenuRunnerFlags() OVERRIDE;
493  virtual void DoTestWithMenuOpen() OVERRIDE;
494};
495
496int MenuViewDragAndDropForDropCancel::GetMenuRunnerFlags() {
497  return views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::FOR_DROP;
498}
499
500void MenuViewDragAndDropForDropCancel::DoTestWithMenuOpen() {
501  views::SubmenuView* submenu = menu()->GetSubmenu();
502  ASSERT_TRUE(submenu);
503  ASSERT_TRUE(submenu->IsShowing());
504
505  views::MenuController* controller = menu()->GetMenuController();
506  ASSERT_TRUE(controller);
507  EXPECT_TRUE(controller->IsCancelAllTimerRunningForTest());
508
509  Done();
510}
511
512// Test that if a menu is opened for a drop handled entirely by menu code, the
513// menu will try to close if it does not receive any drag updates.
514VIEW_TEST(MenuViewDragAndDropForDropCancel, MenuViewCancelsForOwnDrag)
515