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 ASH_SHELF_SHELF_VIEW_H_
6#define ASH_SHELF_SHELF_VIEW_H_
7
8#include <utility>
9#include <vector>
10
11#include "ash/shelf/shelf_button_host.h"
12#include "ash/shelf/shelf_model_observer.h"
13#include "ash/wm/gestures/shelf_gesture_handler.h"
14#include "base/observer_list.h"
15#include "ui/app_list/views/app_list_drag_and_drop_host.h"
16#include "ui/views/animation/bounds_animator_observer.h"
17#include "ui/views/context_menu_controller.h"
18#include "ui/views/controls/button/button.h"
19#include "ui/views/focus/focus_manager.h"
20#include "ui/views/view.h"
21
22namespace ui {
23class MenuModel;
24}
25
26namespace views {
27class BoundsAnimator;
28class MenuRunner;
29class ViewModel;
30}
31
32namespace ash {
33class ShelfDelegate;
34class ShelfIconObserver;
35class ShelfItemDelegateManager;
36class ShelfModel;
37struct ShelfItem;
38class DragImageView;
39class OverflowBubble;
40class OverflowButton;
41class ShelfButton;
42class ShelfLayoutManager;
43class ShelfTooltipManager;
44
45namespace test {
46class ShelfViewTestAPI;
47}
48
49extern const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM;
50extern const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT;
51extern const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT;
52extern const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT;
53
54class ASH_EXPORT ShelfView : public views::View,
55                             public ShelfModelObserver,
56                             public views::ButtonListener,
57                             public ShelfButtonHost,
58                             public views::ContextMenuController,
59                             public views::FocusTraversable,
60                             public views::BoundsAnimatorObserver,
61                             public app_list::ApplicationDragAndDropHost {
62 public:
63  ShelfView(ShelfModel* model,
64            ShelfDelegate* delegate,
65            ShelfLayoutManager* manager);
66  virtual ~ShelfView();
67
68  ShelfTooltipManager* tooltip_manager() { return tooltip_.get(); }
69
70  ShelfLayoutManager* shelf_layout_manager() { return layout_manager_; }
71
72  ShelfModel* model() { return model_; }
73
74  void Init();
75
76  void OnShelfAlignmentChanged();
77  void SchedulePaintForAllButtons();
78
79  // Returns the ideal bounds of the specified item, or an empty rect if id
80  // isn't know. If the item is in an overflow shelf, the overflow icon location
81  // will be returned.
82  gfx::Rect GetIdealBoundsOfItemIcon(ShelfID id);
83
84  // Repositions the icon for the specified item by the midpoint of the window.
85  void UpdatePanelIconPosition(ShelfID id, const gfx::Point& midpoint);
86
87  void AddIconObserver(ShelfIconObserver* observer);
88  void RemoveIconObserver(ShelfIconObserver* observer);
89
90  // Returns true if we're showing a menu.
91  bool IsShowingMenu() const;
92
93  // Returns true if overflow bubble is shown.
94  bool IsShowingOverflowBubble() const;
95
96  // Sets owner overflow bubble instance from which this shelf view pops
97  // out as overflow.
98  void set_owner_overflow_bubble(OverflowBubble* owner) {
99    owner_overflow_bubble_ = owner;
100  }
101
102  views::View* GetAppListButtonView() const;
103
104  // Returns true if the mouse cursor exits the area for launcher tooltip.
105  // There are thin gaps between launcher buttons but the tooltip shouldn't hide
106  // in the gaps, but the tooltip should hide if the mouse moved totally outside
107  // of the buttons area.
108  bool ShouldHideTooltip(const gfx::Point& cursor_location);
109
110  // Returns rectangle bounding all visible launcher items. Used screen
111  // coordinate system.
112  gfx::Rect GetVisibleItemsBoundsInScreen();
113
114  // Overridden from FocusTraversable:
115  virtual views::FocusSearch* GetFocusSearch() OVERRIDE;
116  virtual FocusTraversable* GetFocusTraversableParent() OVERRIDE;
117  virtual View* GetFocusTraversableParentView() OVERRIDE;
118
119  // Overridden from app_list::ApplicationDragAndDropHost:
120  virtual void CreateDragIconProxy(
121      const gfx::Point& location_in_screen_coordinates,
122      const gfx::ImageSkia& icon,
123      views::View* replaced_view,
124      const gfx::Vector2d& cursor_offset_from_center,
125      float scale_factor) OVERRIDE;
126  virtual void UpdateDragIconProxy(
127      const gfx::Point& location_in_screen_coordinates) OVERRIDE;
128  virtual void DestroyDragIconProxy() OVERRIDE;
129  virtual bool StartDrag(
130      const std::string& app_id,
131      const gfx::Point& location_in_screen_coordinates) OVERRIDE;
132  virtual bool Drag(const gfx::Point& location_in_screen_coordinates) OVERRIDE;
133  virtual void EndDrag(bool cancel) OVERRIDE;
134
135  // Return the view model for test purposes.
136  const views::ViewModel* view_model_for_test() const {
137    return view_model_.get();
138  }
139
140 private:
141  friend class ash::test::ShelfViewTestAPI;
142
143  class FadeOutAnimationDelegate;
144  class StartFadeAnimationDelegate;
145
146  struct IdealBounds {
147    gfx::Rect overflow_bounds;
148  };
149
150  enum RemovableState {
151    REMOVABLE,     // Item can be removed when dragged away.
152    DRAGGABLE,     // Item can be dragged, but will snap always back to origin.
153    NOT_REMOVABLE, // Item is fixed and can never be removed.
154  };
155
156  // Returns true when this ShelfView is used for Overflow Bubble.
157  // In this mode, it does not show app list, panel and overflow button.
158  // Note:
159  //   * When Shelf can contain only one item (overflow button) due to very
160  //     small resolution screen, overflow bubble can show app list and panel
161  //     button.
162  bool is_overflow_mode() const { return overflow_mode_; }
163
164  bool dragging() const {
165    return drag_pointer_ != NONE;
166  }
167
168  // Sets the bounds of each view to its ideal bounds.
169  void LayoutToIdealBounds();
170
171  // Update all button's visibility in overflow.
172  void UpdateAllButtonsVisibilityInOverflowMode();
173
174  // Calculates the ideal bounds. The bounds of each button corresponding to an
175  // item in the model is set in |view_model_|.
176  void CalculateIdealBounds(IdealBounds* bounds) const;
177
178  // Returns the index of the last view whose max primary axis coordinate is
179  // less than |max_value|. Returns -1 if nothing fits, or there are no views.
180  int DetermineLastVisibleIndex(int max_value) const;
181
182  // Returns the index of the first panel whose min primary axis coordinate is
183  // at least |min_value|. Returns the index past the last panel if none fit.
184  int DetermineFirstVisiblePanelIndex(int min_value) const;
185
186  // Animates the bounds of each view to its ideal bounds.
187  void AnimateToIdealBounds();
188
189  // Creates the view used to represent |item|.
190  views::View* CreateViewForItem(const ShelfItem& item);
191
192  // Fades |view| from an opacity of 0 to 1. This is when adding a new item.
193  void FadeIn(views::View* view);
194
195  // Invoked when the pointer has moved enough to trigger a drag. Sets
196  // internal state in preparation for the drag.
197  void PrepareForDrag(Pointer pointer, const ui::LocatedEvent& event);
198
199  // Invoked when the mouse is dragged. Updates the models as appropriate.
200  void ContinueDrag(const ui::LocatedEvent& event);
201
202  // Handles ripping off an item from the shelf. Returns true when the item got
203  // removed.
204  bool HandleRipOffDrag(const ui::LocatedEvent& event);
205
206  // Finalize the rip off dragging by either |cancel| the action or validating.
207  void FinalizeRipOffDrag(bool cancel);
208
209  // Check if an item can be ripped off or not.
210  RemovableState RemovableByRipOff(int index) const;
211
212  // Returns true if |typea| and |typeb| should be in the same drag range.
213  bool SameDragType(ShelfItemType typea, ShelfItemType typeb) const;
214
215  // Returns the range (in the model) the item at the specified index can be
216  // dragged to.
217  std::pair<int, int> GetDragRange(int index);
218
219  // If there is a drag operation in progress it's canceled. If |modified_index|
220  // is valid, the new position of the corresponding item is returned.
221  int CancelDrag(int modified_index);
222
223  // Returns rectangle bounds used for drag insertion.
224  // Note:
225  //  * When overflow button is visible, returns bounds from first item
226  //    to overflow button.
227  //  * When overflow button is visible and one or more panel items exists,
228  //    returns bounds from first item to last panel item.
229  //  * In the overflow mode, returns only bubble's bounds.
230  gfx::Rect GetBoundsForDragInsertInScreen();
231
232  // Common setup done for all children.
233  void ConfigureChildView(views::View* view);
234
235  // Toggles the overflow menu.
236  void ToggleOverflowBubble();
237
238  // Invoked after the fading out animation for item deletion is ended.
239  void OnFadeOutAnimationEnded();
240
241  // Fade in last visible item.
242  void StartFadeInLastVisibleItem();
243
244  // Updates the visible range of overflow items in |overflow_view|.
245  void UpdateOverflowRange(ShelfView* overflow_view) const;
246
247  // Overridden from views::View:
248  virtual gfx::Size GetPreferredSize() const OVERRIDE;
249  virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
250  virtual FocusTraversable* GetPaneFocusTraversable() OVERRIDE;
251  virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
252
253  // Overridden from ui::EventHandler:
254  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
255
256  // Overridden from ShelfModelObserver:
257  virtual void ShelfItemAdded(int model_index) OVERRIDE;
258  virtual void ShelfItemRemoved(int model_index, ShelfID id) OVERRIDE;
259  virtual void ShelfItemChanged(int model_index,
260                                const ShelfItem& old_item) OVERRIDE;
261  virtual void ShelfItemMoved(int start_index, int target_index) OVERRIDE;
262  virtual void ShelfStatusChanged() OVERRIDE;
263
264  // Overridden from ShelfButtonHost:
265  virtual void PointerPressedOnButton(views::View* view,
266                                      Pointer pointer,
267                                      const ui::LocatedEvent& event) OVERRIDE;
268  virtual void PointerDraggedOnButton(views::View* view,
269                                      Pointer pointer,
270                                      const ui::LocatedEvent& event) OVERRIDE;
271  virtual void PointerReleasedOnButton(views::View* view,
272                                       Pointer pointer,
273                                       bool canceled) OVERRIDE;
274  virtual void MouseMovedOverButton(views::View* view) OVERRIDE;
275  virtual void MouseEnteredButton(views::View* view) OVERRIDE;
276  virtual void MouseExitedButton(views::View* view) OVERRIDE;
277  virtual base::string16 GetAccessibleName(const views::View* view) OVERRIDE;
278
279  // Overridden from views::ButtonListener:
280  virtual void ButtonPressed(views::Button* sender,
281                             const ui::Event& event) OVERRIDE;
282
283  // Show the list of all running items for this |item|. It will return true
284  // when the menu was shown and false if there were no possible items to
285  // choose from. |source| specifies the view which is responsible for showing
286  // the menu, and the bubble will point towards it.
287  // The |event_flags| are the flags of the event which triggered this menu.
288  bool ShowListMenuForView(const ShelfItem& item,
289                           views::View* source,
290                           const ui::Event& event);
291
292  // Overridden from views::ContextMenuController:
293  virtual void ShowContextMenuForView(views::View* source,
294                                      const gfx::Point& point,
295                                      ui::MenuSourceType source_type) OVERRIDE;
296
297  // Show either a context or normal click menu of given |menu_model|.
298  // If |context_menu| is set, the displayed menu is a context menu and not
299  // a menu listing one or more running applications.
300  // The |click_point| is only used for |context_menu|'s.
301  void ShowMenu(ui::MenuModel* menu_model,
302                views::View* source,
303                const gfx::Point& click_point,
304                bool context_menu,
305                ui::MenuSourceType source_type);
306
307  // Overridden from views::BoundsAnimatorObserver:
308  virtual void OnBoundsAnimatorProgressed(
309      views::BoundsAnimator* animator) OVERRIDE;
310  virtual void OnBoundsAnimatorDone(views::BoundsAnimator* animator) OVERRIDE;
311
312  // Returns false if the click which closed the previous menu is the click
313  // which triggered this event.
314  bool IsUsableEvent(const ui::Event& event);
315
316  // Convenience accessor to model_->items().
317  const ShelfItem* ShelfItemForView(const views::View* view) const;
318
319  // Returns true if a tooltip should be shown for |view|.
320  bool ShouldShowTooltipForView(const views::View* view) const;
321
322  // Get the distance from the given |coordinate| to the closest point on this
323  // launcher/shelf.
324  int CalculateShelfDistance(const gfx::Point& coordinate) const;
325
326  // The model; owned by Launcher.
327  ShelfModel* model_;
328
329  // Delegate; owned by Launcher.
330  ShelfDelegate* delegate_;
331
332  // Used to manage the set of active launcher buttons. There is a view per
333  // item in |model_|.
334  scoped_ptr<views::ViewModel> view_model_;
335
336  // Index of first visible launcher item.
337  int first_visible_index_;
338
339  // Last index of a launcher button that is visible
340  // (does not go into overflow).
341  mutable int last_visible_index_;
342
343  scoped_ptr<views::BoundsAnimator> bounds_animator_;
344
345  OverflowButton* overflow_button_;
346
347  scoped_ptr<OverflowBubble> overflow_bubble_;
348
349  OverflowBubble* owner_overflow_bubble_;
350
351  scoped_ptr<ShelfTooltipManager> tooltip_;
352
353  // Pointer device that initiated the current drag operation. If there is no
354  // current dragging operation, this is NONE.
355  Pointer drag_pointer_;
356
357  // The view being dragged. This is set immediately when the mouse is pressed.
358  // |dragging_| is set only if the mouse is dragged far enough.
359  views::View* drag_view_;
360
361  // Position of the mouse down event in |drag_view_|'s coordinates.
362  gfx::Point drag_origin_;
363
364  // Index |drag_view_| was initially at.
365  int start_drag_index_;
366
367  // Used for the context menu of a particular item.
368  ShelfID context_menu_id_;
369
370  scoped_ptr<views::FocusSearch> focus_search_;
371
372  scoped_ptr<ui::MenuModel> context_menu_model_;
373
374  scoped_ptr<views::MenuRunner> launcher_menu_runner_;
375
376  ObserverList<ShelfIconObserver> observers_;
377
378  // Amount content is inset on the left edge (or top edge for vertical
379  // alignment).
380  int leading_inset_;
381
382  ShelfGestureHandler gesture_handler_;
383
384  // True when an item being inserted or removed in the model cancels a drag.
385  bool cancelling_drag_model_changed_;
386
387  // Index of the last hidden launcher item. If there are no hidden items this
388  // will be equal to last_visible_index_ + 1.
389  mutable int last_hidden_index_;
390
391  // The timestamp of the event which closed the last menu - or 0.
392  base::TimeDelta closing_event_time_;
393
394  // When this object gets deleted while a menu is shown, this pointed
395  // element will be set to false.
396  bool* got_deleted_;
397
398  // True if a drag and drop operation created/pinned the item in the launcher
399  // and it needs to be deleted/unpinned again if the operation gets cancelled.
400  bool drag_and_drop_item_pinned_;
401
402  // The ShelfItem which is currently used for a drag and a drop operation
403  // or 0 otherwise.
404  ShelfID drag_and_drop_shelf_id_;
405
406  // The application ID of the application which we drag and drop.
407  std::string drag_and_drop_app_id_;
408
409  // The original launcher item's size before the dragging operation.
410  gfx::Size pre_drag_and_drop_size_;
411
412  // The image proxy for drag operations when a drag and drop host exists and
413  // the item can be dragged outside the app grid.
414  scoped_ptr<ash::DragImageView> drag_image_;
415
416  // The cursor offset to the middle of the dragged item.
417  gfx::Vector2d drag_image_offset_;
418
419  // The view which gets replaced by our drag icon proxy.
420  views::View* drag_replaced_view_;
421
422  // True when the icon was dragged off the shelf.
423  bool dragged_off_shelf_;
424
425  // The rip off view when a snap back operation is underway.
426  views::View* snap_back_from_rip_off_view_;
427
428  // Holds ShelfItemDelegateManager.
429  ShelfItemDelegateManager* item_manager_;
430
431  // Holds ShelfLayoutManager.
432  ShelfLayoutManager* layout_manager_;
433
434  // True when this ShelfView is used for Overflow Bubble.
435  bool overflow_mode_;
436
437  // Holds a pointer to main ShelfView when a ShelfView is in overflow mode.
438  ShelfView* main_shelf_;
439
440  // True when ripped item from overflow bubble is entered into Shelf.
441  bool dragged_off_from_overflow_to_shelf_;
442
443  DISALLOW_COPY_AND_ASSIGN(ShelfView);
444};
445
446}  // namespace ash
447
448#endif  // ASH_SHELF_SHELF_VIEW_H_
449