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_
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/views/animation/bounds_animator.h"
19 #include "ui/views/controls/button/button.h"
20 #include "ui/views/view.h"
21 #include "ui/views/view_model.h"
23 #if defined(OS_WIN) && !defined(USE_AURA)
24 #include "ui/base/dragdrop/drag_source_win.h"
39 #if defined(OS_WIN) && !defined(USE_AURA)
40 class SynchronousDrag
;
44 class AppsGridViewTestApi
;
47 class ApplicationDragAndDropHost
;
48 class AppListItemView
;
49 class AppsGridViewDelegate
;
51 class PaginationModel
;
53 // AppsGridView displays a grid for AppListItemList sub model.
54 class APP_LIST_EXPORT AppsGridView
: public views::View
,
55 public views::ButtonListener
,
56 public AppListItemListObserver
,
57 public PaginationModelObserver
,
58 public AppListModelObserver
{
66 // Constructs the app icon grid view. |delegate| is the delegate of this
67 // view, which usually is the hosting AppListView. |pagination_model| is
68 // the paging info shared within the launcher UI. |start_page_contents| is
69 // the contents for the launcher start page. It could be NULL if the start
70 // page is not available.
71 AppsGridView(AppsGridViewDelegate
* delegate
,
72 PaginationModel
* pagination_model
,
73 content::WebContents
* start_page_contents
);
74 virtual ~AppsGridView();
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 icon_size
, int cols
, int rows_per_page
);
80 // Sets |model| to use. Note this does not take ownership of |model|.
81 void SetModel(AppListModel
* model
);
83 // Sets the |item_list| to render. Note this does not take ownership of
85 void SetItemList(AppListItemList
* item_list
);
87 void SetSelectedView(views::View
* view
);
88 void ClearSelectedView(views::View
* view
);
89 void ClearAnySelectedView();
90 bool IsSelectedView(const views::View
* view
) const;
92 // Ensures the view is visible. Note that if there is a running page
93 // transition, this does nothing.
94 void EnsureViewVisible(const views::View
* view
);
96 void InitiateDrag(AppListItemView
* view
,
98 const ui::LocatedEvent
& event
);
100 // Called from AppListItemView when it receives a drag event.
101 void UpdateDragFromItem(Pointer pointer
,
102 const ui::LocatedEvent
& event
);
104 // Called when the user is dragging an app. |point| is in grid view
106 void UpdateDrag(Pointer pointer
, const gfx::Point
& point
);
107 void EndDrag(bool cancel
);
108 bool IsDraggedView(const views::View
* view
) const;
110 void StartSettingUpSynchronousDrag();
111 bool RunSynchronousDrag();
112 void CleanUpSynchronousDrag();
113 void OnGotShortcutPath(const base::FilePath
& path
);
115 // Set the drag and drop host for application links.
116 void SetDragAndDropHostOfCurrentAppList(
117 ApplicationDragAndDropHost
* drag_and_drop_host
);
119 // Prerenders the icons on and around |page_index|.
120 void Prerender(int page_index
);
122 bool has_dragged_view() const { return drag_view_
!= NULL
; }
123 bool dragging() const { return drag_pointer_
!= NONE
; }
125 // Overridden from views::View:
126 virtual gfx::Size
GetPreferredSize() OVERRIDE
;
127 virtual void Layout() OVERRIDE
;
128 virtual bool OnKeyPressed(const ui::KeyEvent
& event
) OVERRIDE
;
129 virtual bool OnKeyReleased(const ui::KeyEvent
& event
) OVERRIDE
;
130 virtual void ViewHierarchyChanged(
131 const ViewHierarchyChangedDetails
& details
) OVERRIDE
;
132 virtual bool GetDropFormats(
134 std::set
<OSExchangeData::CustomFormat
>* custom_formats
) OVERRIDE
;
135 virtual bool CanDrop(const OSExchangeData
& data
) OVERRIDE
;
136 virtual int OnDragUpdated(const ui::DropTargetEvent
& event
) OVERRIDE
;
138 // Stops the timer that triggers a page flip during a drag.
139 void StopPageFlipTimer();
141 // Return the view model for test purposes.
142 const views::ViewModel
* view_model_for_test() const { return &view_model_
; }
144 // For test: Return if the drag and drop handler was set.
145 bool has_drag_and_drop_host_for_test() { return NULL
!= drag_and_drop_host_
; }
147 // For test: Return if the drag and drop operation gets dispatched.
148 bool forward_events_to_drag_and_drop_host_for_test() {
149 return forward_events_to_drag_and_drop_host_
;
152 void set_is_root_level(bool value
) { is_root_level_
= value
; }
155 friend class test::AppsGridViewTestApi
;
163 // Represents the index to an item view in the grid.
165 Index() : page(-1), slot(-1) {}
166 Index(int page
, int slot
) : page(page
), slot(slot
) {}
168 bool operator==(const Index
& other
) const {
169 return page
== other
.page
&& slot
== other
.slot
;
171 bool operator!=(const Index
& other
) const {
172 return page
!= other
.page
|| slot
!= other
.slot
;
175 int page
; // Which page an item view is on.
176 int slot
; // Which slot in the page an item view is in.
179 int tiles_per_page() const { return cols_
* rows_per_page_
; }
181 // Updates from model.
184 // Updates page splits for item views.
187 // Updates the number of pulsing block views based on AppListModel status and
189 void UpdatePulsingBlockViews();
191 views::View
* CreateViewForItemAtIndex(size_t index
);
193 // Convert between the model index and the visual index. The model index
194 // is the index of the item in AppListModel. The visual index is the Index
195 // struct above with page/slot info of where to display the item.
196 Index
GetIndexFromModelIndex(int model_index
) const;
197 int GetModelIndexFromIndex(const Index
& index
) const;
199 void SetSelectedItemByIndex(const Index
& index
);
200 bool IsValidIndex(const Index
& index
) const;
202 Index
GetIndexOfView(const views::View
* view
) const;
203 views::View
* GetViewAtIndex(const Index
& index
) const;
205 void MoveSelected(int page_delta
, int slot_x_delta
, int slot_y_delta
);
207 void CalculateIdealBounds();
208 void AnimateToIdealBounds();
210 // Invoked when the given |view|'s current bounds and target bounds are on
211 // different rows. To avoid moving diagonally, |view| would be put into a
212 // slot prior |target| and fade in while moving to |target|. In the meanwhile,
213 // a layer copy of |view| would start at |current| and fade out while moving
214 // to succeeding slot of |current|. |animate_current| controls whether to run
215 // fading out animation from |current|. |animate_target| controls whether to
216 // run fading in animation to |target|.
217 void AnimationBetweenRows(views::View
* view
,
218 bool animate_current
,
219 const gfx::Rect
& current
,
221 const gfx::Rect
& target
);
223 // Extracts drag location info from |event| into |drag_point|.
224 void ExtractDragLocation(const ui::LocatedEvent
& event
,
225 gfx::Point
* drag_point
);
227 // Calculates |drop_target_| based on |drag_point|. |drag_point| is in the
228 // grid view's coordinates. When |use_page_button_hovering| is true and
229 // |drag_point| is hovering on a page button, use the last slot on that page
231 void CalculateDropTarget(const gfx::Point
& drag_point
,
232 bool use_page_button_hovering
);
234 // Same as CalculateDropTarget, but with folder UI enabled. The |drop_target_|
235 // can be either a target for re-ordering, or a target folder to move the
236 // dragged item into if |drag_view_| enters its re-ordering or folder
238 void CalculateDropTargetWithFolderEnabled(const gfx::Point
& drag_point
,
239 bool use_page_button_hovering
);
241 // Prepares |drag_and_drop_host_| for dragging. |grid_location| contains
242 // the drag point in this grid view's coordinates.
243 void StartDragAndDropHostDrag(const gfx::Point
& grid_location
);
245 // Dispatch the drag and drop update event to the dnd host (if needed).
246 void DispatchDragEventToDragAndDropHost(
247 const gfx::Point
& location_in_screen_coordinates
);
249 // Starts the page flip timer if |drag_point| is in left/right side page flip
250 // zone or is over page switcher.
251 void MaybeStartPageFlipTimer(const gfx::Point
& drag_point
);
253 // Invoked when |page_flip_timer_| fires.
254 void OnPageFlipTimer();
256 // Updates |model_| to move item represented by |item_view| to |target| slot.
257 void MoveItemInModel(views::View
* item_view
, const Index
& target
);
259 // Updates |model_| to move item represented by |item_view| into a folder
260 // containing item located at |target| slot, also update |view_model_| for
261 // the related view changes.
262 void MoveItemToFolder(views::View
* item_view
, const Index
& target
);
264 // Cancels any context menus showing for app items on the current page.
265 void CancelContextMenusOnCurrentPage();
267 // Returnes true if |point| lies within the bounds of this grid view plus a
268 // buffer area surrounding it.
269 bool IsPointWithinDragBuffer(const gfx::Point
& point
) const;
271 // Handles start page layout and transition animation.
272 void LayoutStartPage();
274 // Overridden from views::ButtonListener:
275 virtual void ButtonPressed(views::Button
* sender
,
276 const ui::Event
& event
) OVERRIDE
;
278 // Overridden from AppListItemListObserver:
279 virtual void OnListItemAdded(size_t index
, AppListItemModel
* item
) OVERRIDE
;
280 virtual void OnListItemRemoved(size_t index
, AppListItemModel
* item
) OVERRIDE
;
281 virtual void OnListItemMoved(size_t from_index
,
283 AppListItemModel
* item
) OVERRIDE
;
285 // Overridden from PaginationModelObserver:
286 virtual void TotalPagesChanged() OVERRIDE
;
287 virtual void SelectedPageChanged(int old_selected
, int new_selected
) OVERRIDE
;
288 virtual void TransitionStarted() OVERRIDE
;
289 virtual void TransitionChanged() OVERRIDE
;
291 // Overridden from AppListModelObserver:
292 virtual void OnAppListModelStatusChanged() OVERRIDE
;
294 // Hide a given view temporarily without losing (mouse) events and / or
295 // changing the size of it. If |immediate| is set the change will be
296 // immediately applied - otherwise it will change gradually.
297 // If |hide| is set the view will get hidden, otherwise it gets shown.
298 void SetViewHidden(views::View
* view
, bool hide
, bool immediate
);
300 // Whether the folder drag-and-drop UI should be enabled.
301 bool EnableFolderDragDropUI();
303 // Whether target specified by |drap_target| can accept more items to be
305 bool CanDropIntoTarget(const Index
& drop_target
);
307 // Returns the visual index of the nearest tile in which |drag_view_| enters
308 // either its re-ordering or folder dropping circle.
309 Index
GetNearestTileForDragView();
311 // Calculates |nearest_tile| in which |vertex| of the |drag_view| is
313 // *|nearest_tile| and *|d_min| will be updated based on the calculation.
314 // *|d_min| is the distance between |nearest_tile| and |drag_view_|.
315 void CalculateNearestTileForVertex(
316 const gfx::Point
& vertex
, Index
* nearest_tile
, int* d_min
);
318 // Returns the bounds of the tile in which |point| is enclosed if there
319 // is a valid item sits on the tile.
320 gfx::Rect
GetTileBoundsForPoint(const gfx::Point
& point
, Index
* tile_index
);
322 // Gets the bounds of the tile located at |row| and |col| on current page.
323 gfx::Rect
GetTileBounds(int row
, int col
) const;
325 // Gets the item view located at |slot| on the current page. If there is
326 // no item located at |slot|, returns NULL.
327 views::View
* GetViewAtSlotOnCurrentPage(int slot
);
329 // Sets state of the view with |target_index| to |is_target_folder| for
330 // dropping |drag_view_|.
331 void SetAsFolderDroppingTarget(const Index
& target_index
,
332 bool is_target_folder
);
334 // Invoked when |reorder_timer_| fires to show re-order preview UI.
335 void OnReorderTimer();
337 // Invoked when |folder_dropping_timer_| fires to show folder dropping
339 void OnFolderDroppingTimer();
341 AppListModel
* model_
; // Owned by AppListView.
342 AppListItemList
* item_list_
; // Not owned.
343 AppsGridViewDelegate
* delegate_
;
344 PaginationModel
* pagination_model_
; // Owned by AppListController.
345 PageSwitcher
* page_switcher_view_
; // Owned by views hierarchy.
346 views::WebView
* start_page_view_
; // Owned by views hierarchy.
348 gfx::Size icon_size_
;
352 // Tracks app item views. There is a view per item in |model_|.
353 views::ViewModel view_model_
;
355 // Tracks pulsing block views.
356 views::ViewModel pulsing_blocks_model_
;
358 views::View
* selected_view_
;
360 AppListItemView
* drag_view_
;
362 // The point where the drag started in AppListItemView coordinates.
363 gfx::Point drag_view_offset_
;
365 // The point where the drag started in GridView coordinates.
366 gfx::Point drag_start_grid_view_
;
368 // The location of |drag_view_| when the drag started.
369 gfx::Point drag_view_start_
;
371 // Page the drag started on.
372 int drag_start_page_
;
374 #if defined(OS_WIN) && !defined(USE_AURA)
375 // Created when a drag is started (ie: drag exceeds the drag threshold), but
376 // not Run() until supplied with a shortcut path.
377 scoped_refptr
<SynchronousDrag
> synchronous_drag_
;
380 Pointer drag_pointer_
;
382 DropAttempt drop_attempt_
;
384 // Timer for re-ordering the |drop_target_| and |drag_view_|.
385 base::OneShotTimer
<AppsGridView
> reorder_timer_
;
387 // Timer for dropping |drag_view_| into the folder containing
388 // the |drop_target_|.
389 base::OneShotTimer
<AppsGridView
> folder_dropping_timer_
;
391 // An application target drag and drop host which accepts dnd operations.
392 ApplicationDragAndDropHost
* drag_and_drop_host_
;
394 // The drag operation is currently inside the dnd host and events get
396 bool forward_events_to_drag_and_drop_host_
;
398 // Last mouse drag location in this view's coordinates.
399 gfx::Point last_drag_point_
;
401 // Timer to auto flip page when dragging an item near the left/right edges.
402 base::OneShotTimer
<AppsGridView
> page_flip_timer_
;
404 // Target page to switch to when |page_flip_timer_| fires.
405 int page_flip_target_
;
407 // Delay in milliseconds of when |page_flip_timer_| should fire after user
408 // drags an item near the edges.
409 int page_flip_delay_in_ms_
;
411 views::BoundsAnimator bounds_animator_
;
413 // If true, AppsGridView is rending items at the root level of the app list.
416 DISALLOW_COPY_AND_ASSIGN(AppsGridView
);
419 } // namespace app_list
421 #endif // UI_APP_LIST_VIEWS_APPS_GRID_VIEW_H_