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