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"
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/views/test/views_test_base.h"
34 const int kIconDimension
= 48;
37 const int kTilesPerPage
= kCols
* kRows
;
39 const int kWidth
= 320;
40 const int kHeight
= 240;
42 class PageFlipWaiter
: public PaginationModelObserver
{
44 PageFlipWaiter(base::MessageLoopForUI
* ui_loop
, PaginationModel
* model
)
45 : ui_loop_(ui_loop
), model_(model
), wait_(false) {
46 model_
->AddObserver(this);
49 virtual ~PageFlipWaiter() {
50 model_
->RemoveObserver(this);
61 void Reset() { selected_pages_
.clear(); }
63 const std::string
& selected_pages() const { return selected_pages_
; }
66 // PaginationModelObserver overrides:
67 virtual void TotalPagesChanged() OVERRIDE
{
69 virtual void SelectedPageChanged(int old_selected
,
70 int new_selected
) OVERRIDE
{
71 if (!selected_pages_
.empty())
72 selected_pages_
+= ',';
73 selected_pages_
+= base::IntToString(new_selected
);
78 virtual void TransitionStarted() OVERRIDE
{
80 virtual void TransitionChanged() OVERRIDE
{
83 base::MessageLoopForUI
* ui_loop_
;
84 PaginationModel
* model_
;
86 std::string selected_pages_
;
88 DISALLOW_COPY_AND_ASSIGN(PageFlipWaiter
);
93 class AppsGridViewTest
: public views::ViewsTestBase
{
96 virtual ~AppsGridViewTest() {}
98 // testing::Test overrides:
99 virtual void SetUp() OVERRIDE
{
100 views::ViewsTestBase::SetUp();
101 model_
.reset(new AppListTestModel
);
102 model_
->SetFoldersEnabled(true);
104 apps_grid_view_
.reset(new AppsGridView(NULL
));
105 apps_grid_view_
->SetLayout(kIconDimension
, kCols
, kRows
);
106 apps_grid_view_
->SetBoundsRect(gfx::Rect(gfx::Size(kWidth
, kHeight
)));
107 apps_grid_view_
->SetModel(model_
.get());
108 apps_grid_view_
->SetItemList(model_
->top_level_item_list());
110 test_api_
.reset(new AppsGridViewTestApi(apps_grid_view_
.get()));
112 virtual void TearDown() OVERRIDE
{
113 apps_grid_view_
.reset(); // Release apps grid view before models.
114 views::ViewsTestBase::TearDown();
118 void EnsureFoldersEnabled() {
119 // Folders require AppList sync to be enabled.
120 CommandLine::ForCurrentProcess()->AppendSwitch(
121 switches::kEnableSyncAppList
);
124 AppListItemView
* GetItemViewAt(int index
) {
125 return static_cast<AppListItemView
*>(
126 test_api_
->GetViewAtModelIndex(index
));
129 AppListItemView
* GetItemViewForPoint(const gfx::Point
& point
) {
130 for (size_t i
= 0; i
< model_
->top_level_item_list()->item_count(); ++i
) {
131 AppListItemView
* view
= GetItemViewAt(i
);
132 if (view
->bounds().Contains(point
))
138 gfx::Rect
GetItemTileRectAt(int row
, int col
) {
139 DCHECK_GT(model_
->top_level_item_list()->item_count(), 0u);
141 gfx::Insets
insets(apps_grid_view_
->GetInsets());
142 gfx::Rect
rect(gfx::Point(insets
.left(), insets
.top()),
143 GetItemViewAt(0)->bounds().size());
144 rect
.Offset(col
* rect
.width(), row
* rect
.height());
148 PaginationModel
* GetPaginationModel() {
149 return apps_grid_view_
->pagination_model();
152 // Points are in |apps_grid_view_|'s coordinates.
153 void SimulateDrag(AppsGridView::Pointer pointer
,
154 const gfx::Point
& from
,
155 const gfx::Point
& to
) {
156 AppListItemView
* view
= GetItemViewForPoint(from
);
159 gfx::Point translated_from
= gfx::PointAtOffsetFromOrigin(
160 from
- view
->bounds().origin());
161 gfx::Point translated_to
= gfx::PointAtOffsetFromOrigin(
162 to
- view
->bounds().origin());
164 ui::MouseEvent
pressed_event(ui::ET_MOUSE_PRESSED
,
165 translated_from
, from
, 0, 0);
166 apps_grid_view_
->InitiateDrag(view
, pointer
, pressed_event
);
168 ui::MouseEvent
drag_event(ui::ET_MOUSE_DRAGGED
,
169 translated_to
, to
, 0, 0);
170 apps_grid_view_
->UpdateDragFromItem(pointer
, drag_event
);
173 void SimulateKeyPress(ui::KeyboardCode key_code
) {
174 ui::KeyEvent
key_event(ui::ET_KEY_PRESSED
, key_code
, 0, false);
175 apps_grid_view_
->OnKeyPressed(key_event
);
178 scoped_ptr
<AppListTestModel
> model_
;
179 scoped_ptr
<AppsGridView
> apps_grid_view_
;
180 scoped_ptr
<AppsGridViewTestApi
> test_api_
;
183 DISALLOW_COPY_AND_ASSIGN(AppsGridViewTest
);
186 class TestAppsGridViewFolderDelegate
: public AppsGridViewFolderDelegate
{
188 TestAppsGridViewFolderDelegate() : show_bubble_(false) {}
189 virtual ~TestAppsGridViewFolderDelegate() {}
191 // Overridden from AppsGridViewFolderDelegate:
192 virtual void UpdateFolderViewBackground(bool show_bubble
) OVERRIDE
{
193 show_bubble_
= show_bubble
;
196 virtual void ReparentItem(AppListItemView
* original_drag_view
,
197 const gfx::Point
& drag_point_in_folder_grid
)
200 virtual void DispatchDragEventForReparent(
201 AppsGridView::Pointer pointer
,
202 const gfx::Point
& drag_point_in_folder_grid
) OVERRIDE
{}
204 virtual void DispatchEndDragEventForReparent(
205 bool events_forwarded_to_drag_drop_host
,
206 bool cancel_drag
) OVERRIDE
{}
208 virtual bool IsPointOutsideOfFolderBoundary(const gfx::Point
& point
)
213 virtual bool IsOEMFolder() const OVERRIDE
{ return false; }
215 virtual void SetRootLevelDragViewVisible(bool visible
) OVERRIDE
{}
217 bool show_bubble() { return show_bubble_
; }
222 DISALLOW_COPY_AND_ASSIGN(TestAppsGridViewFolderDelegate
);
225 TEST_F(AppsGridViewTest
, CreatePage
) {
226 // Fully populates a page.
227 const int kPages
= 1;
228 model_
->PopulateApps(kPages
* kTilesPerPage
);
229 EXPECT_EQ(kPages
, GetPaginationModel()->total_pages());
231 // Adds one more and gets a new page created.
232 model_
->CreateAndAddItem("Extra");
233 EXPECT_EQ(kPages
+ 1, GetPaginationModel()->total_pages());
236 TEST_F(AppsGridViewTest
, EnsureHighlightedVisible
) {
237 const int kPages
= 3;
238 model_
->PopulateApps(kPages
* kTilesPerPage
);
239 EXPECT_EQ(kPages
, GetPaginationModel()->total_pages());
240 EXPECT_EQ(0, GetPaginationModel()->selected_page());
242 // Highlight first one and last one one first page and first page should be
244 model_
->HighlightItemAt(0);
245 EXPECT_EQ(0, GetPaginationModel()->selected_page());
246 model_
->HighlightItemAt(kTilesPerPage
- 1);
247 EXPECT_EQ(0, GetPaginationModel()->selected_page());
249 // Highlight first one on 2nd page and 2nd page should be selected.
250 model_
->HighlightItemAt(kTilesPerPage
+ 1);
251 EXPECT_EQ(1, GetPaginationModel()->selected_page());
253 // Highlight last one in the model and last page should be selected.
254 model_
->HighlightItemAt(model_
->top_level_item_list()->item_count() - 1);
255 EXPECT_EQ(kPages
- 1, GetPaginationModel()->selected_page());
258 TEST_F(AppsGridViewTest
, RemoveSelectedLastApp
) {
259 const int kTotalItems
= 2;
260 const int kLastItemIndex
= kTotalItems
- 1;
262 model_
->PopulateApps(kTotalItems
);
264 AppListItemView
* last_view
= GetItemViewAt(kLastItemIndex
);
265 apps_grid_view_
->SetSelectedView(last_view
);
266 model_
->DeleteItem(model_
->GetItemName(kLastItemIndex
));
268 EXPECT_FALSE(apps_grid_view_
->IsSelectedView(last_view
));
271 AppListItemView
* view
= GetItemViewAt(0);
272 apps_grid_view_
->SetSelectedView(view
);
273 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(view
));
276 TEST_F(AppsGridViewTest
, MouseDragWithFolderDisabled
) {
277 model_
->SetFoldersEnabled(false);
278 const int kTotalItems
= 4;
279 model_
->PopulateApps(kTotalItems
);
280 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
281 model_
->GetModelContent());
283 gfx::Point from
= GetItemTileRectAt(0, 0).CenterPoint();
284 gfx::Point to
= GetItemTileRectAt(0, 1).CenterPoint();
286 // Dragging changes model order.
287 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
288 apps_grid_view_
->EndDrag(false);
289 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
290 model_
->GetModelContent());
291 test_api_
->LayoutToIdealBounds();
293 // Canceling drag should keep existing order.
294 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
295 apps_grid_view_
->EndDrag(true);
296 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
297 model_
->GetModelContent());
298 test_api_
->LayoutToIdealBounds();
300 // Deleting an item keeps remaining intact.
301 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
302 model_
->DeleteItem(model_
->GetItemName(0));
303 apps_grid_view_
->EndDrag(false);
304 EXPECT_EQ(std::string("Item 1,Item 2,Item 3"),
305 model_
->GetModelContent());
306 test_api_
->LayoutToIdealBounds();
308 // Adding a launcher item cancels the drag and respects the order.
309 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
310 model_
->CreateAndAddItem("Extra");
311 apps_grid_view_
->EndDrag(false);
312 EXPECT_EQ(std::string("Item 1,Item 2,Item 3,Extra"),
313 model_
->GetModelContent());
314 test_api_
->LayoutToIdealBounds();
317 TEST_F(AppsGridViewTest
, MouseDragItemIntoFolder
) {
318 EnsureFoldersEnabled();
320 size_t kTotalItems
= 3;
321 model_
->PopulateApps(kTotalItems
);
322 EXPECT_EQ(model_
->top_level_item_list()->item_count(), kTotalItems
);
323 EXPECT_EQ(std::string("Item 0,Item 1,Item 2"), model_
->GetModelContent());
325 gfx::Point from
= GetItemTileRectAt(0, 1).CenterPoint();
326 gfx::Point to
= GetItemTileRectAt(0, 0).CenterPoint();
328 // Dragging item_1 over item_0 creates a folder.
329 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
330 apps_grid_view_
->EndDrag(false);
331 EXPECT_EQ(kTotalItems
- 1, model_
->top_level_item_list()->item_count());
332 EXPECT_EQ(AppListFolderItem::kItemType
,
333 model_
->top_level_item_list()->item_at(0)->GetItemType());
334 AppListFolderItem
* folder_item
= static_cast<AppListFolderItem
*>(
335 model_
->top_level_item_list()->item_at(0));
336 EXPECT_EQ(2u, folder_item
->ChildItemCount());
337 AppListItem
* item_0
= model_
->FindItem("Item 0");
338 EXPECT_TRUE(item_0
->IsInFolder());
339 EXPECT_EQ(folder_item
->id(), item_0
->folder_id());
340 AppListItem
* item_1
= model_
->FindItem("Item 1");
341 EXPECT_TRUE(item_1
->IsInFolder());
342 EXPECT_EQ(folder_item
->id(), item_1
->folder_id());
343 std::string expected_items
= folder_item
->id() + ",Item 2";
344 EXPECT_EQ(expected_items
, model_
->GetModelContent());
345 test_api_
->LayoutToIdealBounds();
347 // Dragging item_2 to the folder adds item_2 to the folder.
348 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
349 apps_grid_view_
->EndDrag(false);
351 EXPECT_EQ(kTotalItems
- 2, model_
->top_level_item_list()->item_count());
352 EXPECT_EQ(folder_item
->id(), model_
->GetModelContent());
353 EXPECT_EQ(3u, folder_item
->ChildItemCount());
354 item_0
= model_
->FindItem("Item 0");
355 EXPECT_TRUE(item_0
->IsInFolder());
356 EXPECT_EQ(folder_item
->id(), item_0
->folder_id());
357 item_1
= model_
->FindItem("Item 1");
358 EXPECT_TRUE(item_1
->IsInFolder());
359 EXPECT_EQ(folder_item
->id(), item_1
->folder_id());
360 AppListItem
* item_2
= model_
->FindItem("Item 2");
361 EXPECT_TRUE(item_2
->IsInFolder());
362 EXPECT_EQ(folder_item
->id(), item_2
->folder_id());
363 test_api_
->LayoutToIdealBounds();
366 TEST_F(AppsGridViewTest
, MouseDragMaxItemsInFolder
) {
367 EnsureFoldersEnabled();
369 // Create and add a folder with 15 items in it.
370 size_t kTotalItems
= kMaxFolderItems
- 1;
371 model_
->CreateAndPopulateFolderWithApps(kTotalItems
);
372 EXPECT_EQ(1u, model_
->top_level_item_list()->item_count());
373 EXPECT_EQ(AppListFolderItem::kItemType
,
374 model_
->top_level_item_list()->item_at(0)->GetItemType());
375 AppListFolderItem
* folder_item
= static_cast<AppListFolderItem
*>(
376 model_
->top_level_item_list()->item_at(0));
377 EXPECT_EQ(kTotalItems
, folder_item
->ChildItemCount());
379 // Create and add another 2 items.
380 model_
->PopulateAppWithId(kTotalItems
);
381 model_
->PopulateAppWithId(kTotalItems
+ 1);
382 EXPECT_EQ(3u, model_
->top_level_item_list()->item_count());
383 EXPECT_EQ(folder_item
->id(), model_
->top_level_item_list()->item_at(0)->id());
384 EXPECT_EQ(model_
->GetItemName(kMaxFolderItems
- 1),
385 model_
->top_level_item_list()->item_at(1)->id());
386 EXPECT_EQ(model_
->GetItemName(kMaxFolderItems
),
387 model_
->top_level_item_list()->item_at(2)->id());
389 gfx::Point from
= GetItemTileRectAt(0, 1).CenterPoint();
390 gfx::Point to
= GetItemTileRectAt(0, 0).CenterPoint();
392 // Dragging one item into the folder, the folder should accept the item.
393 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
394 apps_grid_view_
->EndDrag(false);
395 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
396 EXPECT_EQ(folder_item
->id(), model_
->top_level_item_list()->item_at(0)->id());
397 EXPECT_EQ(kMaxFolderItems
, folder_item
->ChildItemCount());
398 EXPECT_EQ(model_
->GetItemName(kMaxFolderItems
),
399 model_
->top_level_item_list()->item_at(1)->id());
400 test_api_
->LayoutToIdealBounds();
402 // Dragging the last item over the folder, the folder won't accept the new
403 // item, instead, it will re-order the items.
404 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
405 apps_grid_view_
->EndDrag(false);
406 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
407 EXPECT_EQ(model_
->GetItemName(kMaxFolderItems
),
408 model_
->top_level_item_list()->item_at(0)->id());
409 EXPECT_EQ(folder_item
->id(), model_
->top_level_item_list()->item_at(1)->id());
410 EXPECT_EQ(kMaxFolderItems
, folder_item
->ChildItemCount());
411 test_api_
->LayoutToIdealBounds();
414 TEST_F(AppsGridViewTest
, MouseDragItemReorder
) {
415 // This test assumes Folders are enabled.
416 EnsureFoldersEnabled();
418 size_t kTotalItems
= 2;
419 model_
->PopulateApps(kTotalItems
);
420 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
421 EXPECT_EQ(std::string("Item 0,Item 1"), model_
->GetModelContent());
423 gfx::Point from
= GetItemTileRectAt(0, 1).CenterPoint();
424 int reorder_offset
= (GetItemTileRectAt(0, 1).CenterPoint() -
425 GetItemTileRectAt(0, 0).CenterPoint()).Length() -
426 kReorderDroppingCircleRadius
-
427 kPreferredIconDimension
/ 2 + 5;
428 gfx::Point to
= gfx::Point(from
.x() - reorder_offset
, from
.y());
430 // Dragging item_1 closing to item_0 should leads to re-ordering these two
432 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
433 apps_grid_view_
->EndDrag(false);
434 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
435 EXPECT_EQ(std::string("Item 1,Item 0"), model_
->GetModelContent());
436 test_api_
->LayoutToIdealBounds();
439 TEST_F(AppsGridViewTest
, MouseDragFolderReorder
) {
440 EnsureFoldersEnabled();
442 size_t kTotalItems
= 2;
443 model_
->CreateAndPopulateFolderWithApps(kTotalItems
);
444 model_
->PopulateAppWithId(kTotalItems
);
445 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
446 EXPECT_EQ(AppListFolderItem::kItemType
,
447 model_
->top_level_item_list()->item_at(0)->GetItemType());
448 AppListFolderItem
* folder_item
= static_cast<AppListFolderItem
*>(
449 model_
->top_level_item_list()->item_at(0));
450 EXPECT_EQ("Item 2", model_
->top_level_item_list()->item_at(1)->id());
452 gfx::Point from
= GetItemTileRectAt(0, 0).CenterPoint();
453 gfx::Point to
= GetItemTileRectAt(0, 1).CenterPoint();
455 // Dragging folder over item_1 should leads to re-ordering these two
457 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
458 apps_grid_view_
->EndDrag(false);
459 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
460 EXPECT_EQ("Item 2", model_
->top_level_item_list()->item_at(0)->id());
461 EXPECT_EQ(folder_item
->id(), model_
->top_level_item_list()->item_at(1)->id());
462 test_api_
->LayoutToIdealBounds();
465 TEST_F(AppsGridViewTest
, MouseDragWithCancelDeleteAddItem
) {
466 size_t kTotalItems
= 4;
467 model_
->PopulateApps(kTotalItems
);
468 EXPECT_EQ(model_
->top_level_item_list()->item_count(), kTotalItems
);
469 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
470 model_
->GetModelContent());
472 gfx::Point from
= GetItemTileRectAt(0, 0).CenterPoint();
473 gfx::Point to
= GetItemTileRectAt(0, 1).CenterPoint();
475 // Canceling drag should keep existing order.
476 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
477 apps_grid_view_
->EndDrag(true);
478 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
479 model_
->GetModelContent());
480 test_api_
->LayoutToIdealBounds();
482 // Deleting an item keeps remaining intact.
483 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
484 model_
->DeleteItem(model_
->GetItemName(2));
485 apps_grid_view_
->EndDrag(false);
486 EXPECT_EQ(std::string("Item 0,Item 1,Item 3"), model_
->GetModelContent());
487 test_api_
->LayoutToIdealBounds();
489 // Adding a launcher item cancels the drag and respects the order.
490 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
491 model_
->CreateAndAddItem("Extra");
492 apps_grid_view_
->EndDrag(false);
493 EXPECT_EQ(std::string("Item 0,Item 1,Item 3,Extra"),
494 model_
->GetModelContent());
495 test_api_
->LayoutToIdealBounds();
498 TEST_F(AppsGridViewTest
, MouseDragFlipPage
) {
499 test_api_
->SetPageFlipDelay(10);
500 GetPaginationModel()->SetTransitionDurations(10, 10);
502 PageFlipWaiter
page_flip_waiter(message_loop(), GetPaginationModel());
504 const int kPages
= 3;
505 model_
->PopulateApps(kPages
* kTilesPerPage
);
506 EXPECT_EQ(kPages
, GetPaginationModel()->total_pages());
507 EXPECT_EQ(0, GetPaginationModel()->selected_page());
509 gfx::Point from
= GetItemTileRectAt(0, 0).CenterPoint();
510 gfx::Point to
= gfx::Point(apps_grid_view_
->width(),
511 apps_grid_view_
->height() / 2);
513 // Drag to right edge.
514 page_flip_waiter
.Reset();
515 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
517 // Page should be flipped after sometime to hit page 1 and 2 then stop.
518 while (test_api_
->HasPendingPageFlip()) {
519 page_flip_waiter
.Wait();
521 EXPECT_EQ("1,2", page_flip_waiter
.selected_pages());
522 EXPECT_EQ(2, GetPaginationModel()->selected_page());
524 apps_grid_view_
->EndDrag(true);
526 // Now drag to the left edge and test the other direction.
529 page_flip_waiter
.Reset();
530 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
532 while (test_api_
->HasPendingPageFlip()) {
533 page_flip_waiter
.Wait();
535 EXPECT_EQ("1,0", page_flip_waiter
.selected_pages());
536 EXPECT_EQ(0, GetPaginationModel()->selected_page());
538 apps_grid_view_
->EndDrag(true);
541 TEST_F(AppsGridViewTest
, SimultaneousDragWithFolderDisabled
) {
542 model_
->SetFoldersEnabled(false);
543 const int kTotalItems
= 4;
544 model_
->PopulateApps(kTotalItems
);
545 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
546 model_
->GetModelContent());
548 gfx::Point mouse_from
= GetItemTileRectAt(0, 0).CenterPoint();
549 gfx::Point mouse_to
= GetItemTileRectAt(0, 1).CenterPoint();
551 gfx::Point touch_from
= GetItemTileRectAt(1, 0).CenterPoint();
552 gfx::Point touch_to
= GetItemTileRectAt(1, 1).CenterPoint();
554 // Starts a mouse drag first then a touch drag.
555 SimulateDrag(AppsGridView::MOUSE
, mouse_from
, mouse_to
);
556 SimulateDrag(AppsGridView::TOUCH
, touch_from
, touch_to
);
557 // Finishes the drag and mouse drag wins.
558 apps_grid_view_
->EndDrag(false);
559 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
560 model_
->GetModelContent());
561 test_api_
->LayoutToIdealBounds();
563 // Starts a touch drag first then a mouse drag.
564 SimulateDrag(AppsGridView::TOUCH
, touch_from
, touch_to
);
565 SimulateDrag(AppsGridView::MOUSE
, mouse_from
, mouse_to
);
566 // Finishes the drag and touch drag wins.
567 apps_grid_view_
->EndDrag(false);
568 EXPECT_EQ(std::string("Item 1,Item 0,Item 3,Item 2"),
569 model_
->GetModelContent());
570 test_api_
->LayoutToIdealBounds();
573 TEST_F(AppsGridViewTest
, UpdateFolderBackgroundOnCancelDrag
) {
574 EnsureFoldersEnabled();
576 const int kTotalItems
= 4;
577 TestAppsGridViewFolderDelegate folder_delegate
;
578 apps_grid_view_
->set_folder_delegate(&folder_delegate
);
579 model_
->PopulateApps(kTotalItems
);
580 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
581 model_
->GetModelContent());
583 gfx::Point mouse_from
= GetItemTileRectAt(0, 0).CenterPoint();
584 gfx::Point mouse_to
= GetItemTileRectAt(0, 1).CenterPoint();
586 // Starts a mouse drag and then cancels it.
587 SimulateDrag(AppsGridView::MOUSE
, mouse_from
, mouse_to
);
588 EXPECT_TRUE(folder_delegate
.show_bubble());
589 apps_grid_view_
->EndDrag(true);
590 EXPECT_FALSE(folder_delegate
.show_bubble());
591 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
592 model_
->GetModelContent());
595 TEST_F(AppsGridViewTest
, HighlightWithKeyboard
) {
596 const int kPages
= 3;
597 const int kItems
= (kPages
- 1) * kTilesPerPage
+ 1;
598 model_
->PopulateApps(kItems
);
600 const int first_index
= 0;
601 const int last_index
= kItems
- 1;
602 const int last_index_on_page1_first_row
= kRows
- 1;
603 const int last_index_on_page1
= kTilesPerPage
- 1;
604 const int first_index_on_page2
= kTilesPerPage
;
605 const int first_index_on_page2_last_row
= 2 * kTilesPerPage
- kRows
;
606 const int last_index_on_page2_last_row
= 2 * kTilesPerPage
- 1;
608 // Try moving off the item beyond the first one.
609 apps_grid_view_
->SetSelectedView(GetItemViewAt(first_index
));
610 SimulateKeyPress(ui::VKEY_UP
);
611 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(first_index
)));
612 SimulateKeyPress(ui::VKEY_LEFT
);
613 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(first_index
)));
615 // Move to the last item and try to go past it.
616 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index
));
617 SimulateKeyPress(ui::VKEY_DOWN
);
618 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(last_index
)));
619 SimulateKeyPress(ui::VKEY_RIGHT
);
620 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(last_index
)));
622 // Move right on last item on page 1 should get to first item on page 2's last
623 // row and vice versa.
624 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index_on_page1
));
625 SimulateKeyPress(ui::VKEY_RIGHT
);
626 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
627 first_index_on_page2_last_row
)));
628 SimulateKeyPress(ui::VKEY_LEFT
);
629 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
630 last_index_on_page1
)));
632 // Up/down on page boundary does nothing.
633 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index_on_page1
));
634 SimulateKeyPress(ui::VKEY_DOWN
);
635 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
636 last_index_on_page1
)));
637 apps_grid_view_
->SetSelectedView(
638 GetItemViewAt(first_index_on_page2_last_row
));
640 SetSelectedView(GetItemViewAt(last_index_on_page1_first_row
));
641 SimulateKeyPress(ui::VKEY_UP
);
642 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
643 last_index_on_page1_first_row
)));
645 // Page up and down should go to the same item on the next and last page.
646 apps_grid_view_
->SetSelectedView(GetItemViewAt(first_index_on_page2
));
647 SimulateKeyPress(ui::VKEY_PRIOR
);
648 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
650 SimulateKeyPress(ui::VKEY_NEXT
);
651 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
652 first_index_on_page2
)));
654 // Moving onto a a page with too few apps to support the expected index snaps
655 // to the last available index.
656 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row
));
657 SimulateKeyPress(ui::VKEY_RIGHT
);
658 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
660 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row
));
661 SimulateKeyPress(ui::VKEY_NEXT
);
662 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
667 // After page switch, arrow keys select first item on current page.
668 apps_grid_view_
->SetSelectedView(GetItemViewAt(first_index
));
669 GetPaginationModel()->SelectPage(1, false);
670 SimulateKeyPress(ui::VKEY_UP
);
671 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
672 first_index_on_page2
)));
675 TEST_F(AppsGridViewTest
, ItemLabelShortNameOverride
) {
676 // If the app's full name and short name differ, the title label's tooltip
677 // should always be the full name of the app.
678 std::string
expected_text("xyz");
679 std::string
expected_tooltip("tooltip");
680 AppListItem
* item
= model_
->CreateAndAddItem("Item with short name");
681 model_
->SetItemNameAndShortName(item
, expected_tooltip
, expected_text
);
683 base::string16 actual_tooltip
;
684 AppListItemView
* item_view
= GetItemViewAt(0);
685 ASSERT_TRUE(item_view
);
686 const views::Label
* title_label
= item_view
->title();
687 EXPECT_TRUE(title_label
->GetTooltipText(
688 title_label
->bounds().CenterPoint(), &actual_tooltip
));
689 EXPECT_EQ(expected_tooltip
, base::UTF16ToUTF8(actual_tooltip
));
690 EXPECT_EQ(expected_text
, base::UTF16ToUTF8(title_label
->text()));
693 TEST_F(AppsGridViewTest
, ItemLabelNoShortName
) {
694 // If the app's full name and short name are the same, use the default tooltip
695 // behavior of the label (only show a tooltip if the title is truncated).
696 std::string
title("a");
697 AppListItem
* item
= model_
->CreateAndAddItem(title
);
698 model_
->SetItemNameAndShortName(item
, title
, "");
700 base::string16 actual_tooltip
;
701 AppListItemView
* item_view
= GetItemViewAt(0);
702 ASSERT_TRUE(item_view
);
703 const views::Label
* title_label
= item_view
->title();
704 EXPECT_FALSE(title_label
->GetTooltipText(
705 title_label
->bounds().CenterPoint(), &actual_tooltip
));
706 EXPECT_EQ(title
, base::UTF16ToUTF8(title_label
->text()));
710 } // namespace app_list