1// Copyright 2013 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.
4
5#include "ui/app_list/views/apps_container_view.h"
6
7#include <algorithm>
8#include <vector>
9
10#include "base/command_line.h"
11#include "ui/app_list/app_list_constants.h"
12#include "ui/app_list/app_list_folder_item.h"
13#include "ui/app_list/app_list_switches.h"
14#include "ui/app_list/views/app_list_folder_view.h"
15#include "ui/app_list/views/app_list_item_view.h"
16#include "ui/app_list/views/app_list_main_view.h"
17#include "ui/app_list/views/apps_grid_view.h"
18#include "ui/app_list/views/folder_background_view.h"
19#include "ui/events/event.h"
20
21namespace app_list {
22
23AppsContainerView::AppsContainerView(AppListMainView* app_list_main_view,
24                                     AppListModel* model)
25    : model_(model),
26      show_state_(SHOW_NONE),
27      top_icon_animation_pending_count_(0) {
28  apps_grid_view_ = new AppsGridView(app_list_main_view);
29  int cols;
30  int rows;
31  if (switches::IsExperimentalAppListEnabled()) {
32    cols = kExperimentalPreferredCols;
33    rows = kExperimentalPreferredRows;
34  } else if (app_list_main_view->ShouldCenterWindow()) {
35    cols = kCenteredPreferredCols;
36    rows = kCenteredPreferredRows;
37  } else {
38    cols = kPreferredCols;
39    rows = kPreferredRows;
40  }
41  apps_grid_view_->SetLayout(cols, rows);
42  AddChildView(apps_grid_view_);
43
44  folder_background_view_ = new FolderBackgroundView();
45  AddChildView(folder_background_view_);
46
47  app_list_folder_view_ =
48      new AppListFolderView(this, model, app_list_main_view);
49  // The folder view is initially hidden.
50  app_list_folder_view_->SetVisible(false);
51  AddChildView(app_list_folder_view_);
52
53  apps_grid_view_->SetModel(model_);
54  apps_grid_view_->SetItemList(model_->top_level_item_list());
55  SetShowState(SHOW_APPS,
56               false);  /* show apps without animation */
57}
58
59AppsContainerView::~AppsContainerView() {
60}
61
62void AppsContainerView::ShowActiveFolder(AppListFolderItem* folder_item) {
63  // Prevent new animations from starting if there are currently animations
64  // pending. This fixes crbug.com/357099.
65  if (top_icon_animation_pending_count_)
66    return;
67
68  app_list_folder_view_->SetAppListFolderItem(folder_item);
69  SetShowState(SHOW_ACTIVE_FOLDER, false);
70
71  CreateViewsForFolderTopItemsAnimation(folder_item, true);
72}
73
74void AppsContainerView::ShowApps(AppListFolderItem* folder_item) {
75  if (top_icon_animation_pending_count_)
76    return;
77
78  PrepareToShowApps(folder_item);
79  SetShowState(SHOW_APPS,
80               true);  /* show apps with animation */
81}
82
83void AppsContainerView::ResetForShowApps() {
84  SetShowState(SHOW_APPS, false /* show apps without animation */);
85  folder_background_view_->UpdateFolderContainerBubble(
86      FolderBackgroundView::NO_BUBBLE);
87}
88
89void AppsContainerView::SetDragAndDropHostOfCurrentAppList(
90    ApplicationDragAndDropHost* drag_and_drop_host) {
91  apps_grid_view()->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
92  app_list_folder_view()->items_grid_view()->
93      SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
94}
95
96void AppsContainerView::ReparentFolderItemTransit(
97    AppListFolderItem* folder_item) {
98  if (top_icon_animation_pending_count_)
99    return;
100
101  PrepareToShowApps(folder_item);
102  SetShowState(SHOW_ITEM_REPARENT, false);
103}
104
105bool AppsContainerView::IsInFolderView() const {
106  return show_state_ == SHOW_ACTIVE_FOLDER;
107}
108
109gfx::Size AppsContainerView::GetPreferredSize() const {
110  const gfx::Size grid_size = apps_grid_view_->GetPreferredSize();
111  const gfx::Size folder_view_size = app_list_folder_view_->GetPreferredSize();
112
113  int width = std::max(grid_size.width(), folder_view_size.width());
114  int height = std::max(grid_size.height(), folder_view_size.height());
115  return gfx::Size(width, height);
116}
117
118void AppsContainerView::Layout() {
119  gfx::Rect rect(GetContentsBounds());
120  if (rect.IsEmpty())
121    return;
122
123  switch (show_state_) {
124    case SHOW_APPS:
125      apps_grid_view_->SetBoundsRect(rect);
126      break;
127    case SHOW_ACTIVE_FOLDER:
128      folder_background_view_->SetBoundsRect(rect);
129      app_list_folder_view_->SetBoundsRect(rect);
130      break;
131    case SHOW_ITEM_REPARENT:
132      break;
133    default:
134      NOTREACHED();
135  }
136}
137
138bool AppsContainerView::OnKeyPressed(const ui::KeyEvent& event) {
139  if (show_state_ == SHOW_APPS)
140    return apps_grid_view_->OnKeyPressed(event);
141  else
142    return app_list_folder_view_->OnKeyPressed(event);
143}
144
145void AppsContainerView::OnTopIconAnimationsComplete() {
146  --top_icon_animation_pending_count_;
147
148  if (!top_icon_animation_pending_count_) {
149    // Clean up the transitional views used for top item icon animation.
150    top_icon_views_.clear();
151
152    // Show the folder icon when closing the folder.
153    if ((show_state_ == SHOW_APPS || show_state_ == SHOW_ITEM_REPARENT) &&
154        apps_grid_view_->activated_folder_item_view()) {
155      apps_grid_view_->activated_folder_item_view()->SetVisible(true);
156    }
157  }
158}
159
160void AppsContainerView::SetShowState(ShowState show_state,
161                                     bool show_apps_with_animation) {
162  if (show_state_ == show_state)
163    return;
164
165  show_state_ = show_state;
166
167  switch (show_state_) {
168    case SHOW_APPS:
169      folder_background_view_->SetVisible(false);
170      if (show_apps_with_animation) {
171        app_list_folder_view_->ScheduleShowHideAnimation(false, false);
172        apps_grid_view_->ScheduleShowHideAnimation(true);
173      } else {
174        app_list_folder_view_->HideViewImmediately();
175        apps_grid_view_->ResetForShowApps();
176      }
177      break;
178    case SHOW_ACTIVE_FOLDER:
179      folder_background_view_->SetVisible(true);
180      apps_grid_view_->ScheduleShowHideAnimation(false);
181      app_list_folder_view_->ScheduleShowHideAnimation(true, false);
182      break;
183    case SHOW_ITEM_REPARENT:
184      folder_background_view_->SetVisible(false);
185      folder_background_view_->UpdateFolderContainerBubble(
186          FolderBackgroundView::NO_BUBBLE);
187      app_list_folder_view_->ScheduleShowHideAnimation(false, true);
188      apps_grid_view_->ScheduleShowHideAnimation(true);
189      break;
190    default:
191      NOTREACHED();
192  }
193
194  Layout();
195}
196
197Rects AppsContainerView::GetTopItemIconBoundsInActiveFolder() {
198  // Get the active folder's icon bounds relative to AppsContainerView.
199  AppListItemView* folder_item_view =
200      apps_grid_view_->activated_folder_item_view();
201  gfx::Rect to_grid_view = folder_item_view->ConvertRectToParent(
202      folder_item_view->GetIconBounds());
203  gfx::Rect to_container = apps_grid_view_->ConvertRectToParent(to_grid_view);
204
205  return AppListFolderItem::GetTopIconsBounds(to_container);
206}
207
208void AppsContainerView::CreateViewsForFolderTopItemsAnimation(
209    AppListFolderItem* active_folder,
210    bool open_folder) {
211  top_icon_views_.clear();
212  std::vector<gfx::Rect> top_items_bounds =
213      GetTopItemIconBoundsInActiveFolder();
214  top_icon_animation_pending_count_ =
215      std::min(kNumFolderTopItems, active_folder->item_list()->item_count());
216  for (size_t i = 0; i < top_icon_animation_pending_count_; ++i) {
217    if (active_folder->GetTopIcon(i).isNull())
218      continue;
219
220    TopIconAnimationView* icon_view = new TopIconAnimationView(
221        active_folder->GetTopIcon(i), top_items_bounds[i], open_folder);
222    icon_view->AddObserver(this);
223    top_icon_views_.push_back(icon_view);
224
225    // Add the transitional views into child views, and set its bounds to the
226    // same location of the item in the folder list view.
227    AddChildView(top_icon_views_[i]);
228    top_icon_views_[i]->SetBoundsRect(
229        app_list_folder_view_->ConvertRectToParent(
230            app_list_folder_view_->GetItemIconBoundsAt(i)));
231    static_cast<TopIconAnimationView*>(top_icon_views_[i])->TransformView();
232  }
233}
234
235void AppsContainerView::PrepareToShowApps(AppListFolderItem* folder_item) {
236  if (folder_item)
237    CreateViewsForFolderTopItemsAnimation(folder_item, false);
238
239  // Hide the active folder item until the animation completes.
240  if (apps_grid_view_->activated_folder_item_view())
241    apps_grid_view_->activated_folder_item_view()->SetVisible(false);
242}
243
244}  // namespace app_list
245