Views Omnibox: tolerate minor click-to-select-all dragging.
[chromium-blink-merge.git] / ui / app_list / views / apps_grid_view.h
blob3958d67e4ac4edeae84357c95379d6808537021d
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>
10 #include "base/basictypes.h"
11 #include "base/compiler_specific.h"
12 #include "base/timer/timer.h"
13 #include "ui/app_list/app_list_export.h"
14 #include "ui/app_list/app_list_model.h"
15 #include "ui/app_list/app_list_model_observer.h"
16 #include "ui/app_list/pagination_model_observer.h"
17 #include "ui/base/models/list_model_observer.h"
18 #include "ui/compositor/layer_animation_observer.h"
19 #include "ui/views/animation/bounds_animator.h"
20 #include "ui/views/controls/button/button.h"
21 #include "ui/views/view.h"
22 #include "ui/views/view_model.h"
24 #if defined(OS_WIN)
25 #include "ui/base/dragdrop/drag_source_win.h"
26 #endif
28 namespace content {
29 class WebContents;
32 namespace views {
33 class ButtonListener;
34 class DragImageView;
35 class WebView;
38 namespace app_list {
40 #if defined(OS_WIN)
41 class SynchronousDrag;
42 #endif
44 namespace test {
45 class AppsGridViewTestApi;
48 class ApplicationDragAndDropHost;
49 class AppListItemView;
50 class AppsGridViewDelegate;
51 class PageSwitcher;
52 class PaginationModel;
54 // AppsGridView displays a grid for AppListItemList sub model.
55 class APP_LIST_EXPORT AppsGridView : public views::View,
56 public views::ButtonListener,
57 public AppListItemListObserver,
58 public PaginationModelObserver,
59 public AppListModelObserver,
60 public ui::ImplicitAnimationObserver {
61 public:
62 enum Pointer {
63 NONE,
64 MOUSE,
65 TOUCH,
68 // Constructs the app icon grid view. |delegate| is the delegate of this
69 // view, which usually is the hosting AppListView. |pagination_model| is
70 // the paging info shared within the launcher UI. |start_page_contents| is
71 // the contents for the launcher start page. It could be NULL if the start
72 // page is not available.
73 AppsGridView(AppsGridViewDelegate* delegate,
74 PaginationModel* pagination_model,
75 content::WebContents* start_page_contents);
76 virtual ~AppsGridView();
78 // Sets fixed layout parameters. After setting this, CalculateLayout below
79 // is no longer called to dynamically choosing those layout params.
80 void SetLayout(int icon_size, int cols, int rows_per_page);
82 // Sets |model| to use. Note this does not take ownership of |model|.
83 void SetModel(AppListModel* model);
85 // Sets the |item_list| to render. Note this does not take ownership of
86 // |item_list|.
87 void SetItemList(AppListItemList* item_list);
89 void SetSelectedView(views::View* view);
90 void ClearSelectedView(views::View* view);
91 void ClearAnySelectedView();
92 bool IsSelectedView(const views::View* view) const;
94 // Ensures the view is visible. Note that if there is a running page
95 // transition, this does nothing.
96 void EnsureViewVisible(const views::View* view);
98 void InitiateDrag(AppListItemView* view,
99 Pointer pointer,
100 const ui::LocatedEvent& event);
102 // Called from AppListItemView when it receives a drag event.
103 void UpdateDragFromItem(Pointer pointer,
104 const ui::LocatedEvent& event);
106 // Called when the user is dragging an app. |point| is in grid view
107 // coordinates.
108 void UpdateDrag(Pointer pointer, const gfx::Point& point);
109 void EndDrag(bool cancel);
110 bool IsDraggedView(const views::View* view) const;
112 void StartSettingUpSynchronousDrag();
113 bool RunSynchronousDrag();
114 void CleanUpSynchronousDrag();
115 void OnGotShortcutPath(const base::FilePath& path);
117 // Set the drag and drop host for application links.
118 void SetDragAndDropHostOfCurrentAppList(
119 ApplicationDragAndDropHost* drag_and_drop_host);
121 // Prerenders the icons on and around |page_index|.
122 void Prerender(int page_index);
124 bool has_dragged_view() const { return drag_view_ != NULL; }
125 bool dragging() const { return drag_pointer_ != NONE; }
127 // Overridden from views::View:
128 virtual gfx::Size GetPreferredSize() OVERRIDE;
129 virtual void Layout() OVERRIDE;
130 virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
131 virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE;
132 virtual void ViewHierarchyChanged(
133 const ViewHierarchyChangedDetails& details) OVERRIDE;
134 virtual bool GetDropFormats(
135 int* formats,
136 std::set<OSExchangeData::CustomFormat>* custom_formats) OVERRIDE;
137 virtual bool CanDrop(const OSExchangeData& data) OVERRIDE;
138 virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
140 // Stops the timer that triggers a page flip during a drag.
141 void StopPageFlipTimer();
143 // Returns the item view of the item at |index|.
144 AppListItemView* GetItemViewAt(int index) const;
146 // Show or hide the top item views.
147 void SetTopItemViewsVisible(bool visible);
149 // Schedules an animation to show or hide the view.
150 void ScheduleShowHideAnimation(bool show);
152 // Return the view model for test purposes.
153 const views::ViewModel* view_model_for_test() const { return &view_model_; }
155 // For test: Return if the drag and drop handler was set.
156 bool has_drag_and_drop_host_for_test() { return NULL != drag_and_drop_host_; }
158 // For test: Return if the drag and drop operation gets dispatched.
159 bool forward_events_to_drag_and_drop_host_for_test() {
160 return forward_events_to_drag_and_drop_host_;
163 void set_is_root_level(bool value) { is_root_level_ = value; }
165 AppListItemView* activated_item_view() const {
166 return activated_item_view_;
169 private:
170 friend class test::AppsGridViewTestApi;
172 enum DropAttempt {
173 DROP_FOR_NONE,
174 DROP_FOR_REORDER,
175 DROP_FOR_FOLDER,
178 // Represents the index to an item view in the grid.
179 struct Index {
180 Index() : page(-1), slot(-1) {}
181 Index(int page, int slot) : page(page), slot(slot) {}
183 bool operator==(const Index& other) const {
184 return page == other.page && slot == other.slot;
186 bool operator!=(const Index& other) const {
187 return page != other.page || slot != other.slot;
190 int page; // Which page an item view is on.
191 int slot; // Which slot in the page an item view is in.
194 int tiles_per_page() const { return cols_ * rows_per_page_; }
196 // Updates from model.
197 void Update();
199 // Updates page splits for item views.
200 void UpdatePaging();
202 // Updates the number of pulsing block views based on AppListModel status and
203 // number of apps.
204 void UpdatePulsingBlockViews();
206 views::View* CreateViewForItemAtIndex(size_t index);
208 // Convert between the model index and the visual index. The model index
209 // is the index of the item in AppListModel. The visual index is the Index
210 // struct above with page/slot info of where to display the item.
211 Index GetIndexFromModelIndex(int model_index) const;
212 int GetModelIndexFromIndex(const Index& index) const;
214 void SetSelectedItemByIndex(const Index& index);
215 bool IsValidIndex(const Index& index) const;
217 Index GetIndexOfView(const views::View* view) const;
218 views::View* GetViewAtIndex(const Index& index) const;
220 void MoveSelected(int page_delta, int slot_x_delta, int slot_y_delta);
222 void CalculateIdealBounds();
223 void AnimateToIdealBounds();
225 // Invoked when the given |view|'s current bounds and target bounds are on
226 // different rows. To avoid moving diagonally, |view| would be put into a
227 // slot prior |target| and fade in while moving to |target|. In the meanwhile,
228 // a layer copy of |view| would start at |current| and fade out while moving
229 // to succeeding slot of |current|. |animate_current| controls whether to run
230 // fading out animation from |current|. |animate_target| controls whether to
231 // run fading in animation to |target|.
232 void AnimationBetweenRows(views::View* view,
233 bool animate_current,
234 const gfx::Rect& current,
235 bool animate_target,
236 const gfx::Rect& target);
238 // Extracts drag location info from |event| into |drag_point|.
239 void ExtractDragLocation(const ui::LocatedEvent& event,
240 gfx::Point* drag_point);
242 // Calculates |drop_target_| based on |drag_point|. |drag_point| is in the
243 // grid view's coordinates. When |use_page_button_hovering| is true and
244 // |drag_point| is hovering on a page button, use the last slot on that page
245 // as drop target.
246 void CalculateDropTarget(const gfx::Point& drag_point,
247 bool use_page_button_hovering);
249 // Same as CalculateDropTarget, but with folder UI enabled. The |drop_target_|
250 // can be either a target for re-ordering, or a target folder to move the
251 // dragged item into if |drag_view_| enters its re-ordering or folder
252 // dropping circle.
253 void CalculateDropTargetWithFolderEnabled(const gfx::Point& drag_point,
254 bool use_page_button_hovering);
256 // Prepares |drag_and_drop_host_| for dragging. |grid_location| contains
257 // the drag point in this grid view's coordinates.
258 void StartDragAndDropHostDrag(const gfx::Point& grid_location);
260 // Dispatch the drag and drop update event to the dnd host (if needed).
261 void DispatchDragEventToDragAndDropHost(
262 const gfx::Point& location_in_screen_coordinates);
264 // Starts the page flip timer if |drag_point| is in left/right side page flip
265 // zone or is over page switcher.
266 void MaybeStartPageFlipTimer(const gfx::Point& drag_point);
268 // Invoked when |page_flip_timer_| fires.
269 void OnPageFlipTimer();
271 // Updates |model_| to move item represented by |item_view| to |target| slot.
272 void MoveItemInModel(views::View* item_view, const Index& target);
274 // Updates |model_| to move item represented by |item_view| into a folder
275 // containing item located at |target| slot, also update |view_model_| for
276 // the related view changes.
277 void MoveItemToFolder(views::View* item_view, const Index& target);
279 // Cancels any context menus showing for app items on the current page.
280 void CancelContextMenusOnCurrentPage();
282 // Returnes true if |point| lies within the bounds of this grid view plus a
283 // buffer area surrounding it.
284 bool IsPointWithinDragBuffer(const gfx::Point& point) const;
286 // Handles start page layout and transition animation.
287 void LayoutStartPage();
289 // Overridden from views::ButtonListener:
290 virtual void ButtonPressed(views::Button* sender,
291 const ui::Event& event) OVERRIDE;
293 // Overridden from AppListItemListObserver:
294 virtual void OnListItemAdded(size_t index, AppListItem* item) OVERRIDE;
295 virtual void OnListItemRemoved(size_t index, AppListItem* item) OVERRIDE;
296 virtual void OnListItemMoved(size_t from_index,
297 size_t to_index,
298 AppListItem* item) OVERRIDE;
300 // Overridden from PaginationModelObserver:
301 virtual void TotalPagesChanged() OVERRIDE;
302 virtual void SelectedPageChanged(int old_selected, int new_selected) OVERRIDE;
303 virtual void TransitionStarted() OVERRIDE;
304 virtual void TransitionChanged() OVERRIDE;
306 // Overridden from AppListModelObserver:
307 virtual void OnAppListModelStatusChanged() OVERRIDE;
309 // ui::ImplicitAnimationObserver overrides:
310 virtual void OnImplicitAnimationsCompleted() OVERRIDE;
312 // Hide a given view temporarily without losing (mouse) events and / or
313 // changing the size of it. If |immediate| is set the change will be
314 // immediately applied - otherwise it will change gradually.
315 // If |hide| is set the view will get hidden, otherwise it gets shown.
316 void SetViewHidden(views::View* view, bool hide, bool immediate);
318 // Whether the folder drag-and-drop UI should be enabled.
319 bool EnableFolderDragDropUI();
321 // Whether target specified by |drap_target| can accept more items to be
322 // dropped into it.
323 bool CanDropIntoTarget(const Index& drop_target);
325 // Returns the visual index of the nearest tile in which |drag_view_| enters
326 // either its re-ordering or folder dropping circle.
327 Index GetNearestTileForDragView();
329 // Calculates |nearest_tile| in which |vertex| of the |drag_view| is
330 // enclosed.
331 // *|nearest_tile| and *|d_min| will be updated based on the calculation.
332 // *|d_min| is the distance between |nearest_tile| and |drag_view_|.
333 void CalculateNearestTileForVertex(
334 const gfx::Point& vertex, Index* nearest_tile, int* d_min);
336 // Returns the bounds of the tile in which |point| is enclosed if there
337 // is a valid item sits on the tile.
338 gfx::Rect GetTileBoundsForPoint(const gfx::Point& point, Index* tile_index);
340 // Gets the bounds of the tile located at |row| and |col| on current page.
341 gfx::Rect GetTileBounds(int row, int col) const;
343 // Gets the item view located at |slot| on the current page. If there is
344 // no item located at |slot|, returns NULL.
345 views::View* GetViewAtSlotOnCurrentPage(int slot);
347 // Sets state of the view with |target_index| to |is_target_folder| for
348 // dropping |drag_view_|.
349 void SetAsFolderDroppingTarget(const Index& target_index,
350 bool is_target_folder);
352 // Invoked when |reorder_timer_| fires to show re-order preview UI.
353 void OnReorderTimer();
355 // Invoked when |folder_dropping_timer_| fires to show folder dropping
356 // preview UI.
357 void OnFolderDroppingTimer();
359 AppListModel* model_; // Owned by AppListView.
360 AppListItemList* item_list_; // Not owned.
361 AppsGridViewDelegate* delegate_;
362 PaginationModel* pagination_model_; // Owned by AppListController.
363 PageSwitcher* page_switcher_view_; // Owned by views hierarchy.
364 views::WebView* start_page_view_; // Owned by views hierarchy.
366 gfx::Size icon_size_;
367 int cols_;
368 int rows_per_page_;
370 // Tracks app item views. There is a view per item in |model_|.
371 views::ViewModel view_model_;
373 // Tracks pulsing block views.
374 views::ViewModel pulsing_blocks_model_;
376 views::View* selected_view_;
378 AppListItemView* drag_view_;
380 // The point where the drag started in AppListItemView coordinates.
381 gfx::Point drag_view_offset_;
383 // The point where the drag started in GridView coordinates.
384 gfx::Point drag_start_grid_view_;
386 // The location of |drag_view_| when the drag started.
387 gfx::Point drag_view_start_;
389 // Page the drag started on.
390 int drag_start_page_;
392 #if defined(OS_WIN)
393 // Created when a drag is started (ie: drag exceeds the drag threshold), but
394 // not Run() until supplied with a shortcut path.
395 scoped_refptr<SynchronousDrag> synchronous_drag_;
396 #endif
398 Pointer drag_pointer_;
399 Index drop_target_;
400 DropAttempt drop_attempt_;
402 // Timer for re-ordering the |drop_target_| and |drag_view_|.
403 base::OneShotTimer<AppsGridView> reorder_timer_;
405 // Timer for dropping |drag_view_| into the folder containing
406 // the |drop_target_|.
407 base::OneShotTimer<AppsGridView> folder_dropping_timer_;
409 // An application target drag and drop host which accepts dnd operations.
410 ApplicationDragAndDropHost* drag_and_drop_host_;
412 // The drag operation is currently inside the dnd host and events get
413 // forwarded.
414 bool forward_events_to_drag_and_drop_host_;
416 // Last mouse drag location in this view's coordinates.
417 gfx::Point last_drag_point_;
419 // Timer to auto flip page when dragging an item near the left/right edges.
420 base::OneShotTimer<AppsGridView> page_flip_timer_;
422 // Target page to switch to when |page_flip_timer_| fires.
423 int page_flip_target_;
425 // Delay in milliseconds of when |page_flip_timer_| should fire after user
426 // drags an item near the edges.
427 int page_flip_delay_in_ms_;
429 views::BoundsAnimator bounds_animator_;
431 // If true, AppsGridView is rending items at the root level of the app list.
432 bool is_root_level_;
434 // The most recent activated item view.
435 AppListItemView* activated_item_view_;
437 DISALLOW_COPY_AND_ASSIGN(AppsGridView);
440 } // namespace app_list
442 #endif // UI_APP_LIST_VIEWS_APPS_GRID_VIEW_H_