Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / ui / app_list / views / app_list_folder_view.cc
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/app_list_folder_view.h"
6
7 #include <algorithm>
8
9 #include "ui/app_list/app_list_constants.h"
10 #include "ui/app_list/app_list_folder_item.h"
11 #include "ui/app_list/app_list_model.h"
12 #include "ui/app_list/pagination_model.h"
13 #include "ui/app_list/views/app_list_item_view.h"
14 #include "ui/app_list/views/app_list_main_view.h"
15 #include "ui/app_list/views/apps_container_view.h"
16 #include "ui/app_list/views/apps_grid_view.h"
17 #include "ui/app_list/views/contents_view.h"
18 #include "ui/app_list/views/folder_background_view.h"
19 #include "ui/app_list/views/folder_header_view.h"
20 #include "ui/compositor/scoped_layer_animation_settings.h"
21 #include "ui/events/event.h"
22 #include "ui/gfx/rect_conversions.h"
23 #include "ui/views/view_model.h"
24 #include "ui/views/view_model_utils.h"
25
26 namespace app_list {
27
28 namespace {
29
30 // Indexes of interesting views in ViewModel of AppListFolderView.
31 const int kIndexFolderHeader = 0;
32 const int kIndexChildItems = 1;
33
34 // Threshold for the distance from the center of the item to the circle of the
35 // folder container ink bubble, beyond which, the item is considered dragged
36 // out of the folder boundary.
37 const int kOutOfFolderContainerBubbleDelta = 30;
38
39 }  // namespace
40
41 AppListFolderView::AppListFolderView(AppsContainerView* container_view,
42                                      AppListModel* model,
43                                      AppListMainView* app_list_main_view,
44                                      content::WebContents* start_page_contents)
45     : container_view_(container_view),
46       folder_header_view_(new FolderHeaderView(this)),
47       view_model_(new views::ViewModel),
48       model_(model),
49       folder_item_(NULL),
50       pagination_model_(new PaginationModel),
51       hide_for_reparent_(false) {
52   AddChildView(folder_header_view_);
53   view_model_->Add(folder_header_view_, kIndexFolderHeader);
54
55   items_grid_view_ = new AppsGridView(
56       app_list_main_view, pagination_model_.get(), NULL);
57   items_grid_view_->set_is_root_level(false);
58   items_grid_view_->SetLayout(
59       kPreferredIconDimension,
60       container_view->apps_grid_view()->cols(),
61       container_view->apps_grid_view()->rows_per_page());
62   items_grid_view_->SetModel(model);
63   AddChildView(items_grid_view_);
64   view_model_->Add(items_grid_view_, kIndexChildItems);
65
66 #if defined(USE_AURA)
67   SetPaintToLayer(true);
68   SetFillsBoundsOpaquely(false);
69 #endif
70
71   model_->item_list()->AddObserver(this);
72 }
73
74 AppListFolderView::~AppListFolderView() {
75   model_->item_list()->RemoveObserver(this);
76   // Make sure |items_grid_view_| is deleted before |pagination_model_|.
77   RemoveAllChildViews(true);
78 }
79
80 void AppListFolderView::SetAppListFolderItem(AppListFolderItem* folder) {
81   folder_item_ = folder;
82   items_grid_view_->SetItemList(folder_item_->item_list());
83   folder_header_view_->SetFolderItem(folder_item_);
84 }
85
86 void AppListFolderView::ScheduleShowHideAnimation(bool show,
87                                                   bool hide_for_reparent) {
88   hide_for_reparent_ = hide_for_reparent;
89
90   // Stop any previous animation.
91   layer()->GetAnimator()->StopAnimating();
92
93   // Hide the top items temporarily if showing the view for opening the folder.
94   if (show)
95     items_grid_view_->SetTopItemViewsVisible(false);
96
97   // Set initial state.
98   layer()->SetOpacity(show ? 0.0f : 1.0f);
99   SetVisible(true);
100   UpdateFolderNameVisibility(true);
101
102   ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator());
103   animation.SetTweenType(
104       show ? kFolderFadeInTweenType : kFolderFadeOutTweenType);
105   animation.AddObserver(this);
106   animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
107       show ? kFolderTransitionInDurationMs : kFolderTransitionOutDurationMs));
108
109   layer()->SetOpacity(show ? 1.0f : 0.0f);
110 }
111
112 gfx::Size AppListFolderView::GetPreferredSize() {
113   const gfx::Size header_size = folder_header_view_->GetPreferredSize();
114   const gfx::Size grid_size = items_grid_view_->GetPreferredSize();
115   int width = std::max(header_size.width(), grid_size.width());
116   int height = header_size.height() + grid_size.height();
117   return gfx::Size(width, height);
118 }
119
120 void AppListFolderView::Layout() {
121   CalculateIdealBounds();
122   views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_);
123 }
124
125 bool AppListFolderView::OnKeyPressed(const ui::KeyEvent& event) {
126   return items_grid_view_->OnKeyPressed(event);
127 }
128
129 void AppListFolderView::OnListItemRemoved(size_t index, AppListItem* item) {
130   if (item == folder_item_) {
131     items_grid_view_->OnFolderItemRemoved();
132     folder_header_view_->OnFolderItemRemoved();
133     folder_item_ = NULL;
134
135     // Do not change state if it is hidden.
136     if (layer()->opacity() == 0.0f)
137       return;
138
139     // If the folder item associated with this view is removed from the model,
140     // (e.g. the last item in the folder was deleted), reset the view and signal
141     // the container view to show the app list instead.
142     // Pass NULL to ShowApps() to avoid triggering animation from the deleted
143     // folder.
144     container_view_->ShowApps(NULL);
145   }
146 }
147
148 void AppListFolderView::OnImplicitAnimationsCompleted() {
149   // Show the top items when the opening folder animation is done.
150   if (layer()->opacity() == 1.0f)
151     items_grid_view_->SetTopItemViewsVisible(true);
152
153   // If the view is hidden for reparenting a folder item, it has to be visible,
154   // so that drag_view_ can keep receiving mouse events.
155   if (layer()->opacity() == 0.0f && !hide_for_reparent_)
156     SetVisible(false);
157
158   // Set the view bounds to a small rect, so that it won't overlap the root
159   // level apps grid view during folder item reprenting transitional period.
160   if (hide_for_reparent_)
161     SetBoundsRect(gfx::Rect(bounds().x(), bounds().y(), 1, 1));
162 }
163
164 void AppListFolderView::CalculateIdealBounds() {
165   gfx::Rect rect(GetContentsBounds());
166   if (rect.IsEmpty())
167     return;
168
169   gfx::Rect header_frame(rect);
170   gfx::Size size = folder_header_view_->GetPreferredSize();
171   header_frame.set_height(size.height());
172   view_model_->set_ideal_bounds(kIndexFolderHeader, header_frame);
173
174   gfx::Rect grid_frame(rect);
175   grid_frame.Subtract(header_frame);
176   view_model_->set_ideal_bounds(kIndexChildItems, grid_frame);
177 }
178
179 void AppListFolderView::StartSetupDragInRootLevelAppsGridView(
180     AppListItemView* original_drag_view,
181     const gfx::Point& drag_point_in_root_grid) {
182   // Converts the original_drag_view's bounds to the coordinate system of
183   // root level grid view.
184   gfx::RectF rect_f(original_drag_view->bounds());
185   views::View::ConvertRectToTarget(items_grid_view_,
186                                    container_view_->apps_grid_view(),
187                                    &rect_f);
188   gfx::Rect rect_in_root_grid_view = gfx::ToEnclosingRect(rect_f);
189
190   container_view_->apps_grid_view()->
191       InitiateDragFromReparentItemInRootLevelGridView(
192           original_drag_view, rect_in_root_grid_view, drag_point_in_root_grid);
193 }
194
195 gfx::Rect AppListFolderView::GetItemIconBoundsAt(int index) {
196   AppListItemView* item_view = items_grid_view_->GetItemViewAt(index);
197   // Icon bounds relative to AppListItemView.
198   const gfx::Rect icon_bounds = item_view->GetIconBounds();
199   gfx::Rect to_apps_grid_view = item_view->ConvertRectToParent(icon_bounds);
200   gfx::Rect to_folder =
201       items_grid_view_->ConvertRectToParent(to_apps_grid_view);
202
203   // Get the icon image's bound.
204   to_folder.ClampToCenteredSize(
205       gfx::Size(kPreferredIconDimension, kPreferredIconDimension));
206
207   return to_folder;
208 }
209
210 void AppListFolderView::UpdateFolderViewBackground(bool show_bubble) {
211   if (hide_for_reparent_)
212     return;
213
214   // Before showing the folder container inking bubble, hide the folder name.
215   if (show_bubble)
216     UpdateFolderNameVisibility(false);
217
218   container_view_->folder_background_view()->UpdateFolderContainerBubble(
219       show_bubble ? FolderBackgroundView::SHOW_BUBBLE :
220                     FolderBackgroundView::HIDE_BUBBLE);
221 }
222
223 void AppListFolderView::UpdateFolderNameVisibility(bool visible) {
224   folder_header_view_->UpdateFolderNameVisibility(visible);
225 }
226
227 bool AppListFolderView::IsPointOutsideOfFolderBoundray(
228     const gfx::Point& point) {
229   if (!GetLocalBounds().Contains(point))
230     return true;
231
232   gfx::Point center = GetLocalBounds().CenterPoint();
233   float delta = (point - center).Length();
234   return delta > container_view_->folder_background_view()->
235       GetFolderContainerBubbleRadius() + kOutOfFolderContainerBubbleDelta;
236 }
237
238 // When user drags a folder item out of the folder boundary ink bubble, the
239 // folder view UI will be hidden, and switch back to top level AppsGridView.
240 // The dragged item will seamlessly move on the top level AppsGridView.
241 // In order to achieve the above, we keep the folder view and its child grid
242 // view visible with opacity 0, so that the drag_view_ on the hidden grid view
243 // will keep receiving mouse event. At the same time, we initiated a new
244 // drag_view_ in the top level grid view, and keep it moving with the hidden
245 // grid view's drag_view_, so that the dragged item can be engaged in drag and
246 // drop flow in the top level grid view. During the reparenting process, the
247 // drag_view_ in hidden grid view will dispatch the drag and drop event to
248 // the top level grid view, until the drag ends.
249 void AppListFolderView::ReparentItem(
250     AppListItemView* original_drag_view,
251     const gfx::Point& drag_point_in_folder_grid) {
252   // Convert the drag point relative to the root level AppsGridView.
253   gfx::Point to_root_level_grid = drag_point_in_folder_grid;
254   ConvertPointToTarget(items_grid_view_,
255                        container_view_->apps_grid_view(),
256                        &to_root_level_grid);
257   StartSetupDragInRootLevelAppsGridView(original_drag_view, to_root_level_grid);
258   container_view_->ReparentFolderItemTransit(folder_item_);
259 }
260
261 void AppListFolderView::DispatchDragEventForReparent(
262     AppsGridView::Pointer pointer,
263     const ui::LocatedEvent& event) {
264   container_view_->apps_grid_view()->UpdateDragFromReparentItem(pointer, event);
265 }
266
267 void AppListFolderView::DispatchEndDragEventForReparent(
268     bool events_forwarded_to_drag_drop_host) {
269   container_view_->apps_grid_view()->
270       EndDragFromReparentItemInRootLevel(events_forwarded_to_drag_drop_host);
271 }
272
273
274 void AppListFolderView::HideViewImmediately() {
275   SetVisible(false);
276   hide_for_reparent_ = false;
277 }
278
279 void AppListFolderView::NavigateBack(AppListFolderItem* item,
280                                      const ui::Event& event_flags) {
281   container_view_->ShowApps(item);
282 }
283
284 }  // namespace app_list