1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file.
4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/app_list/views/app_list_main_view.h"
6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/run_loop.h"
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/time/time.h"
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/timer/timer.h"
11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/app_list/test/app_list_test_model.h"
13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/app_list/test/app_list_test_view_delegate.h"
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/app_list/views/app_list_folder_view.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/app_list/views/app_list_item_view.h"
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/app_list/views/apps_container_view.h"
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/app_list/views/apps_grid_view.h"
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/app_list/views/contents_view.h"
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/app_list/views/test/apps_grid_view_test_api.h"
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/test/views_test_base.h"
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/view_model.h"
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/widget/widget.h"
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace app_list {
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace test {
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace {
28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kInitialItems = 2;
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class GridViewVisibleWaiter {
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) public:
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  explicit GridViewVisibleWaiter(AppsGridView* grid_view)
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      : grid_view_(grid_view) {}
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ~GridViewVisibleWaiter() {}
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void Wait() {
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (grid_view_->visible())
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return;
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    check_timer_.Start(FROM_HERE,
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                       base::TimeDelta::FromMilliseconds(50),
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                       base::Bind(&GridViewVisibleWaiter::OnTimerCheck,
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                  base::Unretained(this)));
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    run_loop_.reset(new base::RunLoop);
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    run_loop_->Run();
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    check_timer_.Stop();
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private:
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void OnTimerCheck() {
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (grid_view_->visible())
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      run_loop_->Quit();
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AppsGridView* grid_view_;
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<base::RunLoop> run_loop_;
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::RepeatingTimer<GridViewVisibleWaiter> check_timer_;
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(GridViewVisibleWaiter);
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class AppListMainViewTest : public views::ViewsTestBase {
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public:
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  AppListMainViewTest()
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      : widget_(NULL),
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        main_view_(NULL) {}
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual ~AppListMainViewTest() {}
70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // testing::Test overrides:
72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void SetUp() OVERRIDE {
73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    views::ViewsTestBase::SetUp();
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    delegate_.reset(new AppListTestViewDelegate);
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // In Ash, the third argument is a container aura::Window, but it is always
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // NULL on Windows, and not needed for tests. It is only used to determine
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // the scale factor for preloading icons.
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    main_view_ = new AppListMainView(delegate_.get(), 0, NULL);
80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    main_view_->SetPaintToLayer(true);
8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    main_view_->model()->SetFoldersEnabled(true);
82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    widget_ = new views::Widget;
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    views::Widget::InitParams params =
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        CreateParams(views::Widget::InitParams::TYPE_POPUP);
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    params.bounds.set_size(main_view_->GetPreferredSize());
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    widget_->Init(params);
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    widget_->SetContentsView(main_view_);
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void TearDown() OVERRIDE {
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    widget_->Close();
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    views::ViewsTestBase::TearDown();
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    delegate_.reset();
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |point| is in |grid_view|'s coordinates.
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AppListItemView* GetItemViewAtPointInGrid(AppsGridView* grid_view,
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                            const gfx::Point& point) {
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const views::ViewModel* view_model = grid_view->view_model_for_test();
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for (int i = 0; i < view_model->view_size(); ++i) {
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      views::View* view = view_model->view_at(i);
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (view->bounds().Contains(point)) {
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return static_cast<AppListItemView*>(view);
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return NULL;
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SimulateClick(views::View* view) {
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    gfx::Point center = view->GetLocalBounds().CenterPoint();
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    view->OnMousePressed(ui::MouseEvent(ui::ET_MOUSE_PRESSED,
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                        center,
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                        center,
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                        ui::EF_LEFT_MOUSE_BUTTON,
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                        ui::EF_LEFT_MOUSE_BUTTON));
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    view->OnMouseReleased(ui::MouseEvent(ui::ET_MOUSE_RELEASED,
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                         center,
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                         center,
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                         ui::EF_LEFT_MOUSE_BUTTON,
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                         ui::EF_LEFT_MOUSE_BUTTON));
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |point| is in |grid_view|'s coordinates.
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AppListItemView* SimulateInitiateDrag(AppsGridView* grid_view,
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                        AppsGridView::Pointer pointer,
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                        const gfx::Point& point) {
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    AppListItemView* view = GetItemViewAtPointInGrid(grid_view, point);
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DCHECK(view);
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    gfx::Point translated =
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        gfx::PointAtOffsetFromOrigin(point - view->bounds().origin());
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED, translated, point, 0, 0);
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    grid_view->InitiateDrag(view, pointer, pressed_event);
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return view;
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |point| is in |grid_view|'s coordinates.
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SimulateUpdateDrag(AppsGridView* grid_view,
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          AppsGridView::Pointer pointer,
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          AppListItemView* drag_view,
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          const gfx::Point& point) {
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DCHECK(drag_view);
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    gfx::Point translated =
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        gfx::PointAtOffsetFromOrigin(point - drag_view->bounds().origin());
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, translated, point, 0, 0);
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    grid_view->UpdateDragFromItem(pointer, drag_event);
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AppsGridView* RootGridView() {
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return main_view_->contents_view()->apps_container_view()->apps_grid_view();
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AppListFolderView* FolderView() {
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return main_view_->contents_view()
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        ->apps_container_view()
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        ->app_list_folder_view();
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AppsGridView* FolderGridView() { return FolderView()->items_grid_view(); }
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const views::ViewModel* RootViewModel() {
165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return RootGridView()->view_model_for_test();
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const views::ViewModel* FolderViewModel() {
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return FolderGridView()->view_model_for_test();
170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  AppListItemView* CreateAndOpenSingleItemFolder() {
1736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Prepare single folder with a single item in it.
1746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    AppListFolderItem* folder_item =
1756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        delegate_->GetTestModel()->CreateSingleItemFolder("single_item_folder",
1766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                                          "single");
1776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    EXPECT_EQ(folder_item,
1786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)              delegate_->GetTestModel()->FindFolderItem("single_item_folder"));
1796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    EXPECT_EQ(AppListFolderItem::kItemType, folder_item->GetItemType());
1806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    EXPECT_EQ(1, RootViewModel()->view_size());
1826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    AppListItemView* folder_item_view =
1836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        static_cast<AppListItemView*>(RootViewModel()->view_at(0));
1846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    EXPECT_EQ(folder_item_view->item(), folder_item);
1856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Click on the folder to open it.
1876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    EXPECT_FALSE(FolderView()->visible());
1886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SimulateClick(folder_item_view);
1896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    base::RunLoop().RunUntilIdle();
1906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    EXPECT_TRUE(FolderView()->visible());
1916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#if defined(OS_WIN)
1936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    AppsGridViewTestApi folder_grid_view_test_api(FolderGridView());
1946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    folder_grid_view_test_api.DisableSynchronousDrag();
1956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#endif
1966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return folder_item_view;
1976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  AppListItemView* StartDragForReparent(int index_in_folder) {
2006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Start to drag the item in folder.
2016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    views::View* item_view = FolderViewModel()->view_at(index_in_folder);
2026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    gfx::Point point = item_view->bounds().CenterPoint();
2036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    AppListItemView* dragged =
2046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        SimulateInitiateDrag(FolderGridView(), AppsGridView::MOUSE, point);
2056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    EXPECT_EQ(item_view, dragged);
2066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    EXPECT_FALSE(RootGridView()->visible());
2076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    EXPECT_TRUE(FolderView()->visible());
2086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Drag it to top left corner.
2106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    point = gfx::Point(0, 0);
2116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Two update drags needed to actually drag the view. The first changes
2126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // state and the 2nd one actually moves the view. The 2nd call can be
2136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // removed when UpdateDrag is fixed.
2146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SimulateUpdateDrag(FolderGridView(), AppsGridView::MOUSE, dragged, point);
2156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SimulateUpdateDrag(FolderGridView(), AppsGridView::MOUSE, dragged, point);
2166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    base::RunLoop().RunUntilIdle();
2176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Wait until the folder view is invisible and root grid view shows up.
2196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    GridViewVisibleWaiter(RootGridView()).Wait();
2206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    EXPECT_TRUE(RootGridView()->visible());
2216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    EXPECT_EQ(0, FolderView()->layer()->opacity());
2226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return dragged;
2246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
2256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
226a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) protected:
227a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  views::Widget* widget_;  // Owned by native window.
228a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  AppListMainView* main_view_;  // Owned by |widget_|.
229a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<AppListTestViewDelegate> delegate_;
230a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
231a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private:
232a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(AppListMainViewTest);
233a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
234a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
235a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace
236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
237a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Tests changing the AppListModel when switching profiles.
238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(AppListMainViewTest, ModelChanged) {
239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  delegate_->GetTestModel()->PopulateApps(kInitialItems);
240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_EQ(kInitialItems, RootViewModel()->view_size());
241a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
242a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The model is owned by a profile keyed service, which is never destroyed
243a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // until after profile switching.
244a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<AppListModel> old_model(delegate_->ReleaseTestModel());
245a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
246a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const int kReplacementItems = 5;
247a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  delegate_->ReplaceTestModel(kReplacementItems);
248a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  main_view_->ModelChanged();
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_EQ(kReplacementItems, RootViewModel()->view_size());
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Tests dragging an item out of a single item folder and drop it at the last
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// slot.
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST_F(AppListMainViewTest, DragLastItemFromFolderAndDropAtLastSlot) {
2556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  AppListItemView* folder_item_view = CreateAndOpenSingleItemFolder();
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const gfx::Rect first_slot_tile = folder_item_view->bounds();
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_EQ(1, FolderViewModel()->view_size());
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
2606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  AppListItemView* dragged = StartDragForReparent(0);
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Drop it to the slot on the right of first slot.
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  gfx::Rect drop_target_tile(first_slot_tile);
2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  drop_target_tile.Offset(first_slot_tile.width() * 2, 0);
2656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  gfx::Point point = drop_target_tile.CenterPoint();
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SimulateUpdateDrag(FolderGridView(), AppsGridView::MOUSE, dragged, point);
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Drop it.
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FolderGridView()->EndDrag(false);
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Folder icon view should be gone and there is only one item view.
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_EQ(1, RootViewModel()->view_size());
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_EQ(AppListItemView::kViewClassName,
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            RootViewModel()->view_at(0)->GetClassName());
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // The item view should be in slot 1 instead of slot 2 where it is dropped.
277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AppsGridViewTestApi root_grid_view_test_api(RootGridView());
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  root_grid_view_test_api.LayoutToIdealBounds();
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_EQ(first_slot_tile, RootViewModel()->view_at(0)->bounds());
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Single item folder should be auto removed.
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_EQ(NULL,
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            delegate_->GetTestModel()->FindFolderItem("single_item_folder"));
284a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
285a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Tests dragging an item out of a single item folder and dropping it onto the
2871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// page switcher. Regression test for http://crbug.com/415530/.
2881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTEST_F(AppListMainViewTest, DragReparentItemOntoPageSwitcher) {
2891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AppListItemView* folder_item_view = CreateAndOpenSingleItemFolder();
2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const gfx::Rect first_slot_tile = folder_item_view->bounds();
2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  delegate_->GetTestModel()->PopulateApps(20);
2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(1, FolderViewModel()->view_size());
2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(21, RootViewModel()->view_size());
2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AppListItemView* dragged = StartDragForReparent(0);
2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gfx::Rect main_view_bounds = main_view_->bounds();
3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Drag the reparent item to the page switcher.
3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gfx::Point point =
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      gfx::Point(main_view_bounds.width() / 2,
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 main_view_bounds.bottom() - first_slot_tile.height());
3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  SimulateUpdateDrag(FolderGridView(), AppsGridView::MOUSE, dragged, point);
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Drop it.
3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  FolderGridView()->EndDrag(false);
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The folder should be destroyed.
3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(21, RootViewModel()->view_size());
3111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(NULL,
3121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            delegate_->GetTestModel()->FindFolderItem("single_item_folder"));
3131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Test that an interrupted drag while reparenting an item from a folder, when
3166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// canceled via the root grid, correctly forwards the cancelation to the drag
3176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// ocurring from the folder.
3186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)TEST_F(AppListMainViewTest, MouseDragItemOutOfFolderWithCancel) {
3196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  CreateAndOpenSingleItemFolder();
3206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  AppListItemView* dragged = StartDragForReparent(0);
3216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Now add an item to the model, not in any folder, e.g., as if by Sync.
3236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_TRUE(RootGridView()->has_dragged_view());
3246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_TRUE(FolderGridView()->has_dragged_view());
3256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  delegate_->GetTestModel()->CreateAndAddItem("Extra");
3266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // The drag operation should get canceled.
3286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_FALSE(RootGridView()->has_dragged_view());
3296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_FALSE(FolderGridView()->has_dragged_view());
3306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Additional mouse move operations should be ignored.
3326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  gfx::Point point(1, 1);
3336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  SimulateUpdateDrag(FolderGridView(), AppsGridView::MOUSE, dragged, point);
3346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_FALSE(RootGridView()->has_dragged_view());
3356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_FALSE(FolderGridView()->has_dragged_view());
3366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
3376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
338a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace test
339a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace app_list
340