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"
36 const int kTilesPerPage
= kCols
* kRows
;
38 const int kWidth
= 320;
39 const int kHeight
= 240;
41 class PageFlipWaiter
: public PaginationModelObserver
{
43 PageFlipWaiter(base::MessageLoopForUI
* ui_loop
, PaginationModel
* model
)
44 : ui_loop_(ui_loop
), model_(model
), wait_(false) {
45 model_
->AddObserver(this);
48 virtual ~PageFlipWaiter() {
49 model_
->RemoveObserver(this);
60 void Reset() { selected_pages_
.clear(); }
62 const std::string
& selected_pages() const { return selected_pages_
; }
65 // PaginationModelObserver overrides:
66 virtual void TotalPagesChanged() OVERRIDE
{
68 virtual void SelectedPageChanged(int old_selected
,
69 int new_selected
) OVERRIDE
{
70 if (!selected_pages_
.empty())
71 selected_pages_
+= ',';
72 selected_pages_
+= base::IntToString(new_selected
);
77 virtual void TransitionStarted() OVERRIDE
{
79 virtual void TransitionChanged() OVERRIDE
{
82 base::MessageLoopForUI
* ui_loop_
;
83 PaginationModel
* model_
;
85 std::string selected_pages_
;
87 DISALLOW_COPY_AND_ASSIGN(PageFlipWaiter
);
92 class AppsGridViewTest
: public views::ViewsTestBase
{
95 virtual ~AppsGridViewTest() {}
97 // testing::Test overrides:
98 virtual void SetUp() OVERRIDE
{
99 views::ViewsTestBase::SetUp();
100 model_
.reset(new AppListTestModel
);
101 model_
->SetFoldersEnabled(true);
103 apps_grid_view_
.reset(new AppsGridView(NULL
));
104 apps_grid_view_
->SetLayout(kCols
, kRows
);
105 apps_grid_view_
->SetBoundsRect(gfx::Rect(gfx::Size(kWidth
, kHeight
)));
106 apps_grid_view_
->SetModel(model_
.get());
107 apps_grid_view_
->SetItemList(model_
->top_level_item_list());
109 test_api_
.reset(new AppsGridViewTestApi(apps_grid_view_
.get()));
111 virtual void TearDown() OVERRIDE
{
112 apps_grid_view_
.reset(); // Release apps grid view before models.
113 views::ViewsTestBase::TearDown();
117 void EnsureFoldersEnabled() {
118 // Folders require AppList sync to be enabled.
119 CommandLine::ForCurrentProcess()->AppendSwitch(
120 switches::kEnableSyncAppList
);
123 AppListItemView
* GetItemViewAt(int index
) {
124 return static_cast<AppListItemView
*>(
125 test_api_
->GetViewAtModelIndex(index
));
128 AppListItemView
* GetItemViewForPoint(const gfx::Point
& point
) {
129 for (size_t i
= 0; i
< model_
->top_level_item_list()->item_count(); ++i
) {
130 AppListItemView
* view
= GetItemViewAt(i
);
131 if (view
->bounds().Contains(point
))
137 gfx::Rect
GetItemTileRectAt(int row
, int col
) {
138 DCHECK_GT(model_
->top_level_item_list()->item_count(), 0u);
140 gfx::Insets
insets(apps_grid_view_
->GetInsets());
141 gfx::Rect
rect(gfx::Point(insets
.left(), insets
.top()),
142 GetItemViewAt(0)->bounds().size());
143 rect
.Offset(col
* rect
.width(), row
* rect
.height());
147 PaginationModel
* GetPaginationModel() {
148 return apps_grid_view_
->pagination_model();
151 // Points are in |apps_grid_view_|'s coordinates.
152 void SimulateDrag(AppsGridView::Pointer pointer
,
153 const gfx::Point
& from
,
154 const gfx::Point
& to
) {
155 AppListItemView
* view
= GetItemViewForPoint(from
);
158 gfx::Point translated_from
= gfx::PointAtOffsetFromOrigin(
159 from
- view
->bounds().origin());
160 gfx::Point translated_to
= gfx::PointAtOffsetFromOrigin(
161 to
- view
->bounds().origin());
163 ui::MouseEvent
pressed_event(ui::ET_MOUSE_PRESSED
,
164 translated_from
, from
, 0, 0);
165 apps_grid_view_
->InitiateDrag(view
, pointer
, pressed_event
);
167 ui::MouseEvent
drag_event(ui::ET_MOUSE_DRAGGED
,
168 translated_to
, to
, 0, 0);
169 apps_grid_view_
->UpdateDragFromItem(pointer
, drag_event
);
172 void SimulateKeyPress(ui::KeyboardCode key_code
) {
173 ui::KeyEvent
key_event(ui::ET_KEY_PRESSED
, key_code
, ui::EF_NONE
);
174 apps_grid_view_
->OnKeyPressed(key_event
);
177 scoped_ptr
<AppListTestModel
> model_
;
178 scoped_ptr
<AppsGridView
> apps_grid_view_
;
179 scoped_ptr
<AppsGridViewTestApi
> test_api_
;
182 DISALLOW_COPY_AND_ASSIGN(AppsGridViewTest
);
185 class TestAppsGridViewFolderDelegate
: public AppsGridViewFolderDelegate
{
187 TestAppsGridViewFolderDelegate() : show_bubble_(false) {}
188 virtual ~TestAppsGridViewFolderDelegate() {}
190 // Overridden from AppsGridViewFolderDelegate:
191 virtual void UpdateFolderViewBackground(bool show_bubble
) OVERRIDE
{
192 show_bubble_
= show_bubble
;
195 virtual void ReparentItem(AppListItemView
* original_drag_view
,
196 const gfx::Point
& drag_point_in_folder_grid
)
199 virtual void DispatchDragEventForReparent(
200 AppsGridView::Pointer pointer
,
201 const gfx::Point
& drag_point_in_folder_grid
) OVERRIDE
{}
203 virtual void DispatchEndDragEventForReparent(
204 bool events_forwarded_to_drag_drop_host
,
205 bool cancel_drag
) OVERRIDE
{}
207 virtual bool IsPointOutsideOfFolderBoundary(const gfx::Point
& point
)
212 virtual bool IsOEMFolder() const OVERRIDE
{ return false; }
214 virtual void SetRootLevelDragViewVisible(bool visible
) OVERRIDE
{}
216 bool show_bubble() { return show_bubble_
; }
221 DISALLOW_COPY_AND_ASSIGN(TestAppsGridViewFolderDelegate
);
224 TEST_F(AppsGridViewTest
, CreatePage
) {
225 // Fully populates a page.
226 const int kPages
= 1;
227 model_
->PopulateApps(kPages
* kTilesPerPage
);
228 EXPECT_EQ(kPages
, GetPaginationModel()->total_pages());
230 // Adds one more and gets a new page created.
231 model_
->CreateAndAddItem("Extra");
232 EXPECT_EQ(kPages
+ 1, GetPaginationModel()->total_pages());
235 TEST_F(AppsGridViewTest
, EnsureHighlightedVisible
) {
236 const int kPages
= 3;
237 model_
->PopulateApps(kPages
* kTilesPerPage
);
238 EXPECT_EQ(kPages
, GetPaginationModel()->total_pages());
239 EXPECT_EQ(0, GetPaginationModel()->selected_page());
241 // Highlight first one and last one one first page and first page should be
243 model_
->HighlightItemAt(0);
244 EXPECT_EQ(0, GetPaginationModel()->selected_page());
245 model_
->HighlightItemAt(kTilesPerPage
- 1);
246 EXPECT_EQ(0, GetPaginationModel()->selected_page());
248 // Highlight first one on 2nd page and 2nd page should be selected.
249 model_
->HighlightItemAt(kTilesPerPage
+ 1);
250 EXPECT_EQ(1, GetPaginationModel()->selected_page());
252 // Highlight last one in the model and last page should be selected.
253 model_
->HighlightItemAt(model_
->top_level_item_list()->item_count() - 1);
254 EXPECT_EQ(kPages
- 1, GetPaginationModel()->selected_page());
257 TEST_F(AppsGridViewTest
, RemoveSelectedLastApp
) {
258 const int kTotalItems
= 2;
259 const int kLastItemIndex
= kTotalItems
- 1;
261 model_
->PopulateApps(kTotalItems
);
263 AppListItemView
* last_view
= GetItemViewAt(kLastItemIndex
);
264 apps_grid_view_
->SetSelectedView(last_view
);
265 model_
->DeleteItem(model_
->GetItemName(kLastItemIndex
));
267 EXPECT_FALSE(apps_grid_view_
->IsSelectedView(last_view
));
270 AppListItemView
* view
= GetItemViewAt(0);
271 apps_grid_view_
->SetSelectedView(view
);
272 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(view
));
275 TEST_F(AppsGridViewTest
, MouseDragWithFolderDisabled
) {
276 model_
->SetFoldersEnabled(false);
277 const int kTotalItems
= 4;
278 model_
->PopulateApps(kTotalItems
);
279 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
280 model_
->GetModelContent());
282 gfx::Point from
= GetItemTileRectAt(0, 0).CenterPoint();
283 gfx::Point to
= GetItemTileRectAt(0, 1).CenterPoint();
285 // Dragging changes model order.
286 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
287 apps_grid_view_
->EndDrag(false);
288 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
289 model_
->GetModelContent());
290 test_api_
->LayoutToIdealBounds();
292 // Canceling drag should keep existing order.
293 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
294 apps_grid_view_
->EndDrag(true);
295 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
296 model_
->GetModelContent());
297 test_api_
->LayoutToIdealBounds();
299 // Deleting an item keeps remaining intact.
300 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
301 model_
->DeleteItem(model_
->GetItemName(0));
302 apps_grid_view_
->EndDrag(false);
303 EXPECT_EQ(std::string("Item 1,Item 2,Item 3"),
304 model_
->GetModelContent());
305 test_api_
->LayoutToIdealBounds();
307 // Adding a launcher item cancels the drag and respects the order.
308 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
309 EXPECT_TRUE(apps_grid_view_
->has_dragged_view());
310 model_
->CreateAndAddItem("Extra");
311 // No need to EndDrag explicitly - adding an item should do this.
312 EXPECT_FALSE(apps_grid_view_
->has_dragged_view());
313 // Even though cancelled, mouse move events can still arrive via the item
314 // view. Ensure that behaves sanely, and doesn't start a new drag.
315 ui::MouseEvent
drag_event(
316 ui::ET_MOUSE_DRAGGED
, gfx::Point(1, 1), gfx::Point(2, 2), 0, 0);
317 apps_grid_view_
->UpdateDragFromItem(AppsGridView::MOUSE
, drag_event
);
318 EXPECT_FALSE(apps_grid_view_
->has_dragged_view());
320 EXPECT_EQ(std::string("Item 1,Item 2,Item 3,Extra"),
321 model_
->GetModelContent());
322 test_api_
->LayoutToIdealBounds();
325 TEST_F(AppsGridViewTest
, MouseDragItemIntoFolder
) {
326 EnsureFoldersEnabled();
328 size_t kTotalItems
= 3;
329 model_
->PopulateApps(kTotalItems
);
330 EXPECT_EQ(model_
->top_level_item_list()->item_count(), kTotalItems
);
331 EXPECT_EQ(std::string("Item 0,Item 1,Item 2"), model_
->GetModelContent());
333 gfx::Point from
= GetItemTileRectAt(0, 1).CenterPoint();
334 gfx::Point to
= GetItemTileRectAt(0, 0).CenterPoint();
336 // Dragging item_1 over item_0 creates a folder.
337 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
338 apps_grid_view_
->EndDrag(false);
339 EXPECT_EQ(kTotalItems
- 1, model_
->top_level_item_list()->item_count());
340 EXPECT_EQ(AppListFolderItem::kItemType
,
341 model_
->top_level_item_list()->item_at(0)->GetItemType());
342 AppListFolderItem
* folder_item
= static_cast<AppListFolderItem
*>(
343 model_
->top_level_item_list()->item_at(0));
344 EXPECT_EQ(2u, folder_item
->ChildItemCount());
345 AppListItem
* item_0
= model_
->FindItem("Item 0");
346 EXPECT_TRUE(item_0
->IsInFolder());
347 EXPECT_EQ(folder_item
->id(), item_0
->folder_id());
348 AppListItem
* item_1
= model_
->FindItem("Item 1");
349 EXPECT_TRUE(item_1
->IsInFolder());
350 EXPECT_EQ(folder_item
->id(), item_1
->folder_id());
351 std::string expected_items
= folder_item
->id() + ",Item 2";
352 EXPECT_EQ(expected_items
, model_
->GetModelContent());
353 test_api_
->LayoutToIdealBounds();
355 // Dragging item_2 to the folder adds item_2 to the folder.
356 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
357 apps_grid_view_
->EndDrag(false);
359 EXPECT_EQ(kTotalItems
- 2, model_
->top_level_item_list()->item_count());
360 EXPECT_EQ(folder_item
->id(), model_
->GetModelContent());
361 EXPECT_EQ(3u, folder_item
->ChildItemCount());
362 item_0
= model_
->FindItem("Item 0");
363 EXPECT_TRUE(item_0
->IsInFolder());
364 EXPECT_EQ(folder_item
->id(), item_0
->folder_id());
365 item_1
= model_
->FindItem("Item 1");
366 EXPECT_TRUE(item_1
->IsInFolder());
367 EXPECT_EQ(folder_item
->id(), item_1
->folder_id());
368 AppListItem
* item_2
= model_
->FindItem("Item 2");
369 EXPECT_TRUE(item_2
->IsInFolder());
370 EXPECT_EQ(folder_item
->id(), item_2
->folder_id());
371 test_api_
->LayoutToIdealBounds();
374 TEST_F(AppsGridViewTest
, MouseDragMaxItemsInFolder
) {
375 EnsureFoldersEnabled();
377 // Create and add a folder with 15 items in it.
378 size_t kTotalItems
= kMaxFolderItems
- 1;
379 model_
->CreateAndPopulateFolderWithApps(kTotalItems
);
380 EXPECT_EQ(1u, model_
->top_level_item_list()->item_count());
381 EXPECT_EQ(AppListFolderItem::kItemType
,
382 model_
->top_level_item_list()->item_at(0)->GetItemType());
383 AppListFolderItem
* folder_item
= static_cast<AppListFolderItem
*>(
384 model_
->top_level_item_list()->item_at(0));
385 EXPECT_EQ(kTotalItems
, folder_item
->ChildItemCount());
387 // Create and add another 2 items.
388 model_
->PopulateAppWithId(kTotalItems
);
389 model_
->PopulateAppWithId(kTotalItems
+ 1);
390 EXPECT_EQ(3u, model_
->top_level_item_list()->item_count());
391 EXPECT_EQ(folder_item
->id(), model_
->top_level_item_list()->item_at(0)->id());
392 EXPECT_EQ(model_
->GetItemName(kMaxFolderItems
- 1),
393 model_
->top_level_item_list()->item_at(1)->id());
394 EXPECT_EQ(model_
->GetItemName(kMaxFolderItems
),
395 model_
->top_level_item_list()->item_at(2)->id());
397 gfx::Point from
= GetItemTileRectAt(0, 1).CenterPoint();
398 gfx::Point to
= GetItemTileRectAt(0, 0).CenterPoint();
400 // Dragging one item into the folder, the folder should accept the item.
401 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
402 apps_grid_view_
->EndDrag(false);
403 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
404 EXPECT_EQ(folder_item
->id(), model_
->top_level_item_list()->item_at(0)->id());
405 EXPECT_EQ(kMaxFolderItems
, folder_item
->ChildItemCount());
406 EXPECT_EQ(model_
->GetItemName(kMaxFolderItems
),
407 model_
->top_level_item_list()->item_at(1)->id());
408 test_api_
->LayoutToIdealBounds();
410 // Dragging the last item over the folder, the folder won't accept the new
411 // item, instead, it will re-order the items.
412 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
413 apps_grid_view_
->EndDrag(false);
414 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
415 EXPECT_EQ(model_
->GetItemName(kMaxFolderItems
),
416 model_
->top_level_item_list()->item_at(0)->id());
417 EXPECT_EQ(folder_item
->id(), model_
->top_level_item_list()->item_at(1)->id());
418 EXPECT_EQ(kMaxFolderItems
, folder_item
->ChildItemCount());
419 test_api_
->LayoutToIdealBounds();
422 TEST_F(AppsGridViewTest
, MouseDragItemReorder
) {
423 // This test assumes Folders are enabled.
424 EnsureFoldersEnabled();
426 size_t kTotalItems
= 2;
427 model_
->PopulateApps(kTotalItems
);
428 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
429 EXPECT_EQ(std::string("Item 0,Item 1"), model_
->GetModelContent());
431 gfx::Point from
= GetItemTileRectAt(0, 1).CenterPoint();
432 int reorder_offset
= (GetItemTileRectAt(0, 1).CenterPoint() -
433 GetItemTileRectAt(0, 0).CenterPoint()).Length() -
434 kReorderDroppingCircleRadius
- kGridIconDimension
/ 2 +
436 gfx::Point to
= gfx::Point(from
.x() - reorder_offset
, from
.y());
438 // Dragging item_1 closing to item_0 should leads to re-ordering these two
440 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
441 apps_grid_view_
->EndDrag(false);
442 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
443 EXPECT_EQ(std::string("Item 1,Item 0"), model_
->GetModelContent());
444 test_api_
->LayoutToIdealBounds();
447 TEST_F(AppsGridViewTest
, MouseDragFolderReorder
) {
448 EnsureFoldersEnabled();
450 size_t kTotalItems
= 2;
451 model_
->CreateAndPopulateFolderWithApps(kTotalItems
);
452 model_
->PopulateAppWithId(kTotalItems
);
453 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
454 EXPECT_EQ(AppListFolderItem::kItemType
,
455 model_
->top_level_item_list()->item_at(0)->GetItemType());
456 AppListFolderItem
* folder_item
= static_cast<AppListFolderItem
*>(
457 model_
->top_level_item_list()->item_at(0));
458 EXPECT_EQ("Item 2", model_
->top_level_item_list()->item_at(1)->id());
460 gfx::Point from
= GetItemTileRectAt(0, 0).CenterPoint();
461 gfx::Point to
= GetItemTileRectAt(0, 1).CenterPoint();
463 // Dragging folder over item_1 should leads to re-ordering these two
465 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
466 apps_grid_view_
->EndDrag(false);
467 EXPECT_EQ(2u, model_
->top_level_item_list()->item_count());
468 EXPECT_EQ("Item 2", model_
->top_level_item_list()->item_at(0)->id());
469 EXPECT_EQ(folder_item
->id(), model_
->top_level_item_list()->item_at(1)->id());
470 test_api_
->LayoutToIdealBounds();
473 TEST_F(AppsGridViewTest
, MouseDragWithCancelDeleteAddItem
) {
474 size_t kTotalItems
= 4;
475 model_
->PopulateApps(kTotalItems
);
476 EXPECT_EQ(model_
->top_level_item_list()->item_count(), kTotalItems
);
477 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
478 model_
->GetModelContent());
480 gfx::Point from
= GetItemTileRectAt(0, 0).CenterPoint();
481 gfx::Point to
= GetItemTileRectAt(0, 1).CenterPoint();
483 // Canceling drag should keep existing order.
484 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
485 apps_grid_view_
->EndDrag(true);
486 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
487 model_
->GetModelContent());
488 test_api_
->LayoutToIdealBounds();
490 // Deleting an item keeps remaining intact.
491 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
492 model_
->DeleteItem(model_
->GetItemName(2));
493 apps_grid_view_
->EndDrag(false);
494 EXPECT_EQ(std::string("Item 0,Item 1,Item 3"), model_
->GetModelContent());
495 test_api_
->LayoutToIdealBounds();
497 // Adding a launcher item cancels the drag and respects the order.
498 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
499 model_
->CreateAndAddItem("Extra");
500 apps_grid_view_
->EndDrag(false);
501 EXPECT_EQ(std::string("Item 0,Item 1,Item 3,Extra"),
502 model_
->GetModelContent());
503 test_api_
->LayoutToIdealBounds();
506 TEST_F(AppsGridViewTest
, MouseDragFlipPage
) {
507 test_api_
->SetPageFlipDelay(10);
508 GetPaginationModel()->SetTransitionDurations(10, 10);
510 PageFlipWaiter
page_flip_waiter(message_loop(), GetPaginationModel());
512 const int kPages
= 3;
513 model_
->PopulateApps(kPages
* kTilesPerPage
);
514 EXPECT_EQ(kPages
, GetPaginationModel()->total_pages());
515 EXPECT_EQ(0, GetPaginationModel()->selected_page());
517 gfx::Point from
= GetItemTileRectAt(0, 0).CenterPoint();
518 gfx::Point to
= gfx::Point(apps_grid_view_
->width(),
519 apps_grid_view_
->height() / 2);
521 // Drag to right edge.
522 page_flip_waiter
.Reset();
523 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
525 // Page should be flipped after sometime to hit page 1 and 2 then stop.
526 while (test_api_
->HasPendingPageFlip()) {
527 page_flip_waiter
.Wait();
529 EXPECT_EQ("1,2", page_flip_waiter
.selected_pages());
530 EXPECT_EQ(2, GetPaginationModel()->selected_page());
532 apps_grid_view_
->EndDrag(true);
534 // Now drag to the left edge and test the other direction.
537 page_flip_waiter
.Reset();
538 SimulateDrag(AppsGridView::MOUSE
, from
, to
);
540 while (test_api_
->HasPendingPageFlip()) {
541 page_flip_waiter
.Wait();
543 EXPECT_EQ("1,0", page_flip_waiter
.selected_pages());
544 EXPECT_EQ(0, GetPaginationModel()->selected_page());
546 apps_grid_view_
->EndDrag(true);
549 TEST_F(AppsGridViewTest
, SimultaneousDragWithFolderDisabled
) {
550 model_
->SetFoldersEnabled(false);
551 const int kTotalItems
= 4;
552 model_
->PopulateApps(kTotalItems
);
553 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
554 model_
->GetModelContent());
556 gfx::Point mouse_from
= GetItemTileRectAt(0, 0).CenterPoint();
557 gfx::Point mouse_to
= GetItemTileRectAt(0, 1).CenterPoint();
559 gfx::Point touch_from
= GetItemTileRectAt(1, 0).CenterPoint();
560 gfx::Point touch_to
= GetItemTileRectAt(1, 1).CenterPoint();
562 // Starts a mouse drag first then a touch drag.
563 SimulateDrag(AppsGridView::MOUSE
, mouse_from
, mouse_to
);
564 SimulateDrag(AppsGridView::TOUCH
, touch_from
, touch_to
);
565 // Finishes the drag and mouse drag wins.
566 apps_grid_view_
->EndDrag(false);
567 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
568 model_
->GetModelContent());
569 test_api_
->LayoutToIdealBounds();
571 // Starts a touch drag first then a mouse drag.
572 SimulateDrag(AppsGridView::TOUCH
, touch_from
, touch_to
);
573 SimulateDrag(AppsGridView::MOUSE
, mouse_from
, mouse_to
);
574 // Finishes the drag and touch drag wins.
575 apps_grid_view_
->EndDrag(false);
576 EXPECT_EQ(std::string("Item 1,Item 0,Item 3,Item 2"),
577 model_
->GetModelContent());
578 test_api_
->LayoutToIdealBounds();
581 TEST_F(AppsGridViewTest
, UpdateFolderBackgroundOnCancelDrag
) {
582 EnsureFoldersEnabled();
584 const int kTotalItems
= 4;
585 TestAppsGridViewFolderDelegate folder_delegate
;
586 apps_grid_view_
->set_folder_delegate(&folder_delegate
);
587 model_
->PopulateApps(kTotalItems
);
588 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
589 model_
->GetModelContent());
591 gfx::Point mouse_from
= GetItemTileRectAt(0, 0).CenterPoint();
592 gfx::Point mouse_to
= GetItemTileRectAt(0, 1).CenterPoint();
594 // Starts a mouse drag and then cancels it.
595 SimulateDrag(AppsGridView::MOUSE
, mouse_from
, mouse_to
);
596 EXPECT_TRUE(folder_delegate
.show_bubble());
597 apps_grid_view_
->EndDrag(true);
598 EXPECT_FALSE(folder_delegate
.show_bubble());
599 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
600 model_
->GetModelContent());
603 TEST_F(AppsGridViewTest
, HighlightWithKeyboard
) {
604 const int kPages
= 3;
605 const int kItems
= (kPages
- 1) * kTilesPerPage
+ 1;
606 model_
->PopulateApps(kItems
);
608 const int first_index
= 0;
609 const int last_index
= kItems
- 1;
610 const int last_index_on_page1_first_row
= kRows
- 1;
611 const int last_index_on_page1
= kTilesPerPage
- 1;
612 const int first_index_on_page2
= kTilesPerPage
;
613 const int first_index_on_page2_last_row
= 2 * kTilesPerPage
- kRows
;
614 const int last_index_on_page2_last_row
= 2 * kTilesPerPage
- 1;
616 // Try moving off the item beyond the first one.
617 apps_grid_view_
->SetSelectedView(GetItemViewAt(first_index
));
618 SimulateKeyPress(ui::VKEY_UP
);
619 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(first_index
)));
620 SimulateKeyPress(ui::VKEY_LEFT
);
621 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(first_index
)));
623 // Move to the last item and try to go past it.
624 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index
));
625 SimulateKeyPress(ui::VKEY_DOWN
);
626 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(last_index
)));
627 SimulateKeyPress(ui::VKEY_RIGHT
);
628 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(last_index
)));
630 // Move right on last item on page 1 should get to first item on page 2's last
631 // row and vice versa.
632 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index_on_page1
));
633 SimulateKeyPress(ui::VKEY_RIGHT
);
634 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
635 first_index_on_page2_last_row
)));
636 SimulateKeyPress(ui::VKEY_LEFT
);
637 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
638 last_index_on_page1
)));
640 // Up/down on page boundary does nothing.
641 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index_on_page1
));
642 SimulateKeyPress(ui::VKEY_DOWN
);
643 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
644 last_index_on_page1
)));
645 apps_grid_view_
->SetSelectedView(
646 GetItemViewAt(first_index_on_page2_last_row
));
648 SetSelectedView(GetItemViewAt(last_index_on_page1_first_row
));
649 SimulateKeyPress(ui::VKEY_UP
);
650 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
651 last_index_on_page1_first_row
)));
653 // Page up and down should go to the same item on the next and last page.
654 apps_grid_view_
->SetSelectedView(GetItemViewAt(first_index_on_page2
));
655 SimulateKeyPress(ui::VKEY_PRIOR
);
656 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
658 SimulateKeyPress(ui::VKEY_NEXT
);
659 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
660 first_index_on_page2
)));
662 // Moving onto a a page with too few apps to support the expected index snaps
663 // to the last available index.
664 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row
));
665 SimulateKeyPress(ui::VKEY_RIGHT
);
666 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
668 apps_grid_view_
->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row
));
669 SimulateKeyPress(ui::VKEY_NEXT
);
670 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
675 // After page switch, arrow keys select first item on current page.
676 apps_grid_view_
->SetSelectedView(GetItemViewAt(first_index
));
677 GetPaginationModel()->SelectPage(1, false);
678 SimulateKeyPress(ui::VKEY_UP
);
679 EXPECT_TRUE(apps_grid_view_
->IsSelectedView(GetItemViewAt(
680 first_index_on_page2
)));
683 TEST_F(AppsGridViewTest
, ItemLabelShortNameOverride
) {
684 // If the app's full name and short name differ, the title label's tooltip
685 // should always be the full name of the app.
686 std::string
expected_text("xyz");
687 std::string
expected_tooltip("tooltip");
688 AppListItem
* item
= model_
->CreateAndAddItem("Item with short name");
689 model_
->SetItemNameAndShortName(item
, expected_tooltip
, expected_text
);
691 base::string16 actual_tooltip
;
692 AppListItemView
* item_view
= GetItemViewAt(0);
693 ASSERT_TRUE(item_view
);
694 const views::Label
* title_label
= item_view
->title();
695 EXPECT_TRUE(title_label
->GetTooltipText(
696 title_label
->bounds().CenterPoint(), &actual_tooltip
));
697 EXPECT_EQ(expected_tooltip
, base::UTF16ToUTF8(actual_tooltip
));
698 EXPECT_EQ(expected_text
, base::UTF16ToUTF8(title_label
->text()));
701 TEST_F(AppsGridViewTest
, ItemLabelNoShortName
) {
702 // If the app's full name and short name are the same, use the default tooltip
703 // behavior of the label (only show a tooltip if the title is truncated).
704 std::string
title("a");
705 AppListItem
* item
= model_
->CreateAndAddItem(title
);
706 model_
->SetItemNameAndShortName(item
, title
, "");
708 base::string16 actual_tooltip
;
709 AppListItemView
* item_view
= GetItemViewAt(0);
710 ASSERT_TRUE(item_view
);
711 const views::Label
* title_label
= item_view
->title();
712 EXPECT_FALSE(title_label
->GetTooltipText(
713 title_label
->bounds().CenterPoint(), &actual_tooltip
));
714 EXPECT_EQ(title
, base::UTF16ToUTF8(title_label
->text()));
718 } // namespace app_list