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