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