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/utf_string_conversions.h"
15 #include "base/timer/timer.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), page_changed_(false) {
46 model_
->AddObserver(this);
49 virtual ~PageFlipWaiter() {
50 model_
->RemoveObserver(this);
53 bool Wait(int time_out_ms
) {
56 page_changed_
= false;
60 wait_timer_
.Start(FROM_HERE
,
61 base::TimeDelta::FromMilliseconds(time_out_ms
),
62 this, &PageFlipWaiter::OnWaitTimeOut
);
71 void OnWaitTimeOut() {
75 // PaginationModelObserver overrides:
76 virtual void TotalPagesChanged() OVERRIDE
{
78 virtual void SelectedPageChanged(int old_selected
,
79 int new_selected
) OVERRIDE
{
84 virtual void TransitionStarted() OVERRIDE
{
86 virtual void TransitionChanged() OVERRIDE
{
89 base::MessageLoopForUI
* ui_loop_
;
90 PaginationModel
* model_
;
93 base::OneShotTimer
<PageFlipWaiter
> wait_timer_
;
95 DISALLOW_COPY_AND_ASSIGN(PageFlipWaiter
);
100 class AppsGridViewTest
: public views::ViewsTestBase
{
102 AppsGridViewTest() {}
103 virtual ~AppsGridViewTest() {}
105 // testing::Test overrides:
106 virtual void SetUp() OVERRIDE
{
107 views::ViewsTestBase::SetUp();
108 model_
.reset(new AppListTestModel
);
109 pagination_model_
.reset(new PaginationModel
);
111 apps_grid_view_
.reset(new AppsGridView(NULL
, pagination_model_
.get()));
112 apps_grid_view_
->SetLayout(kIconDimension
, kCols
, kRows
);
113 apps_grid_view_
->SetBoundsRect(gfx::Rect(gfx::Size(kWidth
, kHeight
)));
114 apps_grid_view_
->SetModel(model_
.get());
115 apps_grid_view_
->SetItemList(model_
->top_level_item_list());
117 test_api_
.reset(new AppsGridViewTestApi(apps_grid_view_
.get()));
119 virtual void TearDown() OVERRIDE
{
120 apps_grid_view_
.reset(); // Release apps grid view before models.
121 views::ViewsTestBase::TearDown();
125 void EnsureFoldersEnabled() {
126 // Folders require AppList sync to be enabled.
127 CommandLine::ForCurrentProcess()->AppendSwitch(
128 switches::kEnableSyncAppList
);
131 AppListItemView
* GetItemViewAt(int index
) {
132 return static_cast<AppListItemView
*>(
133 test_api_
->GetViewAtModelIndex(index
));
136 AppListItemView
* GetItemViewForPoint(const gfx::Point
& point
) {
137 for (size_t i
= 0; i
< model_
->top_level_item_list()->item_count(); ++i
) {
138 AppListItemView
* view
= GetItemViewAt(i
);
139 if (view
->bounds().Contains(point
))
145 gfx::Rect
GetItemTileRectAt(int row
, int col
) {
146 DCHECK_GT(model_
->top_level_item_list()->item_count(), 0u);
148 gfx::Insets
insets(apps_grid_view_
->GetInsets());
149 gfx::Rect
rect(gfx::Point(insets
.left(), insets
.top()),
150 GetItemViewAt(0)->bounds().size());
151 rect
.Offset(col
* rect
.width(), row
* rect
.height());
155 // Points are in |apps_grid_view_|'s coordinates.
156 void SimulateDrag(AppsGridView::Pointer pointer
,
157 const gfx::Point
& from
,
158 const gfx::Point
& to
) {
159 AppListItemView
* view
= GetItemViewForPoint(from
);
162 gfx::Point translated_from
= gfx::PointAtOffsetFromOrigin(
163 from
- view
->bounds().origin());
164 gfx::Point translated_to
= gfx::PointAtOffsetFromOrigin(
165 to
- view
->bounds().origin());
167 ui::MouseEvent
pressed_event(ui::ET_MOUSE_PRESSED
,
168 translated_from
, from
, 0, 0);
169 apps_grid_view_
->InitiateDrag(view
, pointer
, pressed_event
);
171 ui::MouseEvent
drag_event(ui::ET_MOUSE_DRAGGED
,
172 translated_to
, to
, 0, 0);
173 apps_grid_view_
->UpdateDragFromItem(pointer
, drag_event
);
176 void SimulateKeyPress(ui::KeyboardCode key_code
) {
177 ui::KeyEvent
key_event(ui::ET_KEY_PRESSED
, key_code
, 0, false);
178 apps_grid_view_
->OnKeyPressed(key_event
);
181 scoped_ptr
<AppListTestModel
> model_
;
182 scoped_ptr
<PaginationModel
> pagination_model_
;
183 scoped_ptr
<AppsGridView
> apps_grid_view_
;
184 scoped_ptr
<AppsGridViewTestApi
> test_api_
;
187 DISALLOW_COPY_AND_ASSIGN(AppsGridViewTest
);
190 class TestAppsGridViewFolderDelegate
: public AppsGridViewFolderDelegate
{
192 TestAppsGridViewFolderDelegate() : show_bubble_(false) {}
193 virtual ~TestAppsGridViewFolderDelegate() {}
195 // Overridden from AppsGridViewFolderDelegate:
196 virtual void UpdateFolderViewBackground(bool show_bubble
) OVERRIDE
{
197 show_bubble_
= show_bubble
;
200 virtual void ReparentItem(AppListItemView
* original_drag_view
,
201 const gfx::Point
& drag_point_in_folder_grid
)
204 virtual void DispatchDragEventForReparent(
205 AppsGridView::Pointer pointer
,
206 const gfx::Point
& drag_point_in_folder_grid
) OVERRIDE
{}
208 virtual void DispatchEndDragEventForReparent(
209 bool events_forwarded_to_drag_drop_host
,
210 bool cancel_drag
) OVERRIDE
{}
212 virtual bool IsPointOutsideOfFolderBoundary(const gfx::Point
& point
)
217 virtual bool IsOEMFolder() const OVERRIDE
{ return false; }
219 virtual void SetRootLevelDragViewVisible(bool visible
) OVERRIDE
{}
221 bool show_bubble() { return show_bubble_
; }
226 DISALLOW_COPY_AND_ASSIGN(TestAppsGridViewFolderDelegate
);
229 TEST_F(AppsGridViewTest
, CreatePage
) {
230 // Fully populates a page.
231 const int kPages
= 1;
232 model_
->PopulateApps(kPages
* kTilesPerPage
);
233 EXPECT_EQ(kPages
, pagination_model_
->total_pages());
235 // Adds one more and gets a new page created.
236 model_
->CreateAndAddItem("Extra");
237 EXPECT_EQ(kPages
+ 1, pagination_model_
->total_pages());
240 TEST_F(AppsGridViewTest
, EnsureHighlightedVisible
) {
241 const int kPages
= 3;
242 model_
->PopulateApps(kPages
* kTilesPerPage
);
243 EXPECT_EQ(kPages
, pagination_model_
->total_pages());
244 EXPECT_EQ(0, pagination_model_
->selected_page());
246 // Highlight first one and last one one first page and first page should be
248 model_
->HighlightItemAt(0);
249 EXPECT_EQ(0, pagination_model_
->selected_page());
250 model_
->HighlightItemAt(kTilesPerPage
- 1);
251 EXPECT_EQ(0, pagination_model_
->selected_page());
253 // Highlight first one on 2nd page and 2nd page should be selected.
254 model_
->HighlightItemAt(kTilesPerPage
+ 1);
255 EXPECT_EQ(1, pagination_model_
->selected_page());
257 // Highlight last one in the model and last page should be selected.
258 model_
->HighlightItemAt(model_
->top_level_item_list()->item_count() - 1);
259 EXPECT_EQ(kPages
- 1, pagination_model_
->selected_page());
262 TEST_F(AppsGridViewTest
, RemoveSelectedLastApp
) {
263 const int kTotalItems
= 2;
264 const int kLastItemIndex
= kTotalItems
- 1;
266 model_
->PopulateApps(kTotalItems
);
268 AppListItemView
* last_view
= GetItemViewAt(kLastItemIndex
);
269 apps_grid_view_
->SetSelectedView(last_view
);
270 model_
->DeleteItem(model_
->GetItemName(kLastItemIndex
));
272 EXPECT_FALSE(apps_grid_view_
->IsSelectedView(last_view
));
275 AppListItemView
* view
= GetItemViewAt(0);
276 apps_grid_view_
->SetSelectedView(view
);
277 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(view
));
280 TEST_F(AppsGridViewTest
, MouseDragWithFolderDisabled
) {
281 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kDisableSyncAppList
);
282 const int kTotalItems
= 4;
283 model_
->PopulateApps(kTotalItems
);
284 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
285 model_
->GetModelContent());
287 gfx::Point from
= GetItemTileRectAt(0, 0).CenterPoint();
288 gfx::Point to
= GetItemTileRectAt(0, 1).CenterPoint();
290 // Dragging changes model order.
291 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
292 apps_grid_view_
->EndDrag(false);
293 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
294 model_
->GetModelContent());
295 test_api_
->LayoutToIdealBounds();
297 // Canceling drag should keep existing order.
298 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
299 apps_grid_view_
->EndDrag(true);
300 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
301 model_
->GetModelContent());
302 test_api_
->LayoutToIdealBounds();
304 // Deleting an item keeps remaining intact.
305 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
306 model_
->DeleteItem(model_
->GetItemName(0));
307 apps_grid_view_
->EndDrag(false);
308 EXPECT_EQ(std::string("Item 1,Item 2,Item 3"),
309 model_
->GetModelContent());
310 test_api_
->LayoutToIdealBounds();
312 // Adding a launcher item cancels the drag and respects the order.
313 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
314 model_
->CreateAndAddItem("Extra");
315 apps_grid_view_
->EndDrag(false);
316 EXPECT_EQ(std::string("Item 1,Item 2,Item 3,Extra"),
317 model_
->GetModelContent());
318 test_api_
->LayoutToIdealBounds();
321 TEST_F(AppsGridViewTest
, MouseDragItemIntoFolder
) {
322 EnsureFoldersEnabled();
324 size_t kTotalItems
= 3;
325 model_
->PopulateApps(kTotalItems
);
326 EXPECT_EQ(model_
->top_level_item_list()->item_count(), kTotalItems
);
327 EXPECT_EQ(std::string("Item 0,Item 1,Item 2"), model_
->GetModelContent());
329 gfx::Point from
= GetItemTileRectAt(0, 1).CenterPoint();
330 gfx::Point to
= GetItemTileRectAt(0, 0).CenterPoint();
332 // Dragging item_1 over item_0 creates a folder.
333 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
334 apps_grid_view_
->EndDrag(false);
335 EXPECT_EQ(kTotalItems
- 1, model_
->top_level_item_list()->item_count());
336 EXPECT_EQ(AppListFolderItem::kItemType
,
337 model_
->top_level_item_list()->item_at(0)->GetItemType());
338 AppListFolderItem
* folder_item
= static_cast<AppListFolderItem
*>(
339 model_
->top_level_item_list()->item_at(0));
340 EXPECT_EQ(2u, folder_item
->ChildItemCount());
341 AppListItem
* item_0
= model_
->FindItem("Item 0");
342 EXPECT_TRUE(item_0
->IsInFolder());
343 EXPECT_EQ(folder_item
->id(), item_0
->folder_id());
344 AppListItem
* item_1
= model_
->FindItem("Item 1");
345 EXPECT_TRUE(item_1
->IsInFolder());
346 EXPECT_EQ(folder_item
->id(), item_1
->folder_id());
347 std::string expected_items
= folder_item
->id() + ",Item 2";
348 EXPECT_EQ(expected_items
, model_
->GetModelContent());
349 test_api_
->LayoutToIdealBounds();
351 // Dragging item_2 to the folder adds item_2 to the folder.
352 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
353 apps_grid_view_
->EndDrag(false);
355 EXPECT_EQ(kTotalItems
- 2, model_
->top_level_item_list()->item_count());
356 EXPECT_EQ(folder_item
->id(), model_
->GetModelContent());
357 EXPECT_EQ(3u, folder_item
->ChildItemCount());
358 item_0
= model_
->FindItem("Item 0");
359 EXPECT_TRUE(item_0
->IsInFolder());
360 EXPECT_EQ(folder_item
->id(), item_0
->folder_id());
361 item_1
= model_
->FindItem("Item 1");
362 EXPECT_TRUE(item_1
->IsInFolder());
363 EXPECT_EQ(folder_item
->id(), item_1
->folder_id());
364 AppListItem
* item_2
= model_
->FindItem("Item 2");
365 EXPECT_TRUE(item_2
->IsInFolder());
366 EXPECT_EQ(folder_item
->id(), item_2
->folder_id());
367 test_api_
->LayoutToIdealBounds();
370 TEST_F(AppsGridViewTest
, MouseDragMaxItemsInFolder
) {
371 EnsureFoldersEnabled();
373 // Create and add a folder with 15 items in it.
374 size_t kTotalItems
= kMaxFolderItems
- 1;
375 model_
->CreateAndPopulateFolderWithApps(kTotalItems
);
376 EXPECT_EQ(1u, model_
->top_level_item_list()->item_count());
377 EXPECT_EQ(AppListFolderItem::kItemType
,
378 model_
->top_level_item_list()->item_at(0)->GetItemType());
379 AppListFolderItem
* folder_item
= static_cast<AppListFolderItem
*>(
380 model_
->top_level_item_list()->item_at(0));
381 EXPECT_EQ(kTotalItems
, folder_item
->ChildItemCount());
383 // Create and add another 2 items.
384 model_
->PopulateAppWithId(kTotalItems
);
385 model_
->PopulateAppWithId(kTotalItems
+ 1);
386 EXPECT_EQ(3u, model_
->top_level_item_list()->item_count());
387 EXPECT_EQ(folder_item
->id(), model_
->top_level_item_list()->item_at(0)->id());
388 EXPECT_EQ(model_
->GetItemName(kMaxFolderItems
- 1),
389 model_
->top_level_item_list()->item_at(1)->id());
390 EXPECT_EQ(model_
->GetItemName(kMaxFolderItems
),
391 model_
->top_level_item_list()->item_at(2)->id());
393 gfx::Point from
= GetItemTileRectAt(0, 1).CenterPoint();
394 gfx::Point to
= GetItemTileRectAt(0, 0).CenterPoint();
396 // Dragging one item into the folder, the folder should accept the item.
397 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
398 apps_grid_view_
->EndDrag(false);
399 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
400 EXPECT_EQ(folder_item
->id(), model_
->top_level_item_list()->item_at(0)->id());
401 EXPECT_EQ(kMaxFolderItems
, folder_item
->ChildItemCount());
402 EXPECT_EQ(model_
->GetItemName(kMaxFolderItems
),
403 model_
->top_level_item_list()->item_at(1)->id());
404 test_api_
->LayoutToIdealBounds();
406 // Dragging the last item over the folder, the folder won't accept the new
407 // item, instead, it will re-order the items.
408 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
409 apps_grid_view_
->EndDrag(false);
410 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
411 EXPECT_EQ(model_
->GetItemName(kMaxFolderItems
),
412 model_
->top_level_item_list()->item_at(0)->id());
413 EXPECT_EQ(folder_item
->id(), model_
->top_level_item_list()->item_at(1)->id());
414 EXPECT_EQ(kMaxFolderItems
, folder_item
->ChildItemCount());
415 test_api_
->LayoutToIdealBounds();
418 TEST_F(AppsGridViewTest
, MouseDragItemReorder
) {
419 // This test assumes Folders are enabled.
420 EnsureFoldersEnabled();
422 size_t kTotalItems
= 2;
423 model_
->PopulateApps(kTotalItems
);
424 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
425 EXPECT_EQ(std::string("Item 0,Item 1"), model_
->GetModelContent());
427 gfx::Point from
= GetItemTileRectAt(0, 1).CenterPoint();
428 int reorder_offset
= (GetItemTileRectAt(0, 1).CenterPoint() -
429 GetItemTileRectAt(0, 0).CenterPoint()).Length() -
430 kReorderDroppingCircleRadius
-
431 kPreferredIconDimension
/ 2 + 5;
432 gfx::Point to
= gfx::Point(from
.x() - reorder_offset
, from
.y());
434 // Dragging item_1 closing to item_0 should leads to re-ordering these two
436 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
437 apps_grid_view_
->EndDrag(false);
438 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
439 EXPECT_EQ(std::string("Item 1,Item 0"), model_
->GetModelContent());
440 test_api_
->LayoutToIdealBounds();
443 TEST_F(AppsGridViewTest
, MouseDragFolderReorder
) {
444 EnsureFoldersEnabled();
446 size_t kTotalItems
= 2;
447 model_
->CreateAndPopulateFolderWithApps(kTotalItems
);
448 model_
->PopulateAppWithId(kTotalItems
);
449 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
450 EXPECT_EQ(AppListFolderItem::kItemType
,
451 model_
->top_level_item_list()->item_at(0)->GetItemType());
452 AppListFolderItem
* folder_item
= static_cast<AppListFolderItem
*>(
453 model_
->top_level_item_list()->item_at(0));
454 EXPECT_EQ("Item 2", model_
->top_level_item_list()->item_at(1)->id());
456 gfx::Point from
= GetItemTileRectAt(0, 0).CenterPoint();
457 gfx::Point to
= GetItemTileRectAt(0, 1).CenterPoint();
459 // Dragging folder over item_1 should leads to re-ordering these two
461 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
462 apps_grid_view_
->EndDrag(false);
463 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
464 EXPECT_EQ("Item 2", model_
->top_level_item_list()->item_at(0)->id());
465 EXPECT_EQ(folder_item
->id(), model_
->top_level_item_list()->item_at(1)->id());
466 test_api_
->LayoutToIdealBounds();
469 TEST_F(AppsGridViewTest
, MouseDragWithCancelDeleteAddItem
) {
470 size_t kTotalItems
= 4;
471 model_
->PopulateApps(kTotalItems
);
472 EXPECT_EQ(model_
->top_level_item_list()->item_count(), kTotalItems
);
473 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
474 model_
->GetModelContent());
476 gfx::Point from
= GetItemTileRectAt(0, 0).CenterPoint();
477 gfx::Point to
= GetItemTileRectAt(0, 1).CenterPoint();
479 // Canceling drag should keep existing order.
480 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
481 apps_grid_view_
->EndDrag(true);
482 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
483 model_
->GetModelContent());
484 test_api_
->LayoutToIdealBounds();
486 // Deleting an item keeps remaining intact.
487 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
488 model_
->DeleteItem(model_
->GetItemName(2));
489 apps_grid_view_
->EndDrag(false);
490 EXPECT_EQ(std::string("Item 0,Item 1,Item 3"), model_
->GetModelContent());
491 test_api_
->LayoutToIdealBounds();
493 // Adding a launcher item cancels the drag and respects the order.
494 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
495 model_
->CreateAndAddItem("Extra");
496 apps_grid_view_
->EndDrag(false);
497 EXPECT_EQ(std::string("Item 0,Item 1,Item 3,Extra"),
498 model_
->GetModelContent());
499 test_api_
->LayoutToIdealBounds();
502 TEST_F(AppsGridViewTest
, MouseDragFlipPage
) {
503 test_api_
->SetPageFlipDelay(10);
504 pagination_model_
->SetTransitionDurations(10, 10);
506 PageFlipWaiter
page_flip_waiter(message_loop(),
507 pagination_model_
.get());
509 const int kPages
= 3;
510 model_
->PopulateApps(kPages
* kTilesPerPage
);
511 EXPECT_EQ(kPages
, pagination_model_
->total_pages());
512 EXPECT_EQ(0, pagination_model_
->selected_page());
514 gfx::Point from
= GetItemTileRectAt(0, 0).CenterPoint();
515 gfx::Point to
= gfx::Point(apps_grid_view_
->width(),
516 apps_grid_view_
->height() / 2);
518 // Drag to right edge.
519 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
521 // Page should be flipped after sometime.
522 EXPECT_TRUE(page_flip_waiter
.Wait(0));
523 EXPECT_EQ(1, pagination_model_
->selected_page());
525 // Stay there and page should be flipped again.
526 EXPECT_TRUE(page_flip_waiter
.Wait(0));
527 EXPECT_EQ(2, pagination_model_
->selected_page());
529 // Stay there longer and no page flip happen since we are at the last page.
530 EXPECT_FALSE(page_flip_waiter
.Wait(100));
531 EXPECT_EQ(2, pagination_model_
->selected_page());
533 apps_grid_view_
->EndDrag(true);
535 // Now drag to the left edge and test the other direction.
538 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
540 EXPECT_TRUE(page_flip_waiter
.Wait(0));
541 EXPECT_EQ(1, pagination_model_
->selected_page());
543 EXPECT_TRUE(page_flip_waiter
.Wait(0));
544 EXPECT_EQ(0, pagination_model_
->selected_page());
546 EXPECT_FALSE(page_flip_waiter
.Wait(100));
547 EXPECT_EQ(0, pagination_model_
->selected_page());
548 apps_grid_view_
->EndDrag(true);
551 TEST_F(AppsGridViewTest
, SimultaneousDragWithFolderDisabled
) {
552 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kDisableSyncAppList
);
553 const int kTotalItems
= 4;
554 model_
->PopulateApps(kTotalItems
);
555 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
556 model_
->GetModelContent());
558 gfx::Point mouse_from
= GetItemTileRectAt(0, 0).CenterPoint();
559 gfx::Point mouse_to
= GetItemTileRectAt(0, 1).CenterPoint();
561 gfx::Point touch_from
= GetItemTileRectAt(1, 0).CenterPoint();
562 gfx::Point touch_to
= GetItemTileRectAt(1, 1).CenterPoint();
564 // Starts a mouse drag first then a touch drag.
565 SimulateDrag(AppsGridView::MOUSE
, mouse_from
, mouse_to
);
566 SimulateDrag(AppsGridView::TOUCH
, touch_from
, touch_to
);
567 // Finishes the drag and mouse drag wins.
568 apps_grid_view_
->EndDrag(false);
569 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
570 model_
->GetModelContent());
571 test_api_
->LayoutToIdealBounds();
573 // Starts a touch drag first then a mouse drag.
574 SimulateDrag(AppsGridView::TOUCH
, touch_from
, touch_to
);
575 SimulateDrag(AppsGridView::MOUSE
, mouse_from
, mouse_to
);
576 // Finishes the drag and touch drag wins.
577 apps_grid_view_
->EndDrag(false);
578 EXPECT_EQ(std::string("Item 1,Item 0,Item 3,Item 2"),
579 model_
->GetModelContent());
580 test_api_
->LayoutToIdealBounds();
583 TEST_F(AppsGridViewTest
, UpdateFolderBackgroundOnCancelDrag
) {
584 EnsureFoldersEnabled();
586 const int kTotalItems
= 4;
587 TestAppsGridViewFolderDelegate folder_delegate
;
588 apps_grid_view_
->set_folder_delegate(&folder_delegate
);
589 model_
->PopulateApps(kTotalItems
);
590 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
591 model_
->GetModelContent());
593 gfx::Point mouse_from
= GetItemTileRectAt(0, 0).CenterPoint();
594 gfx::Point mouse_to
= GetItemTileRectAt(0, 1).CenterPoint();
596 // Starts a mouse drag and then cancels it.
597 SimulateDrag(AppsGridView::MOUSE
, mouse_from
, mouse_to
);
598 EXPECT_TRUE(folder_delegate
.show_bubble());
599 apps_grid_view_
->EndDrag(true);
600 EXPECT_FALSE(folder_delegate
.show_bubble());
601 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
602 model_
->GetModelContent());
605 TEST_F(AppsGridViewTest
, HighlightWithKeyboard
) {
606 const int kPages
= 3;
607 const int kItems
= (kPages
- 1) * kTilesPerPage
+ 1;
608 model_
->PopulateApps(kItems
);
610 const int first_index
= 0;
611 const int last_index
= kItems
- 1;
612 const int last_index_on_page1_first_row
= kRows
- 1;
613 const int last_index_on_page1
= kTilesPerPage
- 1;
614 const int first_index_on_page2
= kTilesPerPage
;
615 const int first_index_on_page2_last_row
= 2 * kTilesPerPage
- kRows
;
616 const int last_index_on_page2_last_row
= 2 * kTilesPerPage
- 1;
618 // Try moving off the item beyond the first one.
619 apps_grid_view_
->SetSelectedView(GetItemViewAt(first_index
));
620 SimulateKeyPress(ui::VKEY_UP
);
621 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(first_index
)));
622 SimulateKeyPress(ui::VKEY_LEFT
);
623 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(first_index
)));
625 // Move to the last item and try to go past it.
626 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index
));
627 SimulateKeyPress(ui::VKEY_DOWN
);
628 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(last_index
)));
629 SimulateKeyPress(ui::VKEY_RIGHT
);
630 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(last_index
)));
632 // Move right on last item on page 1 should get to first item on page 2's last
633 // row and vice versa.
634 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index_on_page1
));
635 SimulateKeyPress(ui::VKEY_RIGHT
);
636 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
637 first_index_on_page2_last_row
)));
638 SimulateKeyPress(ui::VKEY_LEFT
);
639 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
640 last_index_on_page1
)));
642 // Up/down on page boundary does nothing.
643 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index_on_page1
));
644 SimulateKeyPress(ui::VKEY_DOWN
);
645 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
646 last_index_on_page1
)));
647 apps_grid_view_
->SetSelectedView(
648 GetItemViewAt(first_index_on_page2_last_row
));
650 SetSelectedView(GetItemViewAt(last_index_on_page1_first_row
));
651 SimulateKeyPress(ui::VKEY_UP
);
652 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
653 last_index_on_page1_first_row
)));
655 // Page up and down should go to the same item on the next and last page.
656 apps_grid_view_
->SetSelectedView(GetItemViewAt(first_index_on_page2
));
657 SimulateKeyPress(ui::VKEY_PRIOR
);
658 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
660 SimulateKeyPress(ui::VKEY_NEXT
);
661 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
662 first_index_on_page2
)));
664 // Moving onto a a page with too few apps to support the expected index snaps
665 // to the last available index.
666 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row
));
667 SimulateKeyPress(ui::VKEY_RIGHT
);
668 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
670 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row
));
671 SimulateKeyPress(ui::VKEY_NEXT
);
672 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
677 // After page switch, arrow keys select first item on current page.
678 apps_grid_view_
->SetSelectedView(GetItemViewAt(first_index
));
679 pagination_model_
->SelectPage(1, false);
680 SimulateKeyPress(ui::VKEY_UP
);
681 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
682 first_index_on_page2
)));
685 TEST_F(AppsGridViewTest
, ItemLabelShortNameOverride
) {
686 // If the app's full name and short name differ, the title label's tooltip
687 // should always be the full name of the app.
688 std::string
expected_text("xyz");
689 std::string
expected_tooltip("tooltip");
690 AppListItem
* item
= model_
->CreateAndAddItem("Item with short name");
691 model_
->SetItemNameAndShortName(item
, expected_tooltip
, expected_text
);
693 base::string16 actual_tooltip
;
694 AppListItemView
* item_view
= GetItemViewAt(0);
695 ASSERT_TRUE(item_view
);
696 const views::Label
* title_label
= item_view
->title();
697 EXPECT_TRUE(title_label
->GetTooltipText(
698 title_label
->bounds().CenterPoint(), &actual_tooltip
));
699 EXPECT_EQ(expected_tooltip
, base::UTF16ToUTF8(actual_tooltip
));
700 EXPECT_EQ(expected_text
, base::UTF16ToUTF8(title_label
->text()));
703 TEST_F(AppsGridViewTest
, ItemLabelNoShortName
) {
704 // If the app's full name and short name are the same, use the default tooltip
705 // behavior of the label (only show a tooltip if the title is truncated).
706 std::string
title("a");
707 AppListItem
* item
= model_
->CreateAndAddItem(title
);
708 model_
->SetItemNameAndShortName(item
, title
, "");
710 base::string16 actual_tooltip
;
711 AppListItemView
* item_view
= GetItemViewAt(0);
712 ASSERT_TRUE(item_view
);
713 const views::Label
* title_label
= item_view
->title();
714 EXPECT_FALSE(title_label
->GetTooltipText(
715 title_label
->bounds().CenterPoint(), &actual_tooltip
));
716 EXPECT_EQ(title
, base::UTF16ToUTF8(title_label
->text()));
720 } // namespace app_list