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 25 namespace views { 26 class ButtonListener; 27 class DragImageView; 28 } 29 30 namespace app_list { 31 32 #if defined(OS_WIN) && !defined(USE_AURA) 33 class SynchronousDrag; 34 #endif 35 36 namespace test { 37 class AppsGridViewTestApi; 38 } 39 40 class ApplicationDragAndDropHost; 41 class AppListItemView; 42 class AppsGridViewDelegate; 43 class PageSwitcher; 44 class PaginationModel; 45 46 // AppsGridView displays a grid for AppListModel::Apps sub model. 47 class 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 // Returnes true if |point| lies within the bounds of this grid view plus a 226 // buffer area surrounding it. 227 bool IsPointWithinDragBuffer(const gfx::Point& point) const; 228 229 // Overridden from views::ButtonListener: 230 virtual void ButtonPressed(views::Button* sender, 231 const ui::Event& event) OVERRIDE; 232 233 // Overridden from ListModelObserver: 234 virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE; 235 virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE; 236 virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE; 237 virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE; 238 239 // Overridden from PaginationModelObserver: 240 virtual void TotalPagesChanged() OVERRIDE; 241 virtual void SelectedPageChanged(int old_selected, int new_selected) OVERRIDE; 242 virtual void TransitionStarted() OVERRIDE; 243 virtual void TransitionChanged() OVERRIDE; 244 245 // Overridden from AppListModelObserver: 246 virtual void OnAppListModelStatusChanged() OVERRIDE; 247 248 // Hide a given view temporarily without losing (mouse) events and / or 249 // changing the size of it. 250 void HideView(views::View* view, bool hide); 251 252 AppListModel* model_; // Owned by AppListView. 253 AppsGridViewDelegate* delegate_; 254 PaginationModel* pagination_model_; // Owned by AppListController. 255 PageSwitcher* page_switcher_view_; // Owned by views hierarchy. 256 257 gfx::Size icon_size_; 258 int cols_; 259 int rows_per_page_; 260 261 // Tracks app item views. There is a view per item in |model_|. 262 views::ViewModel view_model_; 263 264 // Tracks pulsing block views. 265 views::ViewModel pulsing_blocks_model_; 266 267 views::View* selected_view_; 268 269 AppListItemView* drag_view_; 270 271 // The point where the drag started in AppListItemView coordinates. 272 gfx::Point drag_view_offset_; 273 274 // The point where the drag started in GridView coordinates. 275 gfx::Point drag_start_grid_view_; 276 277 // The location of |drag_view_| when the drag started. 278 gfx::Point drag_view_start_; 279 280 // Page the drag started on. 281 int drag_start_page_; 282 283 #if defined(OS_WIN) && !defined(USE_AURA) 284 // Created when a drag is started (ie: drag exceeds the drag threshold), but 285 // not Run() until supplied with a shortcut path. 286 scoped_refptr<SynchronousDrag> synchronous_drag_; 287 #endif 288 289 Pointer drag_pointer_; 290 Index drop_target_; 291 292 // An application target drag and drop host which accepts dnd operations. 293 ApplicationDragAndDropHost* drag_and_drop_host_; 294 295 // The drag operation is currently inside the dnd host and events get 296 // forwarded. 297 bool forward_events_to_drag_and_drop_host_; 298 299 // Last mouse drag location in this view's coordinates. 300 gfx::Point last_drag_point_; 301 302 // Timer to auto flip page when dragging an item near the left/right edges. 303 base::OneShotTimer<AppsGridView> page_flip_timer_; 304 305 // Target page to switch to when |page_flip_timer_| fires. 306 int page_flip_target_; 307 308 // Delay in milliseconds of when |page_flip_timer_| should fire after user 309 // drags an item near the edges. 310 int page_flip_delay_in_ms_; 311 312 views::BoundsAnimator bounds_animator_; 313 314 DISALLOW_COPY_AND_ASSIGN(AppsGridView); 315 }; 316 317 } // namespace app_list 318 319 #endif // UI_APP_LIST_VIEWS_APPS_GRID_VIEW_H_ 320