Home | History | Annotate | Download | only in views
      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