Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / ui / app_list / views / apps_grid_view_unittest.cc
bloba5f9926bff01cc0328efc28fad781566f869bb16
1 // Copyright (c) 2012 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 "ui/app_list/views/apps_grid_view.h"
7 #include <string>
9 #include "base/basictypes.h"
10 #include "base/command_line.h"
11 #include "base/compiler_specific.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/app_list/app_list_constants.h"
18 #include "ui/app_list/app_list_folder_item.h"
19 #include "ui/app_list/app_list_item.h"
20 #include "ui/app_list/app_list_model.h"
21 #include "ui/app_list/app_list_switches.h"
22 #include "ui/app_list/pagination_model.h"
23 #include "ui/app_list/test/app_list_test_model.h"
24 #include "ui/app_list/views/app_list_item_view.h"
25 #include "ui/app_list/views/apps_grid_view_folder_delegate.h"
26 #include "ui/app_list/views/test/apps_grid_view_test_api.h"
27 #include "ui/events/event_utils.h"
28 #include "ui/views/test/views_test_base.h"
30 namespace app_list {
31 namespace test {
33 namespace {
35 const int kCols = 2;
36 const int kRows = 2;
37 const int kTilesPerPage = kCols * kRows;
39 class PageFlipWaiter : public PaginationModelObserver {
40 public:
41 PageFlipWaiter(base::MessageLoopForUI* ui_loop, PaginationModel* model)
42 : ui_loop_(ui_loop), model_(model), wait_(false) {
43 model_->AddObserver(this);
46 ~PageFlipWaiter() override { model_->RemoveObserver(this); }
48 void Wait() {
49 DCHECK(!wait_);
50 wait_ = true;
52 ui_loop_->Run();
53 wait_ = false;
56 void Reset() { selected_pages_.clear(); }
58 const std::string& selected_pages() const { return selected_pages_; }
60 private:
61 // PaginationModelObserver overrides:
62 void TotalPagesChanged() override {}
63 void SelectedPageChanged(int old_selected, int new_selected) override {
64 if (!selected_pages_.empty())
65 selected_pages_ += ',';
66 selected_pages_ += base::IntToString(new_selected);
68 if (wait_)
69 ui_loop_->Quit();
71 void TransitionStarted() override {}
72 void TransitionChanged() override {}
74 base::MessageLoopForUI* ui_loop_;
75 PaginationModel* model_;
76 bool wait_;
77 std::string selected_pages_;
79 DISALLOW_COPY_AND_ASSIGN(PageFlipWaiter);
82 } // namespace
84 class AppsGridViewTest : public views::ViewsTestBase {
85 public:
86 AppsGridViewTest() {}
87 ~AppsGridViewTest() override {}
89 // testing::Test overrides:
90 void SetUp() override {
91 views::ViewsTestBase::SetUp();
92 model_.reset(new AppListTestModel);
93 model_->SetFoldersEnabled(true);
95 apps_grid_view_.reset(new AppsGridView(NULL));
96 apps_grid_view_->SetLayout(kCols, kRows);
97 apps_grid_view_->SetBoundsRect(
98 gfx::Rect(apps_grid_view_->GetPreferredSize()));
99 apps_grid_view_->SetModel(model_.get());
100 apps_grid_view_->SetItemList(model_->top_level_item_list());
102 test_api_.reset(new AppsGridViewTestApi(apps_grid_view_.get()));
104 void TearDown() override {
105 apps_grid_view_.reset(); // Release apps grid view before models.
106 views::ViewsTestBase::TearDown();
109 protected:
110 void EnsureFoldersEnabled() {
111 #if defined(OS_MACOSX)
112 // Folders require toolkit-views app list to be enabled.
113 base::CommandLine::ForCurrentProcess()->AppendSwitch(
114 switches::kEnableMacViewsAppList);
115 #endif
118 AppListItemView* GetItemViewAt(int index) {
119 return static_cast<AppListItemView*>(
120 test_api_->GetViewAtModelIndex(index));
123 AppListItemView* GetItemViewForPoint(const gfx::Point& point) {
124 for (size_t i = 0; i < model_->top_level_item_list()->item_count(); ++i) {
125 AppListItemView* view = GetItemViewAt(i);
126 if (view->bounds().Contains(point))
127 return view;
129 return NULL;
132 gfx::Rect GetItemTileRectAt(int row, int col) {
133 DCHECK_GT(model_->top_level_item_list()->item_count(), 0u);
135 gfx::Insets insets(apps_grid_view_->GetInsets());
136 gfx::Rect rect(gfx::Point(insets.left(), insets.top()),
137 AppsGridView::GetTotalTileSize());
138 rect.Offset(col * rect.width(), row * rect.height());
139 return rect;
142 PaginationModel* GetPaginationModel() {
143 return apps_grid_view_->pagination_model();
146 // Points are in |apps_grid_view_|'s coordinates.
147 AppListItemView* SimulateDrag(AppsGridView::Pointer pointer,
148 const gfx::Point& from,
149 const gfx::Point& to) {
150 AppListItemView* view = GetItemViewForPoint(from);
151 DCHECK(view);
153 gfx::Point translated_from = gfx::PointAtOffsetFromOrigin(
154 from - view->bounds().origin());
155 gfx::Point translated_to = gfx::PointAtOffsetFromOrigin(
156 to - view->bounds().origin());
158 ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED, translated_from, from,
159 ui::EventTimeForNow(), 0, 0);
160 apps_grid_view_->InitiateDrag(view, pointer, pressed_event);
162 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, translated_to, to,
163 ui::EventTimeForNow(), 0, 0);
164 apps_grid_view_->UpdateDragFromItem(pointer, drag_event);
165 return view;
168 void SimulateKeyPress(ui::KeyboardCode key_code) {
169 ui::KeyEvent key_event(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE);
170 apps_grid_view_->OnKeyPressed(key_event);
173 scoped_ptr<AppListTestModel> model_;
174 scoped_ptr<AppsGridView> apps_grid_view_;
175 scoped_ptr<AppsGridViewTestApi> test_api_;
177 private:
178 DISALLOW_COPY_AND_ASSIGN(AppsGridViewTest);
181 class TestAppsGridViewFolderDelegate : public AppsGridViewFolderDelegate {
182 public:
183 TestAppsGridViewFolderDelegate() : show_bubble_(false) {}
184 ~TestAppsGridViewFolderDelegate() override {}
186 // Overridden from AppsGridViewFolderDelegate:
187 void UpdateFolderViewBackground(bool show_bubble) override {
188 show_bubble_ = show_bubble;
191 void ReparentItem(AppListItemView* original_drag_view,
192 const gfx::Point& drag_point_in_folder_grid,
193 bool has_native_drag) override {}
195 void DispatchDragEventForReparent(
196 AppsGridView::Pointer pointer,
197 const gfx::Point& drag_point_in_folder_grid) override {}
199 void DispatchEndDragEventForReparent(bool events_forwarded_to_drag_drop_host,
200 bool cancel_drag) override {}
202 bool IsPointOutsideOfFolderBoundary(const gfx::Point& point) override {
203 return false;
206 bool IsOEMFolder() const override { return false; }
208 void SetRootLevelDragViewVisible(bool visible) override {}
210 bool show_bubble() { return show_bubble_; }
212 private:
213 bool show_bubble_;
215 DISALLOW_COPY_AND_ASSIGN(TestAppsGridViewFolderDelegate);
218 TEST_F(AppsGridViewTest, CreatePage) {
219 // Fully populates a page.
220 const int kPages = 1;
221 model_->PopulateApps(kPages * kTilesPerPage);
222 EXPECT_EQ(kPages, GetPaginationModel()->total_pages());
224 // Adds one more and gets a new page created.
225 model_->CreateAndAddItem("Extra");
226 EXPECT_EQ(kPages + 1, GetPaginationModel()->total_pages());
229 TEST_F(AppsGridViewTest, EnsureHighlightedVisible) {
230 const int kPages = 3;
231 model_->PopulateApps(kPages * kTilesPerPage);
232 EXPECT_EQ(kPages, GetPaginationModel()->total_pages());
233 EXPECT_EQ(0, GetPaginationModel()->selected_page());
235 // Highlight first one and last one one first page and first page should be
236 // selected.
237 model_->HighlightItemAt(0);
238 EXPECT_EQ(0, GetPaginationModel()->selected_page());
239 model_->HighlightItemAt(kTilesPerPage - 1);
240 EXPECT_EQ(0, GetPaginationModel()->selected_page());
242 // Highlight first one on 2nd page and 2nd page should be selected.
243 model_->HighlightItemAt(kTilesPerPage + 1);
244 EXPECT_EQ(1, GetPaginationModel()->selected_page());
246 // Highlight last one in the model and last page should be selected.
247 model_->HighlightItemAt(model_->top_level_item_list()->item_count() - 1);
248 EXPECT_EQ(kPages - 1, GetPaginationModel()->selected_page());
251 TEST_F(AppsGridViewTest, RemoveSelectedLastApp) {
252 const int kTotalItems = 2;
253 const int kLastItemIndex = kTotalItems - 1;
255 model_->PopulateApps(kTotalItems);
257 AppListItemView* last_view = GetItemViewAt(kLastItemIndex);
258 apps_grid_view_->SetSelectedView(last_view);
259 model_->DeleteItem(model_->GetItemName(kLastItemIndex));
261 EXPECT_FALSE(apps_grid_view_->IsSelectedView(last_view));
263 // No crash happens.
264 AppListItemView* view = GetItemViewAt(0);
265 apps_grid_view_->SetSelectedView(view);
266 EXPECT_TRUE(apps_grid_view_->IsSelectedView(view));
269 TEST_F(AppsGridViewTest, MouseDragWithFolderDisabled) {
270 model_->SetFoldersEnabled(false);
271 const int kTotalItems = 4;
272 model_->PopulateApps(kTotalItems);
273 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
274 model_->GetModelContent());
276 gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
277 gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
279 // Dragging changes model order.
280 SimulateDrag(AppsGridView::MOUSE, from, to);
281 apps_grid_view_->EndDrag(false);
282 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
283 model_->GetModelContent());
284 test_api_->LayoutToIdealBounds();
286 // Canceling drag should keep existing order.
287 SimulateDrag(AppsGridView::MOUSE, from, to);
288 apps_grid_view_->EndDrag(true);
289 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
290 model_->GetModelContent());
291 test_api_->LayoutToIdealBounds();
293 // Deleting an item keeps remaining intact.
294 SimulateDrag(AppsGridView::MOUSE, from, to);
295 model_->DeleteItem(model_->GetItemName(0));
296 apps_grid_view_->EndDrag(false);
297 EXPECT_EQ(std::string("Item 1,Item 2,Item 3"),
298 model_->GetModelContent());
299 test_api_->LayoutToIdealBounds();
301 // Adding a launcher item cancels the drag and respects the order.
302 SimulateDrag(AppsGridView::MOUSE, from, to);
303 EXPECT_TRUE(apps_grid_view_->has_dragged_view());
304 model_->CreateAndAddItem("Extra");
305 // No need to EndDrag explicitly - adding an item should do this.
306 EXPECT_FALSE(apps_grid_view_->has_dragged_view());
307 // Even though cancelled, mouse move events can still arrive via the item
308 // view. Ensure that behaves sanely, and doesn't start a new drag.
309 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, gfx::Point(1, 1),
310 gfx::Point(2, 2), ui::EventTimeForNow(), 0, 0);
311 apps_grid_view_->UpdateDragFromItem(AppsGridView::MOUSE, drag_event);
312 EXPECT_FALSE(apps_grid_view_->has_dragged_view());
314 EXPECT_EQ(std::string("Item 1,Item 2,Item 3,Extra"),
315 model_->GetModelContent());
316 test_api_->LayoutToIdealBounds();
319 TEST_F(AppsGridViewTest, MouseDragItemIntoFolder) {
320 EnsureFoldersEnabled();
322 size_t kTotalItems = 3;
323 model_->PopulateApps(kTotalItems);
324 EXPECT_EQ(model_->top_level_item_list()->item_count(), kTotalItems);
325 EXPECT_EQ(std::string("Item 0,Item 1,Item 2"), model_->GetModelContent());
327 gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
328 gfx::Point to = GetItemTileRectAt(0, 0).CenterPoint();
330 // Dragging item_1 over item_0 creates a folder.
331 SimulateDrag(AppsGridView::MOUSE, from, to);
332 apps_grid_view_->EndDrag(false);
333 EXPECT_EQ(kTotalItems - 1, model_->top_level_item_list()->item_count());
334 EXPECT_EQ(AppListFolderItem::kItemType,
335 model_->top_level_item_list()->item_at(0)->GetItemType());
336 AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
337 model_->top_level_item_list()->item_at(0));
338 EXPECT_EQ(2u, folder_item->ChildItemCount());
339 AppListItem* item_0 = model_->FindItem("Item 0");
340 EXPECT_TRUE(item_0->IsInFolder());
341 EXPECT_EQ(folder_item->id(), item_0->folder_id());
342 AppListItem* item_1 = model_->FindItem("Item 1");
343 EXPECT_TRUE(item_1->IsInFolder());
344 EXPECT_EQ(folder_item->id(), item_1->folder_id());
345 std::string expected_items = folder_item->id() + ",Item 2";
346 EXPECT_EQ(expected_items, model_->GetModelContent());
347 test_api_->LayoutToIdealBounds();
349 // Dragging item_2 to the folder adds item_2 to the folder.
350 SimulateDrag(AppsGridView::MOUSE, from, to);
351 apps_grid_view_->EndDrag(false);
353 EXPECT_EQ(kTotalItems - 2, model_->top_level_item_list()->item_count());
354 EXPECT_EQ(folder_item->id(), model_->GetModelContent());
355 EXPECT_EQ(3u, folder_item->ChildItemCount());
356 item_0 = model_->FindItem("Item 0");
357 EXPECT_TRUE(item_0->IsInFolder());
358 EXPECT_EQ(folder_item->id(), item_0->folder_id());
359 item_1 = model_->FindItem("Item 1");
360 EXPECT_TRUE(item_1->IsInFolder());
361 EXPECT_EQ(folder_item->id(), item_1->folder_id());
362 AppListItem* item_2 = model_->FindItem("Item 2");
363 EXPECT_TRUE(item_2->IsInFolder());
364 EXPECT_EQ(folder_item->id(), item_2->folder_id());
365 test_api_->LayoutToIdealBounds();
368 TEST_F(AppsGridViewTest, MouseDragMaxItemsInFolder) {
369 EnsureFoldersEnabled();
371 // Create and add a folder with 15 items in it.
372 size_t kTotalItems = kMaxFolderItems - 1;
373 model_->CreateAndPopulateFolderWithApps(kTotalItems);
374 EXPECT_EQ(1u, model_->top_level_item_list()->item_count());
375 EXPECT_EQ(AppListFolderItem::kItemType,
376 model_->top_level_item_list()->item_at(0)->GetItemType());
377 AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
378 model_->top_level_item_list()->item_at(0));
379 EXPECT_EQ(kTotalItems, folder_item->ChildItemCount());
381 // Create and add another 2 items.
382 model_->PopulateAppWithId(kTotalItems);
383 model_->PopulateAppWithId(kTotalItems + 1);
384 EXPECT_EQ(3u, model_->top_level_item_list()->item_count());
385 EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
386 EXPECT_EQ(model_->GetItemName(kMaxFolderItems - 1),
387 model_->top_level_item_list()->item_at(1)->id());
388 EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
389 model_->top_level_item_list()->item_at(2)->id());
391 gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
392 gfx::Point to = GetItemTileRectAt(0, 0).CenterPoint();
394 // Dragging one item into the folder, the folder should accept the item.
395 SimulateDrag(AppsGridView::MOUSE, from, to);
396 apps_grid_view_->EndDrag(false);
397 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
398 EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
399 EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
400 EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
401 model_->top_level_item_list()->item_at(1)->id());
402 test_api_->LayoutToIdealBounds();
404 // Dragging the last item over the folder, the folder won't accept the new
405 // item.
406 SimulateDrag(AppsGridView::MOUSE, from, to);
407 apps_grid_view_->EndDrag(false);
408 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
409 EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
410 test_api_->LayoutToIdealBounds();
413 // Check that moving items around doesn't allow a drop to happen into a full
414 // folder.
415 TEST_F(AppsGridViewTest, MouseDragMaxItemsInFolderWithMovement) {
416 EnsureFoldersEnabled();
418 // Create and add a folder with 16 items in it.
419 size_t kTotalItems = kMaxFolderItems;
420 model_->CreateAndPopulateFolderWithApps(kTotalItems);
421 EXPECT_EQ(1u, model_->top_level_item_list()->item_count());
422 EXPECT_EQ(AppListFolderItem::kItemType,
423 model_->top_level_item_list()->item_at(0)->GetItemType());
424 AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
425 model_->top_level_item_list()->item_at(0));
426 EXPECT_EQ(kTotalItems, folder_item->ChildItemCount());
428 // Create and add another item.
429 model_->PopulateAppWithId(kTotalItems);
430 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
431 EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
432 EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
433 model_->top_level_item_list()->item_at(1)->id());
435 AppListItemView* folder_view =
436 GetItemViewForPoint(GetItemTileRectAt(0, 0).CenterPoint());
438 // Drag the new item to the left so that the grid reorders.
439 gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
440 gfx::Point to = GetItemTileRectAt(0, 0).bottom_left();
441 to.Offset(0, -1); // Get a point inside the rect.
442 AppListItemView* dragged_view = SimulateDrag(AppsGridView::MOUSE, from, to);
443 test_api_->LayoutToIdealBounds();
445 // The grid now looks like | blank | folder |.
446 EXPECT_EQ(NULL, GetItemViewForPoint(GetItemTileRectAt(0, 0).CenterPoint()));
447 EXPECT_EQ(folder_view,
448 GetItemViewForPoint(GetItemTileRectAt(0, 1).CenterPoint()));
450 // Move onto the folder and end the drag.
451 to = GetItemTileRectAt(0, 1).CenterPoint();
452 gfx::Point translated_to =
453 gfx::PointAtOffsetFromOrigin(to - dragged_view->bounds().origin());
454 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, translated_to, to,
455 ui::EventTimeForNow(), 0, 0);
456 apps_grid_view_->UpdateDragFromItem(AppsGridView::MOUSE, drag_event);
457 apps_grid_view_->EndDrag(false);
459 // The item should not have moved into the folder.
460 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
461 EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
462 test_api_->LayoutToIdealBounds();
465 TEST_F(AppsGridViewTest, MouseDragItemReorder) {
466 // This test assumes Folders are enabled.
467 EnsureFoldersEnabled();
469 model_->PopulateApps(4);
470 EXPECT_EQ(4u, model_->top_level_item_list()->item_count());
471 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
472 model_->GetModelContent());
474 // Dragging an item towards its neighbours should not reorder until the drag
475 // is past the folder drop point.
476 gfx::Point top_right = GetItemTileRectAt(0, 1).CenterPoint();
477 gfx::Vector2d drag_vector;
478 int half_tile_width =
479 (GetItemTileRectAt(0, 1).x() - GetItemTileRectAt(0, 0).x()) / 2;
480 int tile_height = GetItemTileRectAt(1, 0).y() - GetItemTileRectAt(0, 0).y();
482 // Drag left but stop before the folder dropping circle.
483 drag_vector.set_x(-half_tile_width - 4);
484 SimulateDrag(AppsGridView::MOUSE, top_right, top_right + drag_vector);
485 apps_grid_view_->EndDrag(false);
486 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
487 model_->GetModelContent());
489 // Drag left, past the folder dropping circle.
490 drag_vector.set_x(-3 * half_tile_width + 4);
491 SimulateDrag(AppsGridView::MOUSE, top_right, top_right + drag_vector);
492 apps_grid_view_->EndDrag(false);
493 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
494 model_->GetModelContent());
496 // Drag down, between apps 2 and 3. The gap should open up, making space for
497 // app 0 in the bottom left.
498 drag_vector.set_x(-half_tile_width);
499 drag_vector.set_y(tile_height);
500 SimulateDrag(AppsGridView::MOUSE, top_right, top_right + drag_vector);
501 apps_grid_view_->EndDrag(false);
502 EXPECT_EQ(std::string("Item 1,Item 2,Item 0,Item 3"),
503 model_->GetModelContent());
505 // Drag up, between apps 1 and 2. The gap should open up, making space for app
506 // 0 in the top right.
507 gfx::Point bottom_left = GetItemTileRectAt(1, 0).CenterPoint();
508 drag_vector.set_x(half_tile_width);
509 drag_vector.set_y(-tile_height);
510 SimulateDrag(AppsGridView::MOUSE, bottom_left, bottom_left + drag_vector);
511 apps_grid_view_->EndDrag(false);
512 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
513 model_->GetModelContent());
515 // Dragging down past the last app should reorder to the last position.
516 drag_vector.set_x(half_tile_width);
517 drag_vector.set_y(2 * tile_height);
518 SimulateDrag(AppsGridView::MOUSE, top_right, top_right + drag_vector);
519 apps_grid_view_->EndDrag(false);
520 EXPECT_EQ(std::string("Item 1,Item 2,Item 3,Item 0"),
521 model_->GetModelContent());
524 TEST_F(AppsGridViewTest, MouseDragFolderReorder) {
525 EnsureFoldersEnabled();
527 size_t kTotalItems = 2;
528 model_->CreateAndPopulateFolderWithApps(kTotalItems);
529 model_->PopulateAppWithId(kTotalItems);
530 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
531 EXPECT_EQ(AppListFolderItem::kItemType,
532 model_->top_level_item_list()->item_at(0)->GetItemType());
533 AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
534 model_->top_level_item_list()->item_at(0));
535 EXPECT_EQ("Item 2", model_->top_level_item_list()->item_at(1)->id());
537 gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
538 gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
540 // Dragging folder over item_1 should leads to re-ordering these two
541 // items.
542 SimulateDrag(AppsGridView::MOUSE, from, to);
543 apps_grid_view_->EndDrag(false);
544 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
545 EXPECT_EQ("Item 2", model_->top_level_item_list()->item_at(0)->id());
546 EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(1)->id());
547 test_api_->LayoutToIdealBounds();
550 TEST_F(AppsGridViewTest, MouseDragWithCancelDeleteAddItem) {
551 size_t kTotalItems = 4;
552 model_->PopulateApps(kTotalItems);
553 EXPECT_EQ(model_->top_level_item_list()->item_count(), kTotalItems);
554 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
555 model_->GetModelContent());
557 gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
558 gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
560 // Canceling drag should keep existing order.
561 SimulateDrag(AppsGridView::MOUSE, from, to);
562 apps_grid_view_->EndDrag(true);
563 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
564 model_->GetModelContent());
565 test_api_->LayoutToIdealBounds();
567 // Deleting an item keeps remaining intact.
568 SimulateDrag(AppsGridView::MOUSE, from, to);
569 model_->DeleteItem(model_->GetItemName(2));
570 apps_grid_view_->EndDrag(false);
571 EXPECT_EQ(std::string("Item 0,Item 1,Item 3"), model_->GetModelContent());
572 test_api_->LayoutToIdealBounds();
574 // Adding a launcher item cancels the drag and respects the order.
575 SimulateDrag(AppsGridView::MOUSE, from, to);
576 model_->CreateAndAddItem("Extra");
577 apps_grid_view_->EndDrag(false);
578 EXPECT_EQ(std::string("Item 0,Item 1,Item 3,Extra"),
579 model_->GetModelContent());
580 test_api_->LayoutToIdealBounds();
583 TEST_F(AppsGridViewTest, MouseDragFlipPage) {
584 test_api_->SetPageFlipDelay(10);
585 GetPaginationModel()->SetTransitionDurations(10, 10);
587 PageFlipWaiter page_flip_waiter(message_loop(), GetPaginationModel());
589 const int kPages = 3;
590 model_->PopulateApps(kPages * kTilesPerPage);
591 EXPECT_EQ(kPages, GetPaginationModel()->total_pages());
592 EXPECT_EQ(0, GetPaginationModel()->selected_page());
594 gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
595 gfx::Point to = gfx::Point(apps_grid_view_->width(),
596 apps_grid_view_->height() / 2);
598 // Drag to right edge.
599 page_flip_waiter.Reset();
600 SimulateDrag(AppsGridView::MOUSE, from, to);
602 // Page should be flipped after sometime to hit page 1 and 2 then stop.
603 while (test_api_->HasPendingPageFlip()) {
604 page_flip_waiter.Wait();
606 EXPECT_EQ("1,2", page_flip_waiter.selected_pages());
607 EXPECT_EQ(2, GetPaginationModel()->selected_page());
609 apps_grid_view_->EndDrag(true);
611 // Now drag to the left edge and test the other direction.
612 to.set_x(0);
614 page_flip_waiter.Reset();
615 SimulateDrag(AppsGridView::MOUSE, from, to);
617 while (test_api_->HasPendingPageFlip()) {
618 page_flip_waiter.Wait();
620 EXPECT_EQ("1,0", page_flip_waiter.selected_pages());
621 EXPECT_EQ(0, GetPaginationModel()->selected_page());
623 apps_grid_view_->EndDrag(true);
626 TEST_F(AppsGridViewTest, SimultaneousDragWithFolderDisabled) {
627 model_->SetFoldersEnabled(false);
628 const int kTotalItems = 4;
629 model_->PopulateApps(kTotalItems);
630 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
631 model_->GetModelContent());
633 gfx::Point mouse_from = GetItemTileRectAt(0, 0).CenterPoint();
634 gfx::Point mouse_to = GetItemTileRectAt(0, 1).CenterPoint();
636 gfx::Point touch_from = GetItemTileRectAt(1, 0).CenterPoint();
637 gfx::Point touch_to = GetItemTileRectAt(1, 1).CenterPoint();
639 // Starts a mouse drag first then a touch drag.
640 SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
641 SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
642 // Finishes the drag and mouse drag wins.
643 apps_grid_view_->EndDrag(false);
644 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
645 model_->GetModelContent());
646 test_api_->LayoutToIdealBounds();
648 // Starts a touch drag first then a mouse drag.
649 SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
650 SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
651 // Finishes the drag and touch drag wins.
652 apps_grid_view_->EndDrag(false);
653 EXPECT_EQ(std::string("Item 1,Item 0,Item 3,Item 2"),
654 model_->GetModelContent());
655 test_api_->LayoutToIdealBounds();
658 TEST_F(AppsGridViewTest, UpdateFolderBackgroundOnCancelDrag) {
659 EnsureFoldersEnabled();
661 const int kTotalItems = 4;
662 TestAppsGridViewFolderDelegate folder_delegate;
663 apps_grid_view_->set_folder_delegate(&folder_delegate);
664 model_->PopulateApps(kTotalItems);
665 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
666 model_->GetModelContent());
668 gfx::Point mouse_from = GetItemTileRectAt(0, 0).CenterPoint();
669 gfx::Point mouse_to = GetItemTileRectAt(0, 1).CenterPoint();
671 // Starts a mouse drag and then cancels it.
672 SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
673 EXPECT_TRUE(folder_delegate.show_bubble());
674 apps_grid_view_->EndDrag(true);
675 EXPECT_FALSE(folder_delegate.show_bubble());
676 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
677 model_->GetModelContent());
680 TEST_F(AppsGridViewTest, HighlightWithKeyboard) {
681 const int kPages = 3;
682 const int kItems = (kPages - 1) * kTilesPerPage + 1;
683 model_->PopulateApps(kItems);
685 const int first_index = 0;
686 const int last_index = kItems - 1;
687 const int last_index_on_page1_first_row = kRows - 1;
688 const int last_index_on_page1 = kTilesPerPage - 1;
689 const int first_index_on_page2 = kTilesPerPage;
690 const int first_index_on_page2_last_row = 2 * kTilesPerPage - kRows;
691 const int last_index_on_page2_last_row = 2 * kTilesPerPage - 1;
693 // Try moving off the item beyond the first one.
694 apps_grid_view_->SetSelectedView(GetItemViewAt(first_index));
695 SimulateKeyPress(ui::VKEY_UP);
696 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(first_index)));
697 SimulateKeyPress(ui::VKEY_LEFT);
698 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(first_index)));
700 // Move to the last item and try to go past it.
701 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index));
702 SimulateKeyPress(ui::VKEY_DOWN);
703 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(last_index)));
704 SimulateKeyPress(ui::VKEY_RIGHT);
705 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(last_index)));
707 // Move right on last item on page 1 should get to first item on page 2's last
708 // row and vice versa.
709 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page1));
710 SimulateKeyPress(ui::VKEY_RIGHT);
711 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
712 first_index_on_page2_last_row)));
713 SimulateKeyPress(ui::VKEY_LEFT);
714 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
715 last_index_on_page1)));
717 // Up/down on page boundary does nothing.
718 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page1));
719 SimulateKeyPress(ui::VKEY_DOWN);
720 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
721 last_index_on_page1)));
722 apps_grid_view_->SetSelectedView(
723 GetItemViewAt(first_index_on_page2_last_row));
724 apps_grid_view_->
725 SetSelectedView(GetItemViewAt(last_index_on_page1_first_row));
726 SimulateKeyPress(ui::VKEY_UP);
727 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
728 last_index_on_page1_first_row)));
730 // Page up and down should go to the same item on the next and last page.
731 apps_grid_view_->SetSelectedView(GetItemViewAt(first_index_on_page2));
732 SimulateKeyPress(ui::VKEY_PRIOR);
733 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
734 first_index)));
735 SimulateKeyPress(ui::VKEY_NEXT);
736 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
737 first_index_on_page2)));
739 // Moving onto a page with too few apps to support the expected index snaps
740 // to the last available index.
741 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row));
742 SimulateKeyPress(ui::VKEY_RIGHT);
743 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
744 last_index)));
745 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row));
746 SimulateKeyPress(ui::VKEY_NEXT);
747 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
748 last_index)));
750 // After page switch, arrow keys select first item on current page.
751 apps_grid_view_->SetSelectedView(GetItemViewAt(first_index));
752 GetPaginationModel()->SelectPage(1, false);
753 SimulateKeyPress(ui::VKEY_LEFT);
754 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
755 first_index_on_page2)));
758 TEST_F(AppsGridViewTest, ItemLabelShortNameOverride) {
759 // If the app's full name and short name differ, the title label's tooltip
760 // should always be the full name of the app.
761 std::string expected_text("xyz");
762 std::string expected_tooltip("tooltip");
763 AppListItem* item = model_->CreateAndAddItem("Item with short name");
764 model_->SetItemNameAndShortName(item, expected_tooltip, expected_text);
766 base::string16 actual_tooltip;
767 AppListItemView* item_view = GetItemViewAt(0);
768 ASSERT_TRUE(item_view);
769 const views::Label* title_label = item_view->title();
770 EXPECT_TRUE(item_view->GetTooltipText(title_label->bounds().CenterPoint(),
771 &actual_tooltip));
772 EXPECT_EQ(expected_tooltip, base::UTF16ToUTF8(actual_tooltip));
773 EXPECT_EQ(expected_text, base::UTF16ToUTF8(title_label->text()));
776 TEST_F(AppsGridViewTest, ItemLabelNoShortName) {
777 // If the app's full name and short name are the same, use the default tooltip
778 // behavior of the label (only show a tooltip if the title is truncated).
779 std::string title("a");
780 AppListItem* item = model_->CreateAndAddItem(title);
781 model_->SetItemNameAndShortName(item, title, "");
783 base::string16 actual_tooltip;
784 AppListItemView* item_view = GetItemViewAt(0);
785 ASSERT_TRUE(item_view);
786 const views::Label* title_label = item_view->title();
787 EXPECT_FALSE(title_label->GetTooltipText(
788 title_label->bounds().CenterPoint(), &actual_tooltip));
789 EXPECT_EQ(title, base::UTF16ToUTF8(title_label->text()));
792 } // namespace test
793 } // namespace app_list