Workaround for xkbcommon dead keys.
[chromium-blink-merge.git] / ui / app_list / views / apps_grid_view_unittest.cc
blobe7edc45a51cc7dcf32d3b9dbe1b0116772153f64
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/app_list/views/apps_grid_view.h"
7 #include <string>
9 #include "base/basictypes.h"
10 #include "base/command_line.h"
11 #include "base/compiler_specific.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/app_list/app_list_constants.h"
18 #include "ui/app_list/app_list_folder_item.h"
19 #include "ui/app_list/app_list_item.h"
20 #include "ui/app_list/app_list_model.h"
21 #include "ui/app_list/app_list_switches.h"
22 #include "ui/app_list/pagination_model.h"
23 #include "ui/app_list/test/app_list_test_model.h"
24 #include "ui/app_list/views/app_list_item_view.h"
25 #include "ui/app_list/views/apps_grid_view_folder_delegate.h"
26 #include "ui/app_list/views/test/apps_grid_view_test_api.h"
27 #include "ui/views/test/views_test_base.h"
29 namespace app_list {
30 namespace test {
32 namespace {
34 const int kCols = 2;
35 const int kRows = 2;
36 const int kTilesPerPage = kCols * kRows;
38 class PageFlipWaiter : public PaginationModelObserver {
39 public:
40 PageFlipWaiter(base::MessageLoopForUI* ui_loop, PaginationModel* model)
41 : ui_loop_(ui_loop), model_(model), wait_(false) {
42 model_->AddObserver(this);
45 ~PageFlipWaiter() override { model_->RemoveObserver(this); }
47 void Wait() {
48 DCHECK(!wait_);
49 wait_ = true;
51 ui_loop_->Run();
52 wait_ = false;
55 void Reset() { selected_pages_.clear(); }
57 const std::string& selected_pages() const { return selected_pages_; }
59 private:
60 // PaginationModelObserver overrides:
61 void TotalPagesChanged() override {}
62 void SelectedPageChanged(int old_selected, int new_selected) override {
63 if (!selected_pages_.empty())
64 selected_pages_ += ',';
65 selected_pages_ += base::IntToString(new_selected);
67 if (wait_)
68 ui_loop_->Quit();
70 void TransitionStarted() override {}
71 void TransitionChanged() override {}
73 base::MessageLoopForUI* ui_loop_;
74 PaginationModel* model_;
75 bool wait_;
76 std::string selected_pages_;
78 DISALLOW_COPY_AND_ASSIGN(PageFlipWaiter);
81 } // namespace
83 class AppsGridViewTest : public views::ViewsTestBase {
84 public:
85 AppsGridViewTest() {}
86 ~AppsGridViewTest() override {}
88 // testing::Test overrides:
89 void SetUp() override {
90 views::ViewsTestBase::SetUp();
91 model_.reset(new AppListTestModel);
92 model_->SetFoldersEnabled(true);
94 apps_grid_view_.reset(new AppsGridView(NULL));
95 apps_grid_view_->SetLayout(kCols, kRows);
96 apps_grid_view_->SetBoundsRect(
97 gfx::Rect(apps_grid_view_->GetPreferredSize()));
98 apps_grid_view_->SetModel(model_.get());
99 apps_grid_view_->SetItemList(model_->top_level_item_list());
101 test_api_.reset(new AppsGridViewTestApi(apps_grid_view_.get()));
103 void TearDown() override {
104 apps_grid_view_.reset(); // Release apps grid view before models.
105 views::ViewsTestBase::TearDown();
108 protected:
109 void EnsureFoldersEnabled() {
110 // Folders require AppList sync to be enabled.
111 CommandLine::ForCurrentProcess()->AppendSwitch(
112 switches::kEnableSyncAppList);
115 AppListItemView* GetItemViewAt(int index) {
116 return static_cast<AppListItemView*>(
117 test_api_->GetViewAtModelIndex(index));
120 AppListItemView* GetItemViewForPoint(const gfx::Point& point) {
121 for (size_t i = 0; i < model_->top_level_item_list()->item_count(); ++i) {
122 AppListItemView* view = GetItemViewAt(i);
123 if (view->bounds().Contains(point))
124 return view;
126 return NULL;
129 gfx::Rect GetItemTileRectAt(int row, int col) {
130 DCHECK_GT(model_->top_level_item_list()->item_count(), 0u);
132 gfx::Insets insets(apps_grid_view_->GetInsets());
133 gfx::Rect rect(gfx::Point(insets.left(), insets.top()),
134 AppsGridView::GetTotalTileSize());
135 rect.Offset(col * rect.width(), row * rect.height());
136 return rect;
139 PaginationModel* GetPaginationModel() {
140 return apps_grid_view_->pagination_model();
143 // Points are in |apps_grid_view_|'s coordinates.
144 AppListItemView* SimulateDrag(AppsGridView::Pointer pointer,
145 const gfx::Point& from,
146 const gfx::Point& to) {
147 AppListItemView* view = GetItemViewForPoint(from);
148 DCHECK(view);
150 gfx::Point translated_from = gfx::PointAtOffsetFromOrigin(
151 from - view->bounds().origin());
152 gfx::Point translated_to = gfx::PointAtOffsetFromOrigin(
153 to - view->bounds().origin());
155 ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED,
156 translated_from, from, 0, 0);
157 apps_grid_view_->InitiateDrag(view, pointer, pressed_event);
159 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED,
160 translated_to, to, 0, 0);
161 apps_grid_view_->UpdateDragFromItem(pointer, drag_event);
162 return view;
165 void SimulateKeyPress(ui::KeyboardCode key_code) {
166 ui::KeyEvent key_event(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE);
167 apps_grid_view_->OnKeyPressed(key_event);
170 scoped_ptr<AppListTestModel> model_;
171 scoped_ptr<AppsGridView> apps_grid_view_;
172 scoped_ptr<AppsGridViewTestApi> test_api_;
174 private:
175 DISALLOW_COPY_AND_ASSIGN(AppsGridViewTest);
178 class TestAppsGridViewFolderDelegate : public AppsGridViewFolderDelegate {
179 public:
180 TestAppsGridViewFolderDelegate() : show_bubble_(false) {}
181 ~TestAppsGridViewFolderDelegate() override {}
183 // Overridden from AppsGridViewFolderDelegate:
184 void UpdateFolderViewBackground(bool show_bubble) override {
185 show_bubble_ = show_bubble;
188 void ReparentItem(AppListItemView* original_drag_view,
189 const gfx::Point& drag_point_in_folder_grid,
190 bool has_native_drag) override {}
192 void DispatchDragEventForReparent(
193 AppsGridView::Pointer pointer,
194 const gfx::Point& drag_point_in_folder_grid) override {}
196 void DispatchEndDragEventForReparent(bool events_forwarded_to_drag_drop_host,
197 bool cancel_drag) override {}
199 bool IsPointOutsideOfFolderBoundary(const gfx::Point& point) override {
200 return false;
203 bool IsOEMFolder() const override { return false; }
205 void SetRootLevelDragViewVisible(bool visible) override {}
207 bool show_bubble() { return show_bubble_; }
209 private:
210 bool show_bubble_;
212 DISALLOW_COPY_AND_ASSIGN(TestAppsGridViewFolderDelegate);
215 TEST_F(AppsGridViewTest, CreatePage) {
216 // Fully populates a page.
217 const int kPages = 1;
218 model_->PopulateApps(kPages * kTilesPerPage);
219 EXPECT_EQ(kPages, GetPaginationModel()->total_pages());
221 // Adds one more and gets a new page created.
222 model_->CreateAndAddItem("Extra");
223 EXPECT_EQ(kPages + 1, GetPaginationModel()->total_pages());
226 TEST_F(AppsGridViewTest, EnsureHighlightedVisible) {
227 const int kPages = 3;
228 model_->PopulateApps(kPages * kTilesPerPage);
229 EXPECT_EQ(kPages, GetPaginationModel()->total_pages());
230 EXPECT_EQ(0, GetPaginationModel()->selected_page());
232 // Highlight first one and last one one first page and first page should be
233 // selected.
234 model_->HighlightItemAt(0);
235 EXPECT_EQ(0, GetPaginationModel()->selected_page());
236 model_->HighlightItemAt(kTilesPerPage - 1);
237 EXPECT_EQ(0, GetPaginationModel()->selected_page());
239 // Highlight first one on 2nd page and 2nd page should be selected.
240 model_->HighlightItemAt(kTilesPerPage + 1);
241 EXPECT_EQ(1, GetPaginationModel()->selected_page());
243 // Highlight last one in the model and last page should be selected.
244 model_->HighlightItemAt(model_->top_level_item_list()->item_count() - 1);
245 EXPECT_EQ(kPages - 1, GetPaginationModel()->selected_page());
248 TEST_F(AppsGridViewTest, RemoveSelectedLastApp) {
249 const int kTotalItems = 2;
250 const int kLastItemIndex = kTotalItems - 1;
252 model_->PopulateApps(kTotalItems);
254 AppListItemView* last_view = GetItemViewAt(kLastItemIndex);
255 apps_grid_view_->SetSelectedView(last_view);
256 model_->DeleteItem(model_->GetItemName(kLastItemIndex));
258 EXPECT_FALSE(apps_grid_view_->IsSelectedView(last_view));
260 // No crash happens.
261 AppListItemView* view = GetItemViewAt(0);
262 apps_grid_view_->SetSelectedView(view);
263 EXPECT_TRUE(apps_grid_view_->IsSelectedView(view));
266 TEST_F(AppsGridViewTest, MouseDragWithFolderDisabled) {
267 model_->SetFoldersEnabled(false);
268 const int kTotalItems = 4;
269 model_->PopulateApps(kTotalItems);
270 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
271 model_->GetModelContent());
273 gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
274 gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
276 // Dragging changes model order.
277 SimulateDrag(AppsGridView::MOUSE, from, to);
278 apps_grid_view_->EndDrag(false);
279 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
280 model_->GetModelContent());
281 test_api_->LayoutToIdealBounds();
283 // Canceling drag should keep existing order.
284 SimulateDrag(AppsGridView::MOUSE, from, to);
285 apps_grid_view_->EndDrag(true);
286 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
287 model_->GetModelContent());
288 test_api_->LayoutToIdealBounds();
290 // Deleting an item keeps remaining intact.
291 SimulateDrag(AppsGridView::MOUSE, from, to);
292 model_->DeleteItem(model_->GetItemName(0));
293 apps_grid_view_->EndDrag(false);
294 EXPECT_EQ(std::string("Item 1,Item 2,Item 3"),
295 model_->GetModelContent());
296 test_api_->LayoutToIdealBounds();
298 // Adding a launcher item cancels the drag and respects the order.
299 SimulateDrag(AppsGridView::MOUSE, from, to);
300 EXPECT_TRUE(apps_grid_view_->has_dragged_view());
301 model_->CreateAndAddItem("Extra");
302 // No need to EndDrag explicitly - adding an item should do this.
303 EXPECT_FALSE(apps_grid_view_->has_dragged_view());
304 // Even though cancelled, mouse move events can still arrive via the item
305 // view. Ensure that behaves sanely, and doesn't start a new drag.
306 ui::MouseEvent drag_event(
307 ui::ET_MOUSE_DRAGGED, gfx::Point(1, 1), gfx::Point(2, 2), 0, 0);
308 apps_grid_view_->UpdateDragFromItem(AppsGridView::MOUSE, drag_event);
309 EXPECT_FALSE(apps_grid_view_->has_dragged_view());
311 EXPECT_EQ(std::string("Item 1,Item 2,Item 3,Extra"),
312 model_->GetModelContent());
313 test_api_->LayoutToIdealBounds();
316 TEST_F(AppsGridViewTest, MouseDragItemIntoFolder) {
317 EnsureFoldersEnabled();
319 size_t kTotalItems = 3;
320 model_->PopulateApps(kTotalItems);
321 EXPECT_EQ(model_->top_level_item_list()->item_count(), kTotalItems);
322 EXPECT_EQ(std::string("Item 0,Item 1,Item 2"), model_->GetModelContent());
324 gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
325 gfx::Point to = GetItemTileRectAt(0, 0).CenterPoint();
327 // Dragging item_1 over item_0 creates a folder.
328 SimulateDrag(AppsGridView::MOUSE, from, to);
329 apps_grid_view_->EndDrag(false);
330 EXPECT_EQ(kTotalItems - 1, model_->top_level_item_list()->item_count());
331 EXPECT_EQ(AppListFolderItem::kItemType,
332 model_->top_level_item_list()->item_at(0)->GetItemType());
333 AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
334 model_->top_level_item_list()->item_at(0));
335 EXPECT_EQ(2u, folder_item->ChildItemCount());
336 AppListItem* item_0 = model_->FindItem("Item 0");
337 EXPECT_TRUE(item_0->IsInFolder());
338 EXPECT_EQ(folder_item->id(), item_0->folder_id());
339 AppListItem* item_1 = model_->FindItem("Item 1");
340 EXPECT_TRUE(item_1->IsInFolder());
341 EXPECT_EQ(folder_item->id(), item_1->folder_id());
342 std::string expected_items = folder_item->id() + ",Item 2";
343 EXPECT_EQ(expected_items, model_->GetModelContent());
344 test_api_->LayoutToIdealBounds();
346 // Dragging item_2 to the folder adds item_2 to the folder.
347 SimulateDrag(AppsGridView::MOUSE, from, to);
348 apps_grid_view_->EndDrag(false);
350 EXPECT_EQ(kTotalItems - 2, model_->top_level_item_list()->item_count());
351 EXPECT_EQ(folder_item->id(), model_->GetModelContent());
352 EXPECT_EQ(3u, folder_item->ChildItemCount());
353 item_0 = model_->FindItem("Item 0");
354 EXPECT_TRUE(item_0->IsInFolder());
355 EXPECT_EQ(folder_item->id(), item_0->folder_id());
356 item_1 = model_->FindItem("Item 1");
357 EXPECT_TRUE(item_1->IsInFolder());
358 EXPECT_EQ(folder_item->id(), item_1->folder_id());
359 AppListItem* item_2 = model_->FindItem("Item 2");
360 EXPECT_TRUE(item_2->IsInFolder());
361 EXPECT_EQ(folder_item->id(), item_2->folder_id());
362 test_api_->LayoutToIdealBounds();
365 TEST_F(AppsGridViewTest, MouseDragMaxItemsInFolder) {
366 EnsureFoldersEnabled();
368 // Create and add a folder with 15 items in it.
369 size_t kTotalItems = kMaxFolderItems - 1;
370 model_->CreateAndPopulateFolderWithApps(kTotalItems);
371 EXPECT_EQ(1u, model_->top_level_item_list()->item_count());
372 EXPECT_EQ(AppListFolderItem::kItemType,
373 model_->top_level_item_list()->item_at(0)->GetItemType());
374 AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
375 model_->top_level_item_list()->item_at(0));
376 EXPECT_EQ(kTotalItems, folder_item->ChildItemCount());
378 // Create and add another 2 items.
379 model_->PopulateAppWithId(kTotalItems);
380 model_->PopulateAppWithId(kTotalItems + 1);
381 EXPECT_EQ(3u, model_->top_level_item_list()->item_count());
382 EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
383 EXPECT_EQ(model_->GetItemName(kMaxFolderItems - 1),
384 model_->top_level_item_list()->item_at(1)->id());
385 EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
386 model_->top_level_item_list()->item_at(2)->id());
388 gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
389 gfx::Point to = GetItemTileRectAt(0, 0).CenterPoint();
391 // Dragging one item into the folder, the folder should accept the item.
392 SimulateDrag(AppsGridView::MOUSE, from, to);
393 apps_grid_view_->EndDrag(false);
394 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
395 EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
396 EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
397 EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
398 model_->top_level_item_list()->item_at(1)->id());
399 test_api_->LayoutToIdealBounds();
401 // Dragging the last item over the folder, the folder won't accept the new
402 // item.
403 SimulateDrag(AppsGridView::MOUSE, from, to);
404 apps_grid_view_->EndDrag(false);
405 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
406 EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
407 test_api_->LayoutToIdealBounds();
410 // Check that moving items around doesn't allow a drop to happen into a full
411 // folder.
412 TEST_F(AppsGridViewTest, MouseDragMaxItemsInFolderWithMovement) {
413 EnsureFoldersEnabled();
415 // Create and add a folder with 16 items in it.
416 size_t kTotalItems = kMaxFolderItems;
417 model_->CreateAndPopulateFolderWithApps(kTotalItems);
418 EXPECT_EQ(1u, model_->top_level_item_list()->item_count());
419 EXPECT_EQ(AppListFolderItem::kItemType,
420 model_->top_level_item_list()->item_at(0)->GetItemType());
421 AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
422 model_->top_level_item_list()->item_at(0));
423 EXPECT_EQ(kTotalItems, folder_item->ChildItemCount());
425 // Create and add another item.
426 model_->PopulateAppWithId(kTotalItems);
427 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
428 EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
429 EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
430 model_->top_level_item_list()->item_at(1)->id());
432 AppListItemView* folder_view =
433 GetItemViewForPoint(GetItemTileRectAt(0, 0).CenterPoint());
435 // Drag the new item to the left so that the grid reorders.
436 gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint();
437 gfx::Point to = GetItemTileRectAt(0, 0).bottom_left();
438 to.Offset(0, -1); // Get a point inside the rect.
439 AppListItemView* dragged_view = SimulateDrag(AppsGridView::MOUSE, from, to);
440 test_api_->LayoutToIdealBounds();
442 // The grid now looks like | blank | folder |.
443 EXPECT_EQ(NULL, GetItemViewForPoint(GetItemTileRectAt(0, 0).CenterPoint()));
444 EXPECT_EQ(folder_view,
445 GetItemViewForPoint(GetItemTileRectAt(0, 1).CenterPoint()));
447 // Move onto the folder and end the drag.
448 to = GetItemTileRectAt(0, 1).CenterPoint();
449 gfx::Point translated_to =
450 gfx::PointAtOffsetFromOrigin(to - dragged_view->bounds().origin());
451 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, translated_to, to, 0, 0);
452 apps_grid_view_->UpdateDragFromItem(AppsGridView::MOUSE, drag_event);
453 apps_grid_view_->EndDrag(false);
455 // The item should not have moved into the folder.
456 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
457 EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
458 test_api_->LayoutToIdealBounds();
461 TEST_F(AppsGridViewTest, MouseDragItemReorder) {
462 // This test assumes Folders are enabled.
463 EnsureFoldersEnabled();
465 model_->PopulateApps(4);
466 EXPECT_EQ(4u, model_->top_level_item_list()->item_count());
467 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
468 model_->GetModelContent());
470 // Dragging an item towards its neighbours should not reorder until the drag
471 // is past the folder drop point.
472 gfx::Point top_right = GetItemTileRectAt(0, 1).CenterPoint();
473 gfx::Vector2d drag_vector;
474 int half_tile_width =
475 (GetItemTileRectAt(0, 1).x() - GetItemTileRectAt(0, 0).x()) / 2;
476 int tile_height = GetItemTileRectAt(1, 0).y() - GetItemTileRectAt(0, 0).y();
478 // Drag left but stop before the folder dropping circle.
479 drag_vector.set_x(-half_tile_width - 4);
480 SimulateDrag(AppsGridView::MOUSE, top_right, top_right + drag_vector);
481 apps_grid_view_->EndDrag(false);
482 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
483 model_->GetModelContent());
485 // Drag left, past the folder dropping circle.
486 drag_vector.set_x(-3 * half_tile_width + 4);
487 SimulateDrag(AppsGridView::MOUSE, top_right, top_right + drag_vector);
488 apps_grid_view_->EndDrag(false);
489 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
490 model_->GetModelContent());
492 // Drag down, between apps 2 and 3. The gap should open up, making space for
493 // app 0 in the bottom left.
494 drag_vector.set_x(-half_tile_width);
495 drag_vector.set_y(tile_height);
496 SimulateDrag(AppsGridView::MOUSE, top_right, top_right + drag_vector);
497 apps_grid_view_->EndDrag(false);
498 EXPECT_EQ(std::string("Item 1,Item 2,Item 0,Item 3"),
499 model_->GetModelContent());
501 // Drag up, between apps 1 and 2. The gap should open up, making space for app
502 // 0 in the top right.
503 gfx::Point bottom_left = GetItemTileRectAt(1, 0).CenterPoint();
504 drag_vector.set_x(half_tile_width);
505 drag_vector.set_y(-tile_height);
506 SimulateDrag(AppsGridView::MOUSE, bottom_left, bottom_left + drag_vector);
507 apps_grid_view_->EndDrag(false);
508 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
509 model_->GetModelContent());
511 // Dragging down past the last app should reorder to the last position.
512 drag_vector.set_x(half_tile_width);
513 drag_vector.set_y(2 * tile_height);
514 SimulateDrag(AppsGridView::MOUSE, top_right, top_right + drag_vector);
515 apps_grid_view_->EndDrag(false);
516 EXPECT_EQ(std::string("Item 1,Item 2,Item 3,Item 0"),
517 model_->GetModelContent());
520 TEST_F(AppsGridViewTest, MouseDragFolderReorder) {
521 EnsureFoldersEnabled();
523 size_t kTotalItems = 2;
524 model_->CreateAndPopulateFolderWithApps(kTotalItems);
525 model_->PopulateAppWithId(kTotalItems);
526 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
527 EXPECT_EQ(AppListFolderItem::kItemType,
528 model_->top_level_item_list()->item_at(0)->GetItemType());
529 AppListFolderItem* folder_item = static_cast<AppListFolderItem*>(
530 model_->top_level_item_list()->item_at(0));
531 EXPECT_EQ("Item 2", model_->top_level_item_list()->item_at(1)->id());
533 gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
534 gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
536 // Dragging folder over item_1 should leads to re-ordering these two
537 // items.
538 SimulateDrag(AppsGridView::MOUSE, from, to);
539 apps_grid_view_->EndDrag(false);
540 EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
541 EXPECT_EQ("Item 2", model_->top_level_item_list()->item_at(0)->id());
542 EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(1)->id());
543 test_api_->LayoutToIdealBounds();
546 TEST_F(AppsGridViewTest, MouseDragWithCancelDeleteAddItem) {
547 size_t kTotalItems = 4;
548 model_->PopulateApps(kTotalItems);
549 EXPECT_EQ(model_->top_level_item_list()->item_count(), kTotalItems);
550 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
551 model_->GetModelContent());
553 gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
554 gfx::Point to = GetItemTileRectAt(0, 1).CenterPoint();
556 // Canceling drag should keep existing order.
557 SimulateDrag(AppsGridView::MOUSE, from, to);
558 apps_grid_view_->EndDrag(true);
559 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
560 model_->GetModelContent());
561 test_api_->LayoutToIdealBounds();
563 // Deleting an item keeps remaining intact.
564 SimulateDrag(AppsGridView::MOUSE, from, to);
565 model_->DeleteItem(model_->GetItemName(2));
566 apps_grid_view_->EndDrag(false);
567 EXPECT_EQ(std::string("Item 0,Item 1,Item 3"), model_->GetModelContent());
568 test_api_->LayoutToIdealBounds();
570 // Adding a launcher item cancels the drag and respects the order.
571 SimulateDrag(AppsGridView::MOUSE, from, to);
572 model_->CreateAndAddItem("Extra");
573 apps_grid_view_->EndDrag(false);
574 EXPECT_EQ(std::string("Item 0,Item 1,Item 3,Extra"),
575 model_->GetModelContent());
576 test_api_->LayoutToIdealBounds();
579 TEST_F(AppsGridViewTest, MouseDragFlipPage) {
580 test_api_->SetPageFlipDelay(10);
581 GetPaginationModel()->SetTransitionDurations(10, 10);
583 PageFlipWaiter page_flip_waiter(message_loop(), GetPaginationModel());
585 const int kPages = 3;
586 model_->PopulateApps(kPages * kTilesPerPage);
587 EXPECT_EQ(kPages, GetPaginationModel()->total_pages());
588 EXPECT_EQ(0, GetPaginationModel()->selected_page());
590 gfx::Point from = GetItemTileRectAt(0, 0).CenterPoint();
591 gfx::Point to = gfx::Point(apps_grid_view_->width(),
592 apps_grid_view_->height() / 2);
594 // Drag to right edge.
595 page_flip_waiter.Reset();
596 SimulateDrag(AppsGridView::MOUSE, from, to);
598 // Page should be flipped after sometime to hit page 1 and 2 then stop.
599 while (test_api_->HasPendingPageFlip()) {
600 page_flip_waiter.Wait();
602 EXPECT_EQ("1,2", page_flip_waiter.selected_pages());
603 EXPECT_EQ(2, GetPaginationModel()->selected_page());
605 apps_grid_view_->EndDrag(true);
607 // Now drag to the left edge and test the other direction.
608 to.set_x(0);
610 page_flip_waiter.Reset();
611 SimulateDrag(AppsGridView::MOUSE, from, to);
613 while (test_api_->HasPendingPageFlip()) {
614 page_flip_waiter.Wait();
616 EXPECT_EQ("1,0", page_flip_waiter.selected_pages());
617 EXPECT_EQ(0, GetPaginationModel()->selected_page());
619 apps_grid_view_->EndDrag(true);
622 TEST_F(AppsGridViewTest, SimultaneousDragWithFolderDisabled) {
623 model_->SetFoldersEnabled(false);
624 const int kTotalItems = 4;
625 model_->PopulateApps(kTotalItems);
626 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
627 model_->GetModelContent());
629 gfx::Point mouse_from = GetItemTileRectAt(0, 0).CenterPoint();
630 gfx::Point mouse_to = GetItemTileRectAt(0, 1).CenterPoint();
632 gfx::Point touch_from = GetItemTileRectAt(1, 0).CenterPoint();
633 gfx::Point touch_to = GetItemTileRectAt(1, 1).CenterPoint();
635 // Starts a mouse drag first then a touch drag.
636 SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
637 SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
638 // Finishes the drag and mouse drag wins.
639 apps_grid_view_->EndDrag(false);
640 EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
641 model_->GetModelContent());
642 test_api_->LayoutToIdealBounds();
644 // Starts a touch drag first then a mouse drag.
645 SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
646 SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
647 // Finishes the drag and touch drag wins.
648 apps_grid_view_->EndDrag(false);
649 EXPECT_EQ(std::string("Item 1,Item 0,Item 3,Item 2"),
650 model_->GetModelContent());
651 test_api_->LayoutToIdealBounds();
654 TEST_F(AppsGridViewTest, UpdateFolderBackgroundOnCancelDrag) {
655 EnsureFoldersEnabled();
657 const int kTotalItems = 4;
658 TestAppsGridViewFolderDelegate folder_delegate;
659 apps_grid_view_->set_folder_delegate(&folder_delegate);
660 model_->PopulateApps(kTotalItems);
661 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
662 model_->GetModelContent());
664 gfx::Point mouse_from = GetItemTileRectAt(0, 0).CenterPoint();
665 gfx::Point mouse_to = GetItemTileRectAt(0, 1).CenterPoint();
667 // Starts a mouse drag and then cancels it.
668 SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
669 EXPECT_TRUE(folder_delegate.show_bubble());
670 apps_grid_view_->EndDrag(true);
671 EXPECT_FALSE(folder_delegate.show_bubble());
672 EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
673 model_->GetModelContent());
676 TEST_F(AppsGridViewTest, HighlightWithKeyboard) {
677 const int kPages = 3;
678 const int kItems = (kPages - 1) * kTilesPerPage + 1;
679 model_->PopulateApps(kItems);
681 const int first_index = 0;
682 const int last_index = kItems - 1;
683 const int last_index_on_page1_first_row = kRows - 1;
684 const int last_index_on_page1 = kTilesPerPage - 1;
685 const int first_index_on_page2 = kTilesPerPage;
686 const int first_index_on_page2_last_row = 2 * kTilesPerPage - kRows;
687 const int last_index_on_page2_last_row = 2 * kTilesPerPage - 1;
689 // Try moving off the item beyond the first one.
690 apps_grid_view_->SetSelectedView(GetItemViewAt(first_index));
691 SimulateKeyPress(ui::VKEY_UP);
692 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(first_index)));
693 SimulateKeyPress(ui::VKEY_LEFT);
694 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(first_index)));
696 // Move to the last item and try to go past it.
697 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index));
698 SimulateKeyPress(ui::VKEY_DOWN);
699 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(last_index)));
700 SimulateKeyPress(ui::VKEY_RIGHT);
701 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(last_index)));
703 // Move right on last item on page 1 should get to first item on page 2's last
704 // row and vice versa.
705 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page1));
706 SimulateKeyPress(ui::VKEY_RIGHT);
707 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
708 first_index_on_page2_last_row)));
709 SimulateKeyPress(ui::VKEY_LEFT);
710 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
711 last_index_on_page1)));
713 // Up/down on page boundary does nothing.
714 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page1));
715 SimulateKeyPress(ui::VKEY_DOWN);
716 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
717 last_index_on_page1)));
718 apps_grid_view_->SetSelectedView(
719 GetItemViewAt(first_index_on_page2_last_row));
720 apps_grid_view_->
721 SetSelectedView(GetItemViewAt(last_index_on_page1_first_row));
722 SimulateKeyPress(ui::VKEY_UP);
723 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
724 last_index_on_page1_first_row)));
726 // Page up and down should go to the same item on the next and last page.
727 apps_grid_view_->SetSelectedView(GetItemViewAt(first_index_on_page2));
728 SimulateKeyPress(ui::VKEY_PRIOR);
729 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
730 first_index)));
731 SimulateKeyPress(ui::VKEY_NEXT);
732 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
733 first_index_on_page2)));
735 // Moving onto a a page with too few apps to support the expected index snaps
736 // to the last available index.
737 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row));
738 SimulateKeyPress(ui::VKEY_RIGHT);
739 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
740 last_index)));
741 apps_grid_view_->SetSelectedView(GetItemViewAt(last_index_on_page2_last_row));
742 SimulateKeyPress(ui::VKEY_NEXT);
743 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
744 last_index)));
748 // After page switch, arrow keys select first item on current page.
749 apps_grid_view_->SetSelectedView(GetItemViewAt(first_index));
750 GetPaginationModel()->SelectPage(1, false);
751 SimulateKeyPress(ui::VKEY_UP);
752 EXPECT_TRUE(apps_grid_view_->IsSelectedView(GetItemViewAt(
753 first_index_on_page2)));
756 TEST_F(AppsGridViewTest, ItemLabelShortNameOverride) {
757 // If the app's full name and short name differ, the title label's tooltip
758 // should always be the full name of the app.
759 std::string expected_text("xyz");
760 std::string expected_tooltip("tooltip");
761 AppListItem* item = model_->CreateAndAddItem("Item with short name");
762 model_->SetItemNameAndShortName(item, expected_tooltip, expected_text);
764 base::string16 actual_tooltip;
765 AppListItemView* item_view = GetItemViewAt(0);
766 ASSERT_TRUE(item_view);
767 const views::Label* title_label = item_view->title();
768 EXPECT_TRUE(title_label->GetTooltipText(
769 title_label->bounds().CenterPoint(), &actual_tooltip));
770 EXPECT_EQ(expected_tooltip, base::UTF16ToUTF8(actual_tooltip));
771 EXPECT_EQ(expected_text, base::UTF16ToUTF8(title_label->text()));
774 TEST_F(AppsGridViewTest, ItemLabelNoShortName) {
775 // If the app's full name and short name are the same, use the default tooltip
776 // behavior of the label (only show a tooltip if the title is truncated).
777 std::string title("a");
778 AppListItem* item = model_->CreateAndAddItem(title);
779 model_->SetItemNameAndShortName(item, title, "");
781 base::string16 actual_tooltip;
782 AppListItemView* item_view = GetItemViewAt(0);
783 ASSERT_TRUE(item_view);
784 const views::Label* title_label = item_view->title();
785 EXPECT_FALSE(title_label->GetTooltipText(
786 title_label->bounds().CenterPoint(), &actual_tooltip));
787 EXPECT_EQ(title, base::UTF16ToUTF8(title_label->text()));
790 } // namespace test
791 } // namespace app_list