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_LAUNCHER_LAUNCHER_VIEW_H_
6#define ASH_LAUNCHER_LAUNCHER_VIEW_H_
7
8#include <utility>
9#include <vector>
10
11#include "ash/launcher/launcher_button_host.h"
12#include "ash/launcher/launcher_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 views {
23class BoundsAnimator;
24class MenuModelAdapter;
25class MenuRunner;
26class ViewModel;
27}
28
29namespace ash {
30
31namespace test {
32class LauncherViewTestAPI;
33}
34
35class LauncherDelegate;
36struct LauncherItem;
37class LauncherIconObserver;
38class LauncherModel;
39
40namespace internal {
41
42class DragImageView;
43class LauncherButton;
44class LauncherTooltipManager;
45class ShelfLayoutManager;
46class OverflowBubble;
47class OverflowButton;
48
49class ASH_EXPORT LauncherView : public views::View,
50                                public LauncherModelObserver,
51                                public views::ButtonListener,
52                                public LauncherButtonHost,
53                                public views::ContextMenuController,
54                                public views::FocusTraversable,
55                                public views::BoundsAnimatorObserver,
56                                public app_list::ApplicationDragAndDropHost {
57 public:
58  LauncherView(LauncherModel* model,
59               LauncherDelegate* delegate,
60               ShelfLayoutManager* shelf_layout_manager);
61  virtual ~LauncherView();
62
63  LauncherTooltipManager* tooltip_manager() { return tooltip_.get(); }
64
65  LauncherModel* model() { return model_; }
66
67  void Init();
68
69  void OnShelfAlignmentChanged();
70  void SchedulePaintForAllButtons();
71
72  // Returns the ideal bounds of the specified item, or an empty rect if id
73  // isn't know.
74  gfx::Rect GetIdealBoundsOfItemIcon(LauncherID id);
75
76  // Repositions the icon for the specified item by the midpoint of the window.
77  void UpdatePanelIconPosition(LauncherID id, const gfx::Point& midpoint);
78
79  void AddIconObserver(LauncherIconObserver* observer);
80  void RemoveIconObserver(LauncherIconObserver* observer);
81
82  // Returns true if we're showing a menu.
83  bool IsShowingMenu() const;
84
85  // Returns true if overflow bubble is shown.
86  bool IsShowingOverflowBubble() const;
87
88  views::View* GetAppListButtonView() const;
89
90  // Returns true if the mouse cursor exits the area for launcher tooltip.
91  // There are thin gaps between launcher buttons but the tooltip shouldn't hide
92  // in the gaps, but the tooltip should hide if the mouse moved totally outside
93  // of the buttons area.
94  bool ShouldHideTooltip(const gfx::Point& cursor_location);
95
96  int leading_inset() const { return leading_inset_; }
97  void set_leading_inset(int leading_inset) { leading_inset_ = leading_inset; }
98
99  // Overridden from FocusTraversable:
100  virtual views::FocusSearch* GetFocusSearch() OVERRIDE;
101  virtual FocusTraversable* GetFocusTraversableParent() OVERRIDE;
102  virtual View* GetFocusTraversableParentView() OVERRIDE;
103
104  // Overridden from app_list::ApplicationDragAndDropHost:
105  virtual void CreateDragIconProxy(
106      const gfx::Point& location_in_screen_coordinates,
107      const gfx::ImageSkia& icon,
108      views::View* replaced_view,
109      const gfx::Vector2d& cursor_offset_from_center,
110      float scale_factor) OVERRIDE;
111  virtual void UpdateDragIconProxy(
112      const gfx::Point& location_in_screen_coordinates) OVERRIDE;
113  virtual void DestroyDragIconProxy() OVERRIDE;
114  virtual bool StartDrag(
115      const std::string& app_id,
116      const gfx::Point& location_in_screen_coordinates) OVERRIDE;
117  virtual bool Drag(const gfx::Point& location_in_screen_coordinates) OVERRIDE;
118  virtual void EndDrag(bool cancel) OVERRIDE;
119
120  // Return the view model for test purposes.
121  const views::ViewModel* const view_model_for_test() const {
122    return view_model_.get();
123  }
124
125 private:
126  friend class ash::test::LauncherViewTestAPI;
127
128  class FadeOutAnimationDelegate;
129  class StartFadeAnimationDelegate;
130
131  struct IdealBounds {
132    gfx::Rect overflow_bounds;
133  };
134
135  bool is_overflow_mode() const {
136    return first_visible_index_ > 0;
137  }
138
139  bool dragging() const {
140    return drag_pointer_ != NONE;
141  }
142
143  // Sets the bounds of each view to its ideal bounds.
144  void LayoutToIdealBounds();
145
146  // Calculates the ideal bounds. The bounds of each button corresponding to an
147  // item in the model is set in |view_model_|.
148  void CalculateIdealBounds(IdealBounds* bounds);
149
150  // Returns the index of the last view whose max primary axis coordinate is
151  // less than |max_value|. Returns -1 if nothing fits, or there are no views.
152  int DetermineLastVisibleIndex(int max_value) const;
153
154  // Returns the index of the first panel whose min primary axis coordinate is
155  // at least |min_value|. Returns the index past the last panel if none fit.
156  int DetermineFirstVisiblePanelIndex(int min_value) const;
157
158  // Animates the bounds of each view to its ideal bounds.
159  void AnimateToIdealBounds();
160
161  // Creates the view used to represent |item|.
162  views::View* CreateViewForItem(const LauncherItem& item);
163
164  // Fades |view| from an opacity of 0 to 1. This is when adding a new item.
165  void FadeIn(views::View* view);
166
167  // Invoked when the pointer has moved enough to trigger a drag. Sets
168  // internal state in preparation for the drag.
169  void PrepareForDrag(Pointer pointer, const ui::LocatedEvent& event);
170
171  // Invoked when the mouse is dragged. Updates the models as appropriate.
172  void ContinueDrag(const ui::LocatedEvent& event);
173
174  // Returns true if |typea| and |typeb| should be in the same drag range.
175  bool SameDragType(LauncherItemType typea, LauncherItemType typeb) const;
176
177  // Returns the range (in the model) the item at the specified index can be
178  // dragged to.
179  std::pair<int, int> GetDragRange(int index);
180
181  // If there is a drag operation in progress it's canceled. If |modified_index|
182  // is valid, the new position of the corresponding item is returned.
183  int CancelDrag(int modified_index);
184
185  // Common setup done for all children.
186  void ConfigureChildView(views::View* view);
187
188  // Toggles the overflow menu.
189  void ToggleOverflowBubble();
190
191  // Update first launcher button's padding. This method adds padding to the
192  // first button to include the leading inset. It needs to be called once on
193  // button creation and every time when shelf alignment is changed.
194  void UpdateFirstButtonPadding();
195
196  // Invoked after the fading out animation for item deletion is ended.
197  void OnFadeOutAnimationEnded();
198
199  // Updates the visible range of overflow items in |overflow_view|.
200  void UpdateOverflowRange(LauncherView* overflow_view);
201
202  // Overridden from views::View:
203  virtual gfx::Size GetPreferredSize() OVERRIDE;
204  virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
205  virtual FocusTraversable* GetPaneFocusTraversable() OVERRIDE;
206  virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
207
208  // Overridden from ui::EventHandler:
209  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
210
211  // Overridden from LauncherModelObserver:
212  virtual void LauncherItemAdded(int model_index) OVERRIDE;
213  virtual void LauncherItemRemoved(int model_index, LauncherID id) OVERRIDE;
214  virtual void LauncherItemChanged(int model_index,
215                                   const ash::LauncherItem& old_item) OVERRIDE;
216  virtual void LauncherItemMoved(int start_index, int target_index) OVERRIDE;
217  virtual void LauncherStatusChanged() OVERRIDE;
218
219  // Overridden from LauncherButtonHost:
220  virtual void PointerPressedOnButton(
221      views::View* view,
222      Pointer pointer,
223      const ui::LocatedEvent& event) OVERRIDE;
224  virtual void PointerDraggedOnButton(
225      views::View* view,
226      Pointer pointer,
227      const ui::LocatedEvent& event) OVERRIDE;
228  virtual void PointerReleasedOnButton(views::View* view,
229                                       Pointer pointer,
230                                       bool canceled) OVERRIDE;
231  virtual void MouseMovedOverButton(views::View* view) OVERRIDE;
232  virtual void MouseEnteredButton(views::View* view) OVERRIDE;
233  virtual void MouseExitedButton(views::View* view) OVERRIDE;
234  virtual base::string16 GetAccessibleName(const views::View* view) OVERRIDE;
235
236  // Overridden from views::ButtonListener:
237  virtual void ButtonPressed(views::Button* sender,
238                             const ui::Event& event) OVERRIDE;
239
240  // Show the list of all running items for this |item|. It will return true
241  // when the menu was shown and false if there were no possible items to
242  // choose from. |source| specifies the view which is responsible for showing
243  // the menu, and the bubble will point towards it.
244  // The |event_flags| are the flags of the event which triggered this menu.
245  bool ShowListMenuForView(const LauncherItem& item,
246                           views::View* source,
247                           const ui::Event& event);
248
249  // Overridden from views::ContextMenuController:
250  virtual void ShowContextMenuForView(views::View* source,
251                                      const gfx::Point& point,
252                                      ui::MenuSourceType source_type) OVERRIDE;
253
254  // Show either a context or normal click menu of given |menu_model_adapter|.
255  // If |context_menu| is set, the displayed menu is a context menu and not
256  // a menu listing one or more running applications.
257  // The |click_point| is only used for |context_menu|'s.
258  void ShowMenu(scoped_ptr<views::MenuModelAdapter> menu_model_adapter,
259                views::View* source,
260                const gfx::Point& click_point,
261                bool context_menu,
262                ui::MenuSourceType source_type);
263
264  // Overridden from views::BoundsAnimatorObserver:
265  virtual void OnBoundsAnimatorProgressed(
266      views::BoundsAnimator* animator) OVERRIDE;
267  virtual void OnBoundsAnimatorDone(views::BoundsAnimator* animator) OVERRIDE;
268
269  // Returns false if the click which closed the previous menu is the click
270  // which triggered this event.
271  bool IsUsableEvent(const ui::Event& event);
272
273  // Convenience accessor to model_->items().
274  const LauncherItem* LauncherItemForView(const views::View* view) const;
275
276  // Returns true if a tooltip should be shown for |view|.
277  bool ShouldShowTooltipForView(const views::View* view) const;
278
279  // The model; owned by Launcher.
280  LauncherModel* model_;
281
282  // Delegate; owned by Launcher.
283  LauncherDelegate* delegate_;
284
285  // Used to manage the set of active launcher buttons. There is a view per
286  // item in |model_|.
287  scoped_ptr<views::ViewModel> view_model_;
288
289  // Index of first visible launcher item. When it it greater than 0,
290  // LauncherView is hosted in an overflow bubble. In this mode, it does not
291  // show browser, app list and overflow button.
292  int first_visible_index_;
293
294  // Last index of a launcher button that is visible
295  // (does not go into overflow).
296  int last_visible_index_;
297
298  scoped_ptr<views::BoundsAnimator> bounds_animator_;
299
300  OverflowButton* overflow_button_;
301
302  scoped_ptr<OverflowBubble> overflow_bubble_;
303
304  scoped_ptr<LauncherTooltipManager> tooltip_;
305
306  // Pointer device that initiated the current drag operation. If there is no
307  // current dragging operation, this is NONE.
308  Pointer drag_pointer_;
309
310  // The view being dragged. This is set immediately when the mouse is pressed.
311  // |dragging_| is set only if the mouse is dragged far enough.
312  views::View* drag_view_;
313
314  // X coordinate of the mouse down event in |drag_view_|s coordinates.
315  int drag_offset_;
316
317  // Index |drag_view_| was initially at.
318  int start_drag_index_;
319
320  // Used for the context menu of a particular item.
321  LauncherID context_menu_id_;
322
323  scoped_ptr<views::FocusSearch> focus_search_;
324
325#if !defined(OS_MACOSX)
326  scoped_ptr<views::MenuRunner> launcher_menu_runner_;
327#endif
328
329  ObserverList<LauncherIconObserver> observers_;
330
331  // Amount content is inset on the left edge (or top edge for vertical
332  // alignment).
333  int leading_inset_;
334
335  ShelfGestureHandler gesture_handler_;
336
337  // True when an item being inserted or removed in the model cancels a drag.
338  bool cancelling_drag_model_changed_;
339
340  // Index of the last hidden launcher item. If there are no hidden items this
341  // will be equal to last_visible_index_ + 1.
342  int last_hidden_index_;
343
344  // The timestamp of the event which closed the last menu - or 0.
345  base::TimeDelta closing_event_time_;
346
347  // When this object gets deleted while a menu is shown, this pointed
348  // element will be set to false.
349  bool* got_deleted_;
350
351  // True if a drag and drop operation created/pinned the item in the launcher
352  // and it needs to be deleted/unpinned again if the operation gets cancelled.
353  bool drag_and_drop_item_pinned_;
354
355  // The launcher item which is currently used for a drag and a drop operation
356  // or 0 otherwise.
357  LauncherID drag_and_drop_launcher_id_;
358
359  // The application ID of the application which we drag and drop.
360  std::string drag_and_drop_app_id_;
361
362  // The original launcher item's size before the dragging operation.
363  gfx::Size pre_drag_and_drop_size_;
364
365  // The image proxy for drag operations when a drag and drop host exists and
366  // the item can be dragged outside the app grid.
367  scoped_ptr<ash::internal::DragImageView> drag_image_;
368
369  // The cursor offset to the middle of the dragged item.
370  gfx::Vector2d drag_image_offset_;
371
372  // The view which gets replaced by our drag icon proxy.
373  views::View* drag_replaced_view_;
374
375  DISALLOW_COPY_AND_ASSIGN(LauncherView);
376};
377
378}  // namespace internal
379}  // namespace ash
380
381#endif  // ASH_LAUNCHER_LAUNCHER_VIEW_H_
382