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