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 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" 22 23 #if defined(OS_WIN) 24 #include "ui/base/dragdrop/drag_source_win.h" 25 #endif 26 27 namespace content { 28 class WebContents; 29 } 30 31 namespace views { 32 class ButtonListener; 33 class DragImageView; 34 class WebView; 35 } 36 37 namespace app_list { 38 39 #if defined(OS_WIN) 40 class SynchronousDrag; 41 #endif 42 43 namespace test { 44 class AppsGridViewTestApi; 45 } 46 47 class ApplicationDragAndDropHost; 48 class AppListItemView; 49 class AppsGridViewDelegate; 50 class PageSwitcher; 51 class PaginationModel; 52 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 { 59 public: 60 enum Pointer { 61 NONE, 62 MOUSE, 63 TOUCH, 64 }; 65 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(); 75 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); 79 80 // Sets |model| to use. Note this does not take ownership of |model|. 81 void SetModel(AppListModel* model); 82 83 // Sets the |item_list| to render. Note this does not take ownership of 84 // |item_list|. 85 void SetItemList(AppListItemList* item_list); 86 87 void SetSelectedView(views::View* view); 88 void ClearSelectedView(views::View* view); 89 void ClearAnySelectedView(); 90 bool IsSelectedView(const views::View* view) const; 91 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); 95 96 void InitiateDrag(AppListItemView* view, 97 Pointer pointer, 98 const ui::LocatedEvent& event); 99 100 // Called from AppListItemView when it receives a drag event. 101 void UpdateDragFromItem(Pointer pointer, 102 const ui::LocatedEvent& event); 103 104 // Called when the user is dragging an app. |point| is in grid view 105 // coordinates. 106 void UpdateDrag(Pointer pointer, const gfx::Point& point); 107 void EndDrag(bool cancel); 108 bool IsDraggedView(const views::View* view) const; 109 110 void StartSettingUpSynchronousDrag(); 111 bool RunSynchronousDrag(); 112 void CleanUpSynchronousDrag(); 113 void OnGotShortcutPath(const base::FilePath& path); 114 115 // Set the drag and drop host for application links. 116 void SetDragAndDropHostOfCurrentAppList( 117 ApplicationDragAndDropHost* drag_and_drop_host); 118 119 // Prerenders the icons on and around |page_index|. 120 void Prerender(int page_index); 121 122 bool has_dragged_view() const { return drag_view_ != NULL; } 123 bool dragging() const { return drag_pointer_ != NONE; } 124 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( 133 int* formats, 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; 137 138 // Stops the timer that triggers a page flip during a drag. 139 void StopPageFlipTimer(); 140 141 // Return the view model for test purposes. 142 const views::ViewModel* view_model_for_test() const { return &view_model_; } 143 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_; } 146 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_; 150 } 151 152 void set_is_root_level(bool value) { is_root_level_ = value; } 153 154 private: 155 friend class test::AppsGridViewTestApi; 156 157 enum DropAttempt { 158 DROP_FOR_NONE, 159 DROP_FOR_REORDER, 160 DROP_FOR_FOLDER, 161 }; 162 163 // Represents the index to an item view in the grid. 164 struct Index { 165 Index() : page(-1), slot(-1) {} 166 Index(int page, int slot) : page(page), slot(slot) {} 167 168 bool operator==(const Index& other) const { 169 return page == other.page && slot == other.slot; 170 } 171 bool operator!=(const Index& other) const { 172 return page != other.page || slot != other.slot; 173 } 174 175 int page; // Which page an item view is on. 176 int slot; // Which slot in the page an item view is in. 177 }; 178 179 int tiles_per_page() const { return cols_ * rows_per_page_; } 180 181 // Updates from model. 182 void Update(); 183 184 // Updates page splits for item views. 185 void UpdatePaging(); 186 187 // Updates the number of pulsing block views based on AppListModel status and 188 // number of apps. 189 void UpdatePulsingBlockViews(); 190 191 views::View* CreateViewForItemAtIndex(size_t index); 192 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; 198 199 void SetSelectedItemByIndex(const Index& index); 200 bool IsValidIndex(const Index& index) const; 201 202 Index GetIndexOfView(const views::View* view) const; 203 views::View* GetViewAtIndex(const Index& index) const; 204 205 void MoveSelected(int page_delta, int slot_x_delta, int slot_y_delta); 206 207 void CalculateIdealBounds(); 208 void AnimateToIdealBounds(); 209 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, 220 bool animate_target, 221 const gfx::Rect& target); 222 223 // Extracts drag location info from |event| into |drag_point|. 224 void ExtractDragLocation(const ui::LocatedEvent& event, 225 gfx::Point* drag_point); 226 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 230 // as drop target. 231 void CalculateDropTarget(const gfx::Point& drag_point, 232 bool use_page_button_hovering); 233 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 237 // dropping circle. 238 void CalculateDropTargetWithFolderEnabled(const gfx::Point& drag_point, 239 bool use_page_button_hovering); 240 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); 244 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); 248 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); 252 253 // Invoked when |page_flip_timer_| fires. 254 void OnPageFlipTimer(); 255 256 // Updates |model_| to move item represented by |item_view| to |target| slot. 257 void MoveItemInModel(views::View* item_view, const Index& target); 258 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); 263 264 // Cancels any context menus showing for app items on the current page. 265 void CancelContextMenusOnCurrentPage(); 266 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; 270 271 // Handles start page layout and transition animation. 272 void LayoutStartPage(); 273 274 // Overridden from views::ButtonListener: 275 virtual void ButtonPressed(views::Button* sender, 276 const ui::Event& event) OVERRIDE; 277 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, 282 size_t to_index, 283 AppListItemModel* item) OVERRIDE; 284 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; 290 291 // Overridden from AppListModelObserver: 292 virtual void OnAppListModelStatusChanged() OVERRIDE; 293 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); 299 300 // Whether the folder drag-and-drop UI should be enabled. 301 bool EnableFolderDragDropUI(); 302 303 // Whether target specified by |drap_target| can accept more items to be 304 // dropped into it. 305 bool CanDropIntoTarget(const Index& drop_target); 306 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(); 310 311 // Calculates |nearest_tile| in which |vertex| of the |drag_view| is 312 // enclosed. 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); 317 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); 321 322 // Gets the bounds of the tile located at |row| and |col| on current page. 323 gfx::Rect GetTileBounds(int row, int col) const; 324 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); 328 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); 333 334 // Invoked when |reorder_timer_| fires to show re-order preview UI. 335 void OnReorderTimer(); 336 337 // Invoked when |folder_dropping_timer_| fires to show folder dropping 338 // preview UI. 339 void OnFolderDroppingTimer(); 340 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. 347 348 gfx::Size icon_size_; 349 int cols_; 350 int rows_per_page_; 351 352 // Tracks app item views. There is a view per item in |model_|. 353 views::ViewModel view_model_; 354 355 // Tracks pulsing block views. 356 views::ViewModel pulsing_blocks_model_; 357 358 views::View* selected_view_; 359 360 AppListItemView* drag_view_; 361 362 // The point where the drag started in AppListItemView coordinates. 363 gfx::Point drag_view_offset_; 364 365 // The point where the drag started in GridView coordinates. 366 gfx::Point drag_start_grid_view_; 367 368 // The location of |drag_view_| when the drag started. 369 gfx::Point drag_view_start_; 370 371 // Page the drag started on. 372 int drag_start_page_; 373 374 #if defined(OS_WIN) 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_; 378 #endif 379 380 Pointer drag_pointer_; 381 Index drop_target_; 382 DropAttempt drop_attempt_; 383 384 // Timer for re-ordering the |drop_target_| and |drag_view_|. 385 base::OneShotTimer<AppsGridView> reorder_timer_; 386 387 // Timer for dropping |drag_view_| into the folder containing 388 // the |drop_target_|. 389 base::OneShotTimer<AppsGridView> folder_dropping_timer_; 390 391 // An application target drag and drop host which accepts dnd operations. 392 ApplicationDragAndDropHost* drag_and_drop_host_; 393 394 // The drag operation is currently inside the dnd host and events get 395 // forwarded. 396 bool forward_events_to_drag_and_drop_host_; 397 398 // Last mouse drag location in this view's coordinates. 399 gfx::Point last_drag_point_; 400 401 // Timer to auto flip page when dragging an item near the left/right edges. 402 base::OneShotTimer<AppsGridView> page_flip_timer_; 403 404 // Target page to switch to when |page_flip_timer_| fires. 405 int page_flip_target_; 406 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_; 410 411 views::BoundsAnimator bounds_animator_; 412 413 // If true, AppsGridView is rending items at the root level of the app list. 414 bool is_root_level_; 415 416 DISALLOW_COPY_AND_ASSIGN(AppsGridView); 417 }; 418 419 } // namespace app_list 420 421 #endif // UI_APP_LIST_VIEWS_APPS_GRID_VIEW_H_ 422