Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / app_list / views / apps_grid_view.h
1 // Copyright (c) 2012 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 #ifndef UI_APP_LIST_VIEWS_APPS_GRID_VIEW_H_
6 #define UI_APP_LIST_VIEWS_APPS_GRID_VIEW_H_
7
8 #include <set>
9 #include <string>
10
11 #include "base/basictypes.h"
12 #include "base/compiler_specific.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/timer/timer.h"
15 #include "ui/app_list/app_list_export.h"
16 #include "ui/app_list/app_list_model.h"
17 #include "ui/app_list/app_list_model_observer.h"
18 #include "ui/app_list/pagination_model.h"
19 #include "ui/app_list/pagination_model_observer.h"
20 #include "ui/base/models/list_model_observer.h"
21 #include "ui/compositor/layer_animation_observer.h"
22 #include "ui/gfx/image/image_skia_operations.h"
23 #include "ui/views/animation/bounds_animator.h"
24 #include "ui/views/controls/button/button.h"
25 #include "ui/views/controls/image_view.h"
26 #include "ui/views/view.h"
27 #include "ui/views/view_model.h"
28
29 #if defined(OS_WIN)
30 #include "ui/base/dragdrop/drag_source_win.h"
31 #endif
32
33 namespace views {
34 class ButtonListener;
35 class DragImageView;
36 }
37
38 namespace app_list {
39
40 #if defined(OS_WIN)
41 class SynchronousDrag;
42 #endif
43
44 namespace test {
45 class AppsGridViewTestApi;
46 }
47
48 class ApplicationDragAndDropHost;
49 class AppListItemView;
50 class AppsGridViewDelegate;
51 class AppsGridViewFolderDelegate;
52 class PageSwitcher;
53 class PaginationController;
54 class PulsingBlockView;
55
56 // AppsGridView displays a grid for AppListItemList sub model.
57 class APP_LIST_EXPORT AppsGridView : public views::View,
58                                      public views::ButtonListener,
59                                      public AppListItemListObserver,
60                                      public PaginationModelObserver,
61                                      public AppListModelObserver,
62                                      public ui::ImplicitAnimationObserver {
63  public:
64   enum Pointer {
65     NONE,
66     MOUSE,
67     TOUCH,
68   };
69
70   // Constructs the app icon grid view. |delegate| is the delegate of this
71   // view, which usually is the hosting AppListView.
72   explicit AppsGridView(AppsGridViewDelegate* delegate);
73   ~AppsGridView() override;
74
75   // Sets fixed layout parameters. After setting this, CalculateLayout below
76   // is no longer called to dynamically choosing those layout params.
77   void SetLayout(int cols, int rows_per_page);
78
79   int cols() const { return cols_; }
80   int rows_per_page() const { return rows_per_page_; }
81
82   // This resets the grid view to a fresh state for showing the app list.
83   void ResetForShowApps();
84
85   // Sets |model| to use. Note this does not take ownership of |model|.
86   void SetModel(AppListModel* model);
87
88   // Sets the |item_list| to render. Note this does not take ownership of
89   // |item_list|.
90   void SetItemList(AppListItemList* item_list);
91
92   void SetSelectedView(AppListItemView* view);
93   void ClearSelectedView(AppListItemView* view);
94   void ClearAnySelectedView();
95   bool IsSelectedView(const AppListItemView* view) const;
96
97   void InitiateDrag(AppListItemView* view,
98                     Pointer pointer,
99                     const ui::LocatedEvent& event);
100
101   // Called from AppListItemView when it receives a drag event. Returns true
102   // if the drag is still happening.
103   bool UpdateDragFromItem(Pointer pointer, const ui::LocatedEvent& event);
104
105   // Called when the user is dragging an app. |point| is in grid view
106   // coordinates.
107   void UpdateDrag(Pointer pointer, const gfx::Point& point);
108   void EndDrag(bool cancel);
109   bool IsDraggedView(const AppListItemView* view) const;
110   void ClearDragState();
111   void SetDragViewVisible(bool visible);
112
113   // Set the drag and drop host for application links.
114   void SetDragAndDropHostOfCurrentAppList(
115       ApplicationDragAndDropHost* drag_and_drop_host);
116
117   // Prerenders the icons on and around the currently selected page.
118   void Prerender();
119
120   // Return true if the |bounds_animator_| is animating |view|.
121   bool IsAnimatingView(AppListItemView* view);
122
123   bool has_dragged_view() const { return drag_view_ != NULL; }
124   bool dragging() const { return drag_pointer_ != NONE; }
125
126   // Gets the PaginationModel used for the grid view.
127   PaginationModel* pagination_model() { return &pagination_model_; }
128
129   // Overridden from views::View:
130   gfx::Size GetPreferredSize() const override;
131   void Layout() override;
132   bool OnKeyPressed(const ui::KeyEvent& event) override;
133   bool OnKeyReleased(const ui::KeyEvent& event) override;
134   bool OnMouseWheel(const ui::MouseWheelEvent& event) override;
135   void ViewHierarchyChanged(
136       const ViewHierarchyChangedDetails& details) override;
137   bool GetDropFormats(
138       int* formats,
139       std::set<OSExchangeData::CustomFormat>* custom_formats) override;
140   bool CanDrop(const OSExchangeData& data) override;
141   int OnDragUpdated(const ui::DropTargetEvent& event) override;
142
143   // Overridden from ui::EventHandler:
144   void OnGestureEvent(ui::GestureEvent* event) override;
145   void OnScrollEvent(ui::ScrollEvent* event) override;
146
147   // Stops the timer that triggers a page flip during a drag.
148   void StopPageFlipTimer();
149
150   // Returns the item view of the item at |index|.
151   AppListItemView* GetItemViewAt(int index) const;
152
153   // Show or hide the top item views.
154   void SetTopItemViewsVisible(bool visible);
155
156   // Schedules an animation to show or hide the view.
157   void ScheduleShowHideAnimation(bool show);
158
159   // Called to initiate drag for reparenting a folder item in root level grid
160   // view.
161   // Both |drag_view_rect| and |drag_pint| is in the coordinates of root level
162   // grid view.
163   void InitiateDragFromReparentItemInRootLevelGridView(
164       AppListItemView* original_drag_view,
165       const gfx::Rect& drag_view_rect,
166       const gfx::Point& drag_point,
167       bool has_native_drag);
168
169   // Updates drag in the root level grid view when receiving the drag event
170   // dispatched from the hidden grid view for reparenting a folder item.
171   void UpdateDragFromReparentItem(Pointer pointer,
172                                   const gfx::Point& drag_point);
173
174   // Dispatches the drag event from hidden grid view to the top level grid view.
175   void DispatchDragEventForReparent(Pointer pointer,
176                                     const gfx::Point& drag_point);
177
178   // Handles EndDrag event dispatched from the hidden folder grid view in the
179   // root level grid view to end reparenting a folder item.
180   // |events_forwarded_to_drag_drop_host|: True if the dragged item is dropped
181   // to the drag_drop_host, eg. dropped on shelf.
182   // |cancel_drag|: True if the drag is ending because it has been canceled.
183   void EndDragFromReparentItemInRootLevel(
184       bool events_forwarded_to_drag_drop_host,
185       bool cancel_drag);
186
187   // Handles EndDrag event in the hidden folder grid view to end reparenting
188   // a folder item.
189   void EndDragForReparentInHiddenFolderGridView();
190
191   // Called when the folder item associated with the grid view is removed.
192   // The grid view must be inside a folder view.
193   void OnFolderItemRemoved();
194
195   // Return the view model for test purposes.
196   const views::ViewModelT<AppListItemView>* view_model_for_test() const {
197     return &view_model_;
198   }
199
200   // For test: Return if the drag and drop handler was set.
201   bool has_drag_and_drop_host_for_test() { return NULL != drag_and_drop_host_; }
202
203   // For test: Return if the drag and drop operation gets dispatched.
204   bool forward_events_to_drag_and_drop_host_for_test() {
205     return forward_events_to_drag_and_drop_host_;
206   }
207
208   void set_folder_delegate(AppsGridViewFolderDelegate* folder_delegate) {
209     folder_delegate_ = folder_delegate;
210   }
211
212   AppListItemView* activated_folder_item_view() const {
213     return activated_folder_item_view_;
214   }
215
216   const AppListModel* model() const { return model_; }
217
218  private:
219   friend class test::AppsGridViewTestApi;
220
221   enum DropAttempt {
222     DROP_FOR_NONE,
223     DROP_FOR_REORDER,
224     DROP_FOR_FOLDER,
225   };
226
227   // Represents the index to an item view in the grid.
228   struct Index {
229     Index() : page(-1), slot(-1) {}
230     Index(int page, int slot) : page(page), slot(slot) {}
231
232     bool operator==(const Index& other) const {
233       return page == other.page && slot == other.slot;
234     }
235     bool operator!=(const Index& other) const {
236       return page != other.page || slot != other.slot;
237     }
238     bool operator<(const Index& other) const {
239       if (page != other.page)
240         return page < other.page;
241
242       return slot < other.slot;
243     }
244
245     int page;  // Which page an item view is on.
246     int slot;  // Which slot in the page an item view is in.
247   };
248
249   int tiles_per_page() const { return cols_ * rows_per_page_; }
250
251   // Updates from model.
252   void Update();
253
254   // Updates page splits for item views.
255   void UpdatePaging();
256
257   // Updates the number of pulsing block views based on AppListModel status and
258   // number of apps.
259   void UpdatePulsingBlockViews();
260
261   AppListItemView* CreateViewForItemAtIndex(size_t index);
262
263   // Convert between the model index and the visual index. The model index
264   // is the index of the item in AppListModel. The visual index is the Index
265   // struct above with page/slot info of where to display the item.
266   Index GetIndexFromModelIndex(int model_index) const;
267   int GetModelIndexFromIndex(const Index& index) const;
268
269   // Ensures the view is visible. Note that if there is a running page
270   // transition, this does nothing.
271   void EnsureViewVisible(const Index& index);
272
273   void SetSelectedItemByIndex(const Index& index);
274   bool IsValidIndex(const Index& index) const;
275
276   Index GetIndexOfView(const AppListItemView* view) const;
277   AppListItemView* GetViewAtIndex(const Index& index) const;
278
279   // Gets the index of the AppListItemView at the end of the view model.
280   Index GetLastViewIndex() const;
281
282   void MoveSelected(int page_delta, int slot_x_delta, int slot_y_delta);
283
284   void CalculateIdealBounds();
285   void AnimateToIdealBounds();
286
287   // Invoked when the given |view|'s current bounds and target bounds are on
288   // different rows. To avoid moving diagonally, |view| would be put into a
289   // slot prior |target| and fade in while moving to |target|. In the meanwhile,
290   // a layer copy of |view| would start at |current| and fade out while moving
291   // to succeeding slot of |current|. |animate_current| controls whether to run
292   // fading out animation from |current|. |animate_target| controls whether to
293   // run fading in animation to |target|.
294   void AnimationBetweenRows(AppListItemView* view,
295                             bool animate_current,
296                             const gfx::Rect& current,
297                             bool animate_target,
298                             const gfx::Rect& target);
299
300   // Extracts drag location info from |event| into |drag_point|.
301   void ExtractDragLocation(const ui::LocatedEvent& event,
302                            gfx::Point* drag_point);
303
304   // Updates |reorder_drop_target_|, |folder_drop_target_| and |drop_attempt_|
305   // based on |drag_view_|'s position.
306   void CalculateDropTarget();
307
308   // If |point| is a valid folder drop target, returns true and sets
309   // |drop_target| to the index of the view to do a folder drop for.
310   bool CalculateFolderDropTarget(const gfx::Point& point,
311                                  Index* drop_target) const;
312
313   // Calculates the reorder target |point| and sets |drop_target| to the index
314   // of the view to reorder.
315   void CalculateReorderDropTarget(const gfx::Point& point,
316                                   Index* drop_target) const;
317
318   // Prepares |drag_and_drop_host_| for dragging. |grid_location| contains
319   // the drag point in this grid view's coordinates.
320   void StartDragAndDropHostDrag(const gfx::Point& grid_location);
321
322   // Dispatch the drag and drop update event to the dnd host (if needed).
323   void DispatchDragEventToDragAndDropHost(
324       const gfx::Point& location_in_screen_coordinates);
325
326   // Starts the page flip timer if |drag_point| is in left/right side page flip
327   // zone or is over page switcher.
328   void MaybeStartPageFlipTimer(const gfx::Point& drag_point);
329
330   // Invoked when |page_flip_timer_| fires.
331   void OnPageFlipTimer();
332
333   // Updates |model_| to move item represented by |item_view| to |target| slot.
334   void MoveItemInModel(AppListItemView* item_view, const Index& target);
335
336   // Updates |model_| to move item represented by |item_view| into a folder
337   // containing item located at |target| slot, also update |view_model_| for
338   // the related view changes.
339   void MoveItemToFolder(AppListItemView* item_view, const Index& target);
340
341   // Updates both data model and view_model_ for re-parenting a folder item to a
342   // new position in top level item list.
343   void ReparentItemForReorder(AppListItemView* item_view, const Index& target);
344
345   // Updates both data model and view_model_ for re-parenting a folder item
346   // to anther folder target.
347   void ReparentItemToAnotherFolder(AppListItemView* item_view,
348                                    const Index& target);
349
350   // If there is only 1 item left in the source folder after reparenting an item
351   // from it, updates both data model and view_model_ for removing last item
352   // from the source folder and removes the source folder.
353   void RemoveLastItemFromReparentItemFolderIfNecessary(
354       const std::string& source_folder_id);
355
356   // If user does not drop the re-parenting folder item to any valid target,
357   // cancel the re-parenting action, let the item go back to its original
358   // parent folder with UI animation.
359   void CancelFolderItemReparent(AppListItemView* drag_item_view);
360
361   // Cancels any context menus showing for app items on the current page.
362   void CancelContextMenusOnCurrentPage();
363
364   // Removes the AppListItemView at |index| in |view_model_| and deletes it.
365   void DeleteItemViewAtIndex(int index);
366
367   // Returns true if |point| lies within the bounds of this grid view plus a
368   // buffer area surrounding it.
369   bool IsPointWithinDragBuffer(const gfx::Point& point) const;
370
371   // Overridden from views::ButtonListener:
372   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
373
374   // Overridden from AppListItemListObserver:
375   void OnListItemAdded(size_t index, AppListItem* item) override;
376   void OnListItemRemoved(size_t index, AppListItem* item) override;
377   void OnListItemMoved(size_t from_index,
378                        size_t to_index,
379                        AppListItem* item) override;
380   void OnAppListItemHighlight(size_t index, bool highlight) override;
381
382   // Overridden from PaginationModelObserver:
383   void TotalPagesChanged() override;
384   void SelectedPageChanged(int old_selected, int new_selected) override;
385   void TransitionStarted() override;
386   void TransitionChanged() override;
387
388   // Overridden from AppListModelObserver:
389   void OnAppListModelStatusChanged() override;
390
391   // ui::ImplicitAnimationObserver overrides:
392   void OnImplicitAnimationsCompleted() override;
393
394   // Hide a given view temporarily without losing (mouse) events and / or
395   // changing the size of it. If |immediate| is set the change will be
396   // immediately applied - otherwise it will change gradually.
397   // If |hide| is set the view will get hidden, otherwise it gets shown.
398   void SetViewHidden(AppListItemView* view, bool hide, bool immediate);
399
400   // Whether the folder drag-and-drop UI should be enabled.
401   bool EnableFolderDragDropUI();
402
403   // Returns the size of the entire tile grid.
404   gfx::Size GetTileGridSize() const;
405
406   // Returns the slot number which the given |point| falls into or the closest
407   // slot if |point| is outside the page's bounds.
408   Index GetNearestTileIndexForPoint(const gfx::Point& point) const;
409
410   // Gets the bounds of the tile located at |slot| on the current page.
411   gfx::Rect GetExpectedTileBounds(int slot) const;
412
413   // Gets the bounds of the tile located at |row| and |col| on the current page.
414   gfx::Rect GetExpectedTileBounds(int row, int col) const;
415
416   // Gets the item view currently displayed at |slot| on the current page. If
417   // there is no item displayed at |slot|, returns NULL. Note that this finds an
418   // item *displayed* at a slot, which may differ from the item's location in
419   // the model (as it may have been temporarily moved during a drag operation).
420   AppListItemView* GetViewDisplayedAtSlotOnCurrentPage(int slot) const;
421
422   // Sets state of the view with |target_index| to |is_target_folder| for
423   // dropping |drag_view_|.
424   void SetAsFolderDroppingTarget(const Index& target_index,
425                                  bool is_target_folder);
426
427   // Invoked when |reorder_timer_| fires to show re-order preview UI.
428   void OnReorderTimer();
429
430   // Invoked when |folder_item_reparent_timer_| fires.
431   void OnFolderItemReparentTimer();
432
433   // Invoked when |folder_dropping_timer_| fires to show folder dropping
434   // preview UI.
435   void OnFolderDroppingTimer();
436
437   // Updates drag state for dragging inside a folder's grid view.
438   void UpdateDragStateInsideFolder(Pointer pointer,
439                                    const gfx::Point& drag_point);
440
441   // Returns true if drag event is happening in the root level AppsGridView
442   // for reparenting a folder item.
443   bool IsDraggingForReparentInRootLevelGridView() const;
444
445   // Returns true if drag event is happening in the hidden AppsGridView of the
446   // folder during reparenting a folder item.
447   bool IsDraggingForReparentInHiddenGridView() const;
448
449   // Returns the target icon bounds for |drag_item_view| to fly back
450   // to its parent |folder_item_view| in animation.
451   gfx::Rect GetTargetIconRectInFolder(AppListItemView* drag_item_view,
452       AppListItemView* folder_item_view);
453
454   // Returns true if the grid view is under an OEM folder.
455   bool IsUnderOEMFolder();
456
457   void StartSettingUpSynchronousDrag();
458   bool RunSynchronousDrag();
459   void CleanUpSynchronousDrag();
460 #if defined(OS_WIN)
461   void OnGotShortcutPath(scoped_refptr<SynchronousDrag> drag,
462                          const base::FilePath& path);
463 #endif
464
465   AppListModel* model_;  // Owned by AppListView.
466   AppListItemList* item_list_;  // Not owned.
467   AppsGridViewDelegate* delegate_;
468
469   // This can be NULL. Only grid views inside folders have a folder delegate.
470   AppsGridViewFolderDelegate* folder_delegate_;
471
472   PaginationModel pagination_model_;
473   // Must appear after |pagination_model_|.
474   scoped_ptr<PaginationController> pagination_controller_;
475   PageSwitcher* page_switcher_view_;  // Owned by views hierarchy.
476
477   int cols_;
478   int rows_per_page_;
479
480   // List of app item views. There is a view per item in |model_|.
481   views::ViewModelT<AppListItemView> view_model_;
482
483   // List of pulsing block views.
484   views::ViewModelT<PulsingBlockView> pulsing_blocks_model_;
485
486   AppListItemView* selected_view_;
487
488   AppListItemView* drag_view_;
489
490   // The index of the drag_view_ when the drag starts.
491   Index drag_view_init_index_;
492
493   // The point where the drag started in AppListItemView coordinates.
494   gfx::Point drag_view_offset_;
495
496   // The point where the drag started in GridView coordinates.
497   gfx::Point drag_start_grid_view_;
498
499   // The location of |drag_view_| when the drag started.
500   gfx::Point drag_view_start_;
501
502   // Page the drag started on.
503   int drag_start_page_;
504
505 #if defined(OS_WIN)
506   // Created when a drag is started (ie: drag exceeds the drag threshold), but
507   // not Run() until supplied with a shortcut path.
508   scoped_refptr<SynchronousDrag> synchronous_drag_;
509
510   // Whether to use SynchronousDrag to support dropping to task bar etc.
511   bool use_synchronous_drag_;
512 #endif
513
514   Pointer drag_pointer_;
515
516   // The most recent reorder drop target.
517   Index reorder_drop_target_;
518
519   // The most recent folder drop target.
520   Index folder_drop_target_;
521
522   // The index where an empty slot has been left as a placeholder for the
523   // reorder drop target. This updates when the reorder animation triggers.
524   Index reorder_placeholder_;
525
526   // The current action that ending a drag will perform.
527   DropAttempt drop_attempt_;
528
529   // Timer for re-ordering the |drop_target_| and |drag_view_|.
530   base::OneShotTimer<AppsGridView> reorder_timer_;
531
532   // Timer for dropping |drag_view_| into the folder containing
533   // the |drop_target_|.
534   base::OneShotTimer<AppsGridView> folder_dropping_timer_;
535
536   // Timer for dragging a folder item out of folder container ink bubble.
537   base::OneShotTimer<AppsGridView> folder_item_reparent_timer_;
538
539   // An application target drag and drop host which accepts dnd operations.
540   ApplicationDragAndDropHost* drag_and_drop_host_;
541
542   // The drag operation is currently inside the dnd host and events get
543   // forwarded.
544   bool forward_events_to_drag_and_drop_host_;
545
546   // Last mouse drag location in this view's coordinates.
547   gfx::Point last_drag_point_;
548
549   // Timer to auto flip page when dragging an item near the left/right edges.
550   base::OneShotTimer<AppsGridView> page_flip_timer_;
551
552   // Target page to switch to when |page_flip_timer_| fires.
553   int page_flip_target_;
554
555   // Delay in milliseconds of when |page_flip_timer_| should fire after user
556   // drags an item near the edges.
557   int page_flip_delay_in_ms_;
558
559   views::BoundsAnimator bounds_animator_;
560
561   // The most recent activated folder item view.
562   AppListItemView* activated_folder_item_view_;
563
564   // Tracks if drag_view_ is dragged out of the folder container bubble
565   // when dragging a item inside a folder.
566   bool drag_out_of_folder_container_;
567
568   // True if the drag_view_ item is a folder item being dragged for reparenting.
569   bool dragging_for_reparent_item_;
570
571   DISALLOW_COPY_AND_ASSIGN(AppsGridView);
572 };
573
574 }  // namespace app_list
575
576 #endif  // UI_APP_LIST_VIEWS_APPS_GRID_VIEW_H_