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/test/apps_grid_view_test_api.h"
26 #include "ui/views/test/views_test_base.h"
33 const int kIconDimension = 48;
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), page_changed_(false) {
45 model_->AddObserver(this);
48 virtual ~PageFlipWaiter() {
49 model_->RemoveObserver(this);
52 bool Wait(int time_out_ms) {
55 page_changed_ = false;
59 wait_timer_.Start(FROM_HERE,
60 base::TimeDelta::FromMilliseconds(time_out_ms),
61 this, &PageFlipWaiter::OnWaitTimeOut);
70 void OnWaitTimeOut() {
74 // PaginationModelObserver overrides:
75 virtual void TotalPagesChanged() OVERRIDE {
77 virtual void SelectedPageChanged(int old_selected,
78 int new_selected) OVERRIDE {
83 virtual void TransitionStarted() OVERRIDE {
85 virtual void TransitionChanged() OVERRIDE {
88 base::MessageLoopForUI* ui_loop_;
89 PaginationModel* model_;
92 base::OneShotTimer<PageFlipWaiter> wait_timer_;
94 DISALLOW_COPY_AND_ASSIGN(PageFlipWaiter);
99 class AppsGridViewTest : public views::ViewsTestBase {
101 AppsGridViewTest() {}
102 virtual ~AppsGridViewTest() {}
104 // testing::Test overrides:
105 virtual void SetUp() OVERRIDE {
106 views::ViewsTestBase::SetUp();
107 model_.reset(new AppListTestModel);
108 pagination_model_.reset(new PaginationModel);
110 apps_grid_view_.reset(new AppsGridView(NULL, pagination_model_.get()));
111 apps_grid_view_->SetLayout(kIconDimension, kCols, kRows);
112 apps_grid_view_->SetBoundsRect(gfx::Rect(gfx::Size(kWidth, kHeight)));
113 apps_grid_view_->SetModel(model_.get());
114 apps_grid_view_->SetItemList(model_->top_level_item_list());
116 test_api_.reset(new AppsGridViewTestApi(apps_grid_view_.get()));
118 virtual void TearDown() OVERRIDE {
119 apps_grid_view_.reset(); // Release apps grid view before models.
120 views::ViewsTestBase::TearDown();
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 // Points are in |apps_grid_view_|'s coordinates.
149 void SimulateDrag(AppsGridView::Pointer pointer,
150 const gfx::Point& from,
151 const gfx::Point& to) {
152 AppListItemView* view = GetItemViewForPoint(from);
155 gfx::Point translated_from = gfx::PointAtOffsetFromOrigin(
156 from - view->bounds().origin());
157 gfx::Point translated_to = gfx::PointAtOffsetFromOrigin(
158 to - view->bounds().origin());
160 ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED,
161 translated_from, from, 0, 0);
162 apps_grid_view_->InitiateDrag(view, pointer, pressed_event);
164 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED,
165 translated_to, to, 0, 0);
166 apps_grid_view_->UpdateDragFromItem(pointer, drag_event);
169 void SimulateKeyPress(ui::KeyboardCode key_code) {
170 ui::KeyEvent key_event(ui::ET_KEY_PRESSED, key_code, 0, false);
171 apps_grid_view_->OnKeyPressed(key_event);
174 scoped_ptr<AppListTestModel> model_;
175 scoped_ptr<PaginationModel> pagination_model_;
176 scoped_ptr<AppsGridView> apps_grid_view_;
177 scoped_ptr<AppsGridViewTestApi> test_api_;
180 DISALLOW_COPY_AND_ASSIGN(AppsGridViewTest);
183 TEST_F(AppsGridViewTest, CreatePage) {
184 // Fully populates a page.
185 const int kPages = 1;
186 model_->PopulateApps(kPages * kTilesPerPage);
187 EXPECT_EQ(kPages, pagination_model_->total_pages());
189 // Adds one more and gets a new page created.
190 model_->CreateAndAddItem("Extra");
191 EXPECT_EQ(kPages + 1, pagination_model_->total_pages());
194 TEST_F(AppsGridViewTest, EnsureHighlightedVisible) {
195 const int kPages = 3;
196 model_->PopulateApps(kPages * kTilesPerPage);
197 EXPECT_EQ(kPages, pagination_model_->total_pages());
198 EXPECT_EQ(0, pagination_model_->selected_page());
200 // Highlight first one and last one one first page and first page should be
202 model_->HighlightItemAt(0);
203 EXPECT_EQ(0, pagination_model_->selected_page());
204 model_->HighlightItemAt(kTilesPerPage - 1);
205 EXPECT_EQ(0, pagination_model_->selected_page());
207 // Highlight first one on 2nd page and 2nd page should be selected.
208 model_->HighlightItemAt(kTilesPerPage + 1);
209 EXPECT_EQ(1, pagination_model_->selected_page());
211 // Highlight last one in the model and last page should be selected.
212 model_->HighlightItemAt(model_->top_level_item_list()->item_count() - 1);
213 EXPECT_EQ(kPages - 1, pagination_model_->selected_page());
216 TEST_F(AppsGridViewTest, RemoveSelectedLastApp) {
217 const int kTotalItems = 2;
218 const int kLastItemIndex = kTotalItems - 1;
220 model_->PopulateApps(kTotalItems);
222 AppListItemView* last_view = GetItemViewAt(kLastItemIndex);
223 apps_grid_view_->SetSelectedView(last_view);
224 model_->DeleteItem(model_->GetItemName(kLastItemIndex));
226 EXPECT_FALSE(apps_grid_view_->IsSelectedView(last_view));
229 AppListItemView* view = GetItemViewAt(0);
230 apps_grid_view_->SetSelectedView(view);
231 EXPECT_TRUE(apps_grid_view_->IsSelectedView(view));
234 TEST_F(AppsGridViewTest, MouseDragWithFolderDisabled) {
235 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kDisableFolderUI);
236 const int kTotalItems = 4;
237 model_->PopulateApps(kTotalItems);
238 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
239 model_->GetModelContent());
241 gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
242 gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
244 // Dragging changes model order.
245 SimulateDrag(AppsGridView::MOUSE, from, to);
246 apps_grid_view_->EndDrag(false);
247 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
248 model_->GetModelContent());
249 test_api_->LayoutToIdealBounds();
251 // Canceling drag should keep existing order.
252 SimulateDrag(AppsGridView::MOUSE, from, to);
253 apps_grid_view_->EndDrag(true);
254 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
255 model_->GetModelContent());
256 test_api_->LayoutToIdealBounds();
258 // Deleting an item keeps remaining intact.
259 SimulateDrag(AppsGridView::MOUSE, from, to);
260 model_->DeleteItem(model_->GetItemName(0));
261 apps_grid_view_->EndDrag(false);
262 EXPECT_EQ(std::string("Item 1,Item 2,Item 3"),
263 model_->GetModelContent());
264 test_api_->LayoutToIdealBounds();
266 // Adding a launcher item cancels the drag and respects the order.
267 SimulateDrag(AppsGridView::MOUSE, from, to);
268 model_->CreateAndAddItem("Extra");
269 apps_grid_view_->EndDrag(false);
270 EXPECT_EQ(std::string("Item 1,Item 2,Item 3,Extra"),
271 model_->GetModelContent());
272 test_api_->LayoutToIdealBounds();
275 TEST_F(AppsGridViewTest, MouseDragItemIntoFolder) {
276 size_t kTotalItems = 3;
277 model_->PopulateApps(kTotalItems);
278 EXPECT_EQ(model_->top_level_item_list()->item_count(), kTotalItems);
279 EXPECT_EQ(std::string("Item 0,Item 1,Item 2"), model_->GetModelContent());
281 gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
282 gfx::Point to = GetItemTileRectAt(0, 0).CenterPoint();
284 // Dragging item_1 over item_0 creates a folder.
285 SimulateDrag(AppsGridView::MOUSE, from, to);
286 apps_grid_view_->EndDrag(false);
287 EXPECT_EQ(kTotalItems - 1, model_->top_level_item_list()->item_count());
288 EXPECT_EQ(AppListFolderItem::kItemType,
289 model_->top_level_item_list()->item_at(0)->GetItemType());
290 AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
291 model_->top_level_item_list()->item_at(0));
292 EXPECT_EQ(2u, folder_item->ChildItemCount());
293 AppListItem* item_0 = model_->FindItem("Item 0");
294 EXPECT_TRUE(item_0->IsInFolder());
295 EXPECT_EQ(folder_item->id(), item_0->folder_id());
296 AppListItem* item_1 = model_->FindItem("Item 1");
297 EXPECT_TRUE(item_1->IsInFolder());
298 EXPECT_EQ(folder_item->id(), item_1->folder_id());
299 std::string expected_items = folder_item->id() + ",Item 2";
300 EXPECT_EQ(expected_items, model_->GetModelContent());
301 test_api_->LayoutToIdealBounds();
303 // Dragging item_2 to the folder adds item_2 to the folder.
304 SimulateDrag(AppsGridView::MOUSE, from, to);
305 apps_grid_view_->EndDrag(false);
307 EXPECT_EQ(kTotalItems - 2, model_->top_level_item_list()->item_count());
308 EXPECT_EQ(folder_item->id(), model_->GetModelContent());
309 EXPECT_EQ(3u, folder_item->ChildItemCount());
310 item_0 = model_->FindItem("Item 0");
311 EXPECT_TRUE(item_0->IsInFolder());
312 EXPECT_EQ(folder_item->id(), item_0->folder_id());
313 item_1 = model_->FindItem("Item 1");
314 EXPECT_TRUE(item_1->IsInFolder());
315 EXPECT_EQ(folder_item->id(), item_1->folder_id());
316 AppListItem* item_2 = model_->FindItem("Item 2");
317 EXPECT_TRUE(item_2->IsInFolder());
318 EXPECT_EQ(folder_item->id(), item_2->folder_id());
319 test_api_->LayoutToIdealBounds();
322 TEST_F(AppsGridViewTest, MouseDragMaxItemsInFolder) {
323 // Create and add a folder with 15 items in it.
324 size_t kTotalItems = kMaxFolderItems - 1;
325 model_->CreateAndPopulateFolderWithApps(kTotalItems);
326 EXPECT_EQ(1u, model_->top_level_item_list()->item_count());
327 EXPECT_EQ(AppListFolderItem::kItemType,
328 model_->top_level_item_list()->item_at(0)->GetItemType());
329 AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
330 model_->top_level_item_list()->item_at(0));
331 EXPECT_EQ(kTotalItems, folder_item->ChildItemCount());
333 // Create and add another 2 items.
334 model_->PopulateAppWithId(kTotalItems);
335 model_->PopulateAppWithId(kTotalItems + 1);
336 EXPECT_EQ(3u, model_->top_level_item_list()->item_count());
337 EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
338 EXPECT_EQ(model_->GetItemName(kMaxFolderItems - 1),
339 model_->top_level_item_list()->item_at(1)->id());
340 EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
341 model_->top_level_item_list()->item_at(2)->id());
343 gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
344 gfx::Point to = GetItemTileRectAt(0, 0).CenterPoint();
346 // Dragging one item into the folder, the folder should accept the item.
347 SimulateDrag(AppsGridView::MOUSE, from, to);
348 apps_grid_view_->EndDrag(false);
349 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
350 EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
351 EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
352 EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
353 model_->top_level_item_list()->item_at(1)->id());
354 test_api_->LayoutToIdealBounds();
356 // Dragging the last item over the folder, the folder won't accept the new
357 // item, instead, it will re-order the items.
358 SimulateDrag(AppsGridView::MOUSE, from, to);
359 apps_grid_view_->EndDrag(false);
360 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
361 EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
362 model_->top_level_item_list()->item_at(0)->id());
363 EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(1)->id());
364 EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
365 test_api_->LayoutToIdealBounds();
368 TEST_F(AppsGridViewTest, MouseDragItemReorder) {
369 size_t kTotalItems = 2;
370 model_->PopulateApps(kTotalItems);
371 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
372 EXPECT_EQ(std::string("Item 0,Item 1"), model_->GetModelContent());
374 gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
375 int reorder_offset = (GetItemTileRectAt(0, 1).CenterPoint() -
376 GetItemTileRectAt(0, 0).CenterPoint()).Length() -
377 kReorderDroppingCircleRadius -
378 kPreferredIconDimension / 2 + 5;
379 gfx::Point to = gfx::Point(from.x() - reorder_offset, from.y());
381 // Dragging item_1 closing to item_0 should leads to re-ordering these two
383 SimulateDrag(AppsGridView::MOUSE, from, to);
384 apps_grid_view_->EndDrag(false);
385 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
386 EXPECT_EQ(std::string("Item 1,Item 0"), model_->GetModelContent());
387 test_api_->LayoutToIdealBounds();
390 TEST_F(AppsGridViewTest, MouseDragFolderReorder) {
391 size_t kTotalItems = 2;
392 model_->CreateAndPopulateFolderWithApps(kTotalItems);
393 model_->PopulateAppWithId(kTotalItems);
394 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
395 EXPECT_EQ(AppListFolderItem::kItemType,
396 model_->top_level_item_list()->item_at(0)->GetItemType());
397 AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
398 model_->top_level_item_list()->item_at(0));
399 EXPECT_EQ("Item 2", model_->top_level_item_list()->item_at(1)->id());
401 gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
402 gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
404 // Dragging folder over item_1 should leads to re-ordering these two
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("Item 2", model_->top_level_item_list()->item_at(0)->id());
410 EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(1)->id());
411 test_api_->LayoutToIdealBounds();
414 TEST_F(AppsGridViewTest, MouseDragWithCancelDeleteAddItem) {
415 size_t kTotalItems = 4;
416 model_->PopulateApps(kTotalItems);
417 EXPECT_EQ(model_->top_level_item_list()->item_count(), kTotalItems);
418 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
419 model_->GetModelContent());
421 gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
422 gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
424 // Canceling drag should keep existing order.
425 SimulateDrag(AppsGridView::MOUSE, from, to);
426 apps_grid_view_->EndDrag(true);
427 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
428 model_->GetModelContent());
429 test_api_->LayoutToIdealBounds();
431 // Deleting an item keeps remaining intact.
432 SimulateDrag(AppsGridView::MOUSE, from, to);
433 model_->DeleteItem(model_->GetItemName(2));
434 apps_grid_view_->EndDrag(false);
435 EXPECT_EQ(std::string("Item 0,Item 1,Item 3"), model_->GetModelContent());
436 test_api_->LayoutToIdealBounds();
438 // Adding a launcher item cancels the drag and respects the order.
439 SimulateDrag(AppsGridView::MOUSE, from, to);
440 model_->CreateAndAddItem("Extra");
441 apps_grid_view_->EndDrag(false);
442 EXPECT_EQ(std::string("Item 0,Item 1,Item 3,Extra"),
443 model_->GetModelContent());
444 test_api_->LayoutToIdealBounds();
447 TEST_F(AppsGridViewTest, MouseDragFlipPage) {
448 test_api_->SetPageFlipDelay(10);
449 pagination_model_->SetTransitionDurations(10, 10);
451 PageFlipWaiter page_flip_waiter(message_loop(),
452 pagination_model_.get());
454 const int kPages = 3;
455 model_->PopulateApps(kPages * kTilesPerPage);
456 EXPECT_EQ(kPages, pagination_model_->total_pages());
457 EXPECT_EQ(0, pagination_model_->selected_page());
459 gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
460 gfx::Point to = gfx::Point(apps_grid_view_->width(),
461 apps_grid_view_->height() / 2);
463 // Drag to right edge.
464 SimulateDrag(AppsGridView::MOUSE, from, to);
466 // Page should be flipped after sometime.
467 EXPECT_TRUE(page_flip_waiter.Wait(0));
468 EXPECT_EQ(1, pagination_model_->selected_page());
470 // Stay there and page should be flipped again.
471 EXPECT_TRUE(page_flip_waiter.Wait(0));
472 EXPECT_EQ(2, pagination_model_->selected_page());
474 // Stay there longer and no page flip happen since we are at the last page.
475 EXPECT_FALSE(page_flip_waiter.Wait(100));
476 EXPECT_EQ(2, pagination_model_->selected_page());
478 apps_grid_view_->EndDrag(true);
480 // Now drag to the left edge and test the other direction.
483 SimulateDrag(AppsGridView::MOUSE, from, to);
485 EXPECT_TRUE(page_flip_waiter.Wait(0));
486 EXPECT_EQ(1, pagination_model_->selected_page());
488 EXPECT_TRUE(page_flip_waiter.Wait(0));
489 EXPECT_EQ(0, pagination_model_->selected_page());
491 EXPECT_FALSE(page_flip_waiter.Wait(100));
492 EXPECT_EQ(0, pagination_model_->selected_page());
493 apps_grid_view_->EndDrag(true);
496 TEST_F(AppsGridViewTest, SimultaneousDragWithFolderDisabled) {
497 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kDisableFolderUI);
498 const int kTotalItems = 4;
499 model_->PopulateApps(kTotalItems);
500 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
501 model_->GetModelContent());
503 gfx::Point mouse_from = GetItemTileRectAt(0, 0).CenterPoint();
504 gfx::Point mouse_to = GetItemTileRectAt(0, 1).CenterPoint();
506 gfx::Point touch_from = GetItemTileRectAt(1, 0).CenterPoint();
507 gfx::Point touch_to = GetItemTileRectAt(1, 1).CenterPoint();
509 // Starts a mouse drag first then a touch drag.
510 SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
511 SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
512 // Finishes the drag and mouse drag wins.
513 apps_grid_view_->EndDrag(false);
514 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
515 model_->GetModelContent());
516 test_api_->LayoutToIdealBounds();
518 // Starts a touch drag first then a mouse drag.
519 SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
520 SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
521 // Finishes the drag and touch drag wins.
522 apps_grid_view_->EndDrag(false);
523 EXPECT_EQ(std::string("Item 1,Item 0,Item 3,Item 2"),
524 model_->GetModelContent());
525 test_api_->LayoutToIdealBounds();
528 TEST_F(AppsGridViewTest, HighlightWithKeyboard) {
529 const int kPages = 3;
530 const int kItems = (kPages - 1) * kTilesPerPage + 1;
531 model_->PopulateApps(kItems);
533 const int first_index = 0;
534 const int last_index = kItems - 1;
535 const int last_index_on_page1_first_row = kRows - 1;
536 const int last_index_on_page1 = kTilesPerPage - 1;
537 const int first_index_on_page2 = kTilesPerPage;
538 const int first_index_on_page2_last_row = 2 * kTilesPerPage - kRows;
539 const int last_index_on_page2_last_row = 2 * kTilesPerPage - 1;
541 // Try moving off the item beyond the first one.
542 apps_grid_view_->SetSelectedView(GetItemViewAt(first_index));
543 SimulateKeyPress(ui::VKEY_UP);
544 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(first_index)));
545 SimulateKeyPress(ui::VKEY_LEFT);
546 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(first_index)));
548 // Move to the last item and try to go past it.
549 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index));
550 SimulateKeyPress(ui::VKEY_DOWN);
551 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(last_index)));
552 SimulateKeyPress(ui::VKEY_RIGHT);
553 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(last_index)));
555 // Move right on last item on page 1 should get to first item on page 2's last
556 // row and vice versa.
557 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page1));
558 SimulateKeyPress(ui::VKEY_RIGHT);
559 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
560 first_index_on_page2_last_row)));
561 SimulateKeyPress(ui::VKEY_LEFT);
562 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
563 last_index_on_page1)));
565 // Up/down on page boundary does nothing.
566 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page1));
567 SimulateKeyPress(ui::VKEY_DOWN);
568 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
569 last_index_on_page1)));
570 apps_grid_view_->SetSelectedView(
571 GetItemViewAt(first_index_on_page2_last_row));
573 SetSelectedView(GetItemViewAt(last_index_on_page1_first_row));
574 SimulateKeyPress(ui::VKEY_UP);
575 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
576 last_index_on_page1_first_row)));
578 // Page up and down should go to the same item on the next and last page.
579 apps_grid_view_->SetSelectedView(GetItemViewAt(first_index_on_page2));
580 SimulateKeyPress(ui::VKEY_PRIOR);
581 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
583 SimulateKeyPress(ui::VKEY_NEXT);
584 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
585 first_index_on_page2)));
587 // Moving onto a a page with too few apps to support the expected index snaps
588 // to the last available index.
589 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row));
590 SimulateKeyPress(ui::VKEY_RIGHT);
591 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
593 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row));
594 SimulateKeyPress(ui::VKEY_NEXT);
595 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
600 // After page switch, arrow keys select first item on current page.
601 apps_grid_view_->SetSelectedView(GetItemViewAt(first_index));
602 pagination_model_->SelectPage(1, false);
603 SimulateKeyPress(ui::VKEY_UP);
604 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
605 first_index_on_page2)));
608 TEST_F(AppsGridViewTest, ItemLabelShortNameOverride) {
609 // If the app's full name and short name differ, the title label's tooltip
610 // should always be the full name of the app.
611 std::string expected_text("xyz");
612 std::string expected_tooltip("tooltip");
613 AppListItem* item = model_->CreateAndAddItem("Item with short name");
614 model_->SetItemNameAndShortName(item, expected_tooltip, expected_text);
616 base::string16 actual_tooltip;
617 AppListItemView* item_view = GetItemViewAt(0);
618 ASSERT_TRUE(item_view);
619 const views::Label* title_label = item_view->title();
620 EXPECT_TRUE(title_label->GetTooltipText(
621 title_label->bounds().CenterPoint(), &actual_tooltip));
622 EXPECT_EQ(expected_tooltip, base::UTF16ToUTF8(actual_tooltip));
623 EXPECT_EQ(expected_text, base::UTF16ToUTF8(title_label->text()));
626 TEST_F(AppsGridViewTest, ItemLabelNoShortName) {
627 // If the app's full name and short name are the same, use the default tooltip
628 // behavior of the label (only show a tooltip if the title is truncated).
629 std::string title("a");
630 AppListItem* item = model_->CreateAndAddItem(title);
631 model_->SetItemNameAndShortName(item, title, "");
633 base::string16 actual_tooltip;
634 AppListItemView* item_view = GetItemViewAt(0);
635 ASSERT_TRUE(item_view);
636 const views::Label* title_label = item_view->title();
637 EXPECT_FALSE(title_label->GetTooltipText(
638 title_label->bounds().CenterPoint(), &actual_tooltip));
639 EXPECT_EQ(title, base::UTF16ToUTF8(title_label->text()));
643 } // namespace app_list