apps_grid_view.h revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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 "base/basictypes.h"
9#include "base/compiler_specific.h"
10#include "base/timer/timer.h"
11#include "ui/app_list/app_list_export.h"
12#include "ui/app_list/app_list_model.h"
13#include "ui/app_list/app_list_model_observer.h"
14#include "ui/app_list/pagination_model_observer.h"
15#include "ui/base/models/list_model_observer.h"
16#include "ui/views/animation/bounds_animator.h"
17#include "ui/views/controls/button/button.h"
18#include "ui/views/view.h"
19#include "ui/views/view_model.h"
20
21#if defined(OS_WIN) && !defined(USE_AURA)
22#include "ui/base/dragdrop/drag_source_win.h"
23#endif
24
25namespace views {
26class ButtonListener;
27class DragImageView;
28}
29
30namespace app_list {
31
32#if defined(OS_WIN) && !defined(USE_AURA)
33class SynchronousDrag;
34#endif
35
36namespace test {
37class AppsGridViewTestApi;
38}
39
40class ApplicationDragAndDropHost;
41class AppListItemView;
42class AppsGridViewDelegate;
43class PageSwitcher;
44class PaginationModel;
45
46// AppsGridView displays a grid for AppListModel::Apps sub model.
47class APP_LIST_EXPORT AppsGridView : public views::View,
48                                     public views::ButtonListener,
49                                     public ui::ListModelObserver,
50                                     public PaginationModelObserver,
51                                     public AppListModelObserver {
52 public:
53  enum Pointer {
54    NONE,
55    MOUSE,
56    TOUCH,
57  };
58
59  AppsGridView(AppsGridViewDelegate* delegate,
60               PaginationModel* pagination_model);
61  virtual ~AppsGridView();
62
63  // Sets fixed layout parameters. After setting this, CalculateLayout below
64  // is no longer called to dynamically choosing those layout params.
65  void SetLayout(int icon_size, int cols, int rows_per_page);
66
67  // Sets |model| to use. Note this does not take ownership of |model|.
68  void SetModel(AppListModel* model);
69
70  void SetSelectedView(views::View* view);
71  void ClearSelectedView(views::View* view);
72  bool IsSelectedView(const views::View* view) const;
73
74  // Ensures the view is visible. Note that if there is a running page
75  // transition, this does nothing.
76  void EnsureViewVisible(const views::View* view);
77
78  void InitiateDrag(AppListItemView* view,
79                    Pointer pointer,
80                    const ui::LocatedEvent& event);
81
82  // Called from AppListItemView when it receives a drag event.
83  void UpdateDragFromItem(Pointer pointer,
84                          const ui::LocatedEvent& event);
85
86  // Called when the user is dragging an app. |point| is in grid view
87  // coordinates.
88  void UpdateDrag(Pointer pointer, const gfx::Point& point);
89  void EndDrag(bool cancel);
90  bool IsDraggedView(const views::View* view) const;
91
92  void StartSettingUpSynchronousDrag();
93  bool RunSynchronousDrag();
94  void CleanUpSynchronousDrag();
95  void OnGotShortcutPath(const base::FilePath& path);
96
97  // Set the drag and drop host for application links.
98  void SetDragAndDropHostOfCurrentAppList(
99      ApplicationDragAndDropHost* drag_and_drop_host);
100
101  // Prerenders the icons on and around |page_index|.
102  void Prerender(int page_index);
103
104  bool has_dragged_view() const { return drag_view_ != NULL; }
105  bool dragging() const { return drag_pointer_ != NONE; }
106
107  // Overridden from views::View:
108  virtual gfx::Size GetPreferredSize() OVERRIDE;
109  virtual void Layout() OVERRIDE;
110  virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
111  virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE;
112  virtual void ViewHierarchyChanged(
113      const ViewHierarchyChangedDetails& details) OVERRIDE;
114  virtual bool GetDropFormats(
115      int* formats,
116      std::set<OSExchangeData::CustomFormat>* custom_formats) OVERRIDE;
117  virtual bool CanDrop(const OSExchangeData& data) OVERRIDE;
118  virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
119
120  // Stops the timer that triggers a page flip during a drag.
121  void StopPageFlipTimer();
122
123  // Get the last grid view which was created.
124  static AppsGridView* GetLastGridViewForTest();
125
126  // Return the view model for test purposes.
127  const views::ViewModel* view_model_for_test() const { return &view_model_; }
128
129  // For test: Return if the drag and drop handler was set.
130  bool has_drag_and_drop_host_for_test() { return NULL != drag_and_drop_host_; }
131
132  // For test: Return if the drag and drop operation gets dispatched.
133  bool forward_events_to_drag_and_drop_host_for_test() {
134    return forward_events_to_drag_and_drop_host_;
135  }
136
137 private:
138  friend class app_list::test::AppsGridViewTestApi;
139
140  // Represents the index to an item view in the grid.
141  struct Index {
142    Index() : page(-1), slot(-1) {}
143    Index(int page, int slot) : page(page), slot(slot) {}
144
145    bool operator==(const Index& other) const {
146      return page == other.page && slot == other.slot;
147    }
148    bool operator!=(const Index& other) const {
149      return page != other.page || slot != other.slot;
150    }
151
152    int page;  // Which page an item view is on.
153    int slot;  // Which slot in the page an item view is in.
154  };
155
156  int tiles_per_page() const { return cols_ * rows_per_page_; }
157
158  // Updates from model.
159  void Update();
160
161  // Updates page splits for item views.
162  void UpdatePaging();
163
164  // Updates the number of pulsing block views based on AppListModel status and
165  // number of apps.
166  void UpdatePulsingBlockViews();
167
168  views::View* CreateViewForItemAtIndex(size_t index);
169
170  void SetSelectedItemByIndex(const Index& index);
171  bool IsValidIndex(const Index& index) const;
172
173  Index GetIndexOfView(const views::View* view) const;
174  views::View* GetViewAtIndex(const Index& index) const;
175
176  void MoveSelected(int page_delta, int slot_x_delta, int slot_y_delta);
177
178  void CalculateIdealBounds();
179  void AnimateToIdealBounds();
180
181  // Invoked when the given |view|'s current bounds and target bounds are on
182  // different rows. To avoid moving diagonally, |view| would be put into a
183  // slot prior |target| and fade in while moving to |target|. In the meanwhile,
184  // a layer copy of |view| would start at |current| and fade out while moving
185  // to succeeding slot of |current|. |animate_current| controls whether to run
186  // fading out animation from |current|. |animate_target| controls whether to
187  // run fading in animation to |target|.
188  void AnimationBetweenRows(views::View* view,
189                            bool animate_current,
190                            const gfx::Rect& current,
191                            bool animate_target,
192                            const gfx::Rect& target);
193
194  // Extracts drag location info from |event| into |drag_point|.
195  void ExtractDragLocation(const ui::LocatedEvent& event,
196                           gfx::Point* drag_point);
197
198  // Calculates |drop_target_| based on |drag_point|. |drag_point| is in the
199  // grid view's coordinates. When |use_page_button_hovering| is true and
200  // |drag_point| is hovering on a page button, use the last slot on that page
201  // as drop target.
202  void CalculateDropTarget(const gfx::Point& drag_point,
203                           bool use_page_button_hovering);
204
205  // Prepares |drag_and_drop_host_| for dragging. |grid_location| contains
206  // the drag point in this grid view's coordinates.
207  void StartDragAndDropHostDrag(const gfx::Point& grid_location);
208
209  // Dispatch the drag and drop update event to the dnd host (if needed).
210  void DispatchDragEventToDragAndDropHost(const gfx::Point& point);
211
212  // Starts the page flip timer if |drag_point| is in left/right side page flip
213  // zone or is over page switcher.
214  void MaybeStartPageFlipTimer(const gfx::Point& drag_point);
215
216  // Invoked when |page_flip_timer_| fires.
217  void OnPageFlipTimer();
218
219  // Updates |model_| to move item represented by |item_view| to |target| slot.
220  void MoveItemInModel(views::View* item_view, const Index& target);
221
222  // Cancels any context menus showing for app items on the current page.
223  void CancelContextMenusOnCurrentPage();
224
225  // Overridden from views::ButtonListener:
226  virtual void ButtonPressed(views::Button* sender,
227                             const ui::Event& event) OVERRIDE;
228
229  // Overridden from ListModelObserver:
230  virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE;
231  virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE;
232  virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE;
233  virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE;
234
235  // Overridden from PaginationModelObserver:
236  virtual void TotalPagesChanged() OVERRIDE;
237  virtual void SelectedPageChanged(int old_selected, int new_selected) OVERRIDE;
238  virtual void TransitionStarted() OVERRIDE;
239  virtual void TransitionChanged() OVERRIDE;
240
241  // Overridden from AppListModelObserver:
242  virtual void OnAppListModelStatusChanged() OVERRIDE;
243
244  // Hide a given view temporarily without losing (mouse) events and / or
245  // changing the size of it.
246  void HideView(views::View* view, bool hide);
247
248  AppListModel* model_;  // Owned by AppListView.
249  AppsGridViewDelegate* delegate_;
250  PaginationModel* pagination_model_;  // Owned by AppListController.
251  PageSwitcher* page_switcher_view_;  // Owned by views hierarchy.
252
253  gfx::Size icon_size_;
254  int cols_;
255  int rows_per_page_;
256
257  // Tracks app item views. There is a view per item in |model_|.
258  views::ViewModel view_model_;
259
260  // Tracks pulsing block views.
261  views::ViewModel pulsing_blocks_model_;
262
263  views::View* selected_view_;
264
265  AppListItemView* drag_view_;
266
267  // The point where the drag started in AppListItemView coordinates.
268  gfx::Point drag_view_offset_;
269
270  // The point where the drag started in GridView coordinates.
271  gfx::Point drag_start_grid_view_;
272
273  // The location of |drag_view_| when the drag started.
274  gfx::Point drag_view_start_;
275
276#if defined(OS_WIN) && !defined(USE_AURA)
277  // Created when a drag is started (ie: drag exceeds the drag threshold), but
278  // not Run() until supplied with a shortcut path.
279  scoped_refptr<SynchronousDrag> synchronous_drag_;
280#endif
281
282  Pointer drag_pointer_;
283  Index drop_target_;
284
285  // An application target drag and drop host which accepts dnd operations.
286  ApplicationDragAndDropHost* drag_and_drop_host_;
287
288  // The drag operation is currently inside the dnd host and events get
289  // forwarded.
290  bool forward_events_to_drag_and_drop_host_;
291
292  // Last mouse drag location in this view's coordinates.
293  gfx::Point last_drag_point_;
294
295  // Timer to auto flip page when dragging an item near the left/right edges.
296  base::OneShotTimer<AppsGridView> page_flip_timer_;
297
298  // Target page to switch to when |page_flip_timer_| fires.
299  int page_flip_target_;
300
301  // Delay in milliseconds of when |page_flip_timer_| should fire after user
302  // drags an item near the edges.
303  int page_flip_delay_in_ms_;
304
305  views::BoundsAnimator bounds_animator_;
306
307  DISALLOW_COPY_AND_ASSIGN(AppsGridView);
308};
309
310}  // namespace app_list
311
312#endif  // UI_APP_LIST_VIEWS_APPS_GRID_VIEW_H_
313