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