summaryrefslogtreecommitdiffstats
path: root/chrome/browser/views/tabs/dragged_tab_controller.h
blob: 840a4fe48d43c4afbd9e24de299d8a4b13700f39 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_VIEWS_TABS_DRAGGED_TAB_CONTROLLER_H_
#define CHROME_BROWSER_VIEWS_TABS_DRAGGED_TAB_CONTROLLER_H_
#pragma once

#include "base/message_loop.h"
#include "base/timer.h"
#include "chrome/browser/dock_info.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/common/notification_registrar.h"
#include "gfx/rect.h"

namespace views {
class View;
}
class BaseTab;
class BaseTabStrip;
class DraggedTabView;
class NativeViewPhotobooth;
class TabStripModel;

struct TabRendererData;

///////////////////////////////////////////////////////////////////////////////
//
// DraggedTabController
//
//  An object that handles a drag session for an individual Tab within a
//  TabStrip. This object is created whenever the mouse is pressed down on a
//  Tab and destroyed when the mouse is released or the drag operation is
//  aborted. The Tab that the user dragged (the "source tab") owns this object
//  and must be the only one to destroy it (via |DestroyDragController|).
//
///////////////////////////////////////////////////////////////////////////////
class DraggedTabController : public TabContentsDelegate,
                             public NotificationObserver,
                             public MessageLoopForUI::Observer {
 public:
  DraggedTabController(BaseTab* source_tab,
                       BaseTabStrip* source_tabstrip);
  virtual ~DraggedTabController();

  // Returns true if there is a drag underway and the drag is attached to
  // |tab_strip|.
  // NOTE: this returns false if the dragged tab controller is in the process
  // of finishing the drag.
  static bool IsAttachedTo(BaseTabStrip* tab_strip);

  // Capture information needed to be used during a drag session for this
  // controller's associated source tab and BaseTabStrip. |mouse_offset| is the
  // distance of the mouse pointer from the tab's origin.
  void CaptureDragInfo(views::View* tab, const gfx::Point& mouse_offset);

  // Responds to drag events subsequent to StartDrag. If the mouse moves a
  // sufficient distance before the mouse is released, a drag session is
  // initiated.
  void Drag();

  // Complete the current drag session. If the drag session was canceled
  // because the user pressed Escape or something interrupted it, |canceled|
  // is true so the helper can revert the state to the world before the drag
  // begun.
  void EndDrag(bool canceled);

  TabContents* dragged_contents() { return dragged_contents_; }

  // Returns true if a drag started.
  bool started_drag() const { return started_drag_; }

 private:
  class DockDisplayer;
  friend class DockDisplayer;

  typedef std::set<gfx::NativeView> DockWindows;

  // Enumeration of the ways a drag session can end.
  enum EndDragType {
    // Drag session exited normally: the user released the mouse.
    NORMAL,

    // The drag session was canceled (alt-tab during drag, escape ...)
    CANCELED,

    // The tab (NavigationController) was destroyed during the drag.
    TAB_DESTROYED
  };

  // Overridden from TabContentsDelegate:
  virtual void OpenURLFromTab(TabContents* source,
                              const GURL& url,
                              const GURL& referrer,
                              WindowOpenDisposition disposition,
                              PageTransition::Type transition);
  virtual void NavigationStateChanged(const TabContents* source,
                                      unsigned changed_flags);
  virtual void AddNewContents(TabContents* source,
                              TabContents* new_contents,
                              WindowOpenDisposition disposition,
                              const gfx::Rect& initial_pos,
                              bool user_gesture);
  virtual void ActivateContents(TabContents* contents);
  virtual void LoadingStateChanged(TabContents* source);
  virtual void CloseContents(TabContents* source);
  virtual void MoveContents(TabContents* source, const gfx::Rect& pos);
  virtual void ToolbarSizeChanged(TabContents* source, bool is_animating);
  virtual void URLStarredChanged(TabContents* source, bool starred);
  virtual void UpdateTargetURL(TabContents* source, const GURL& url);

  // Overridden from NotificationObserver:
  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details);

  // Overridden from MessageLoop::Observer:
#if defined(OS_WIN)
  virtual void WillProcessMessage(const MSG& msg);
  virtual void DidProcessMessage(const MSG& msg);
#else
  virtual void WillProcessEvent(GdkEvent* event);
  virtual void DidProcessEvent(GdkEvent* event);
#endif

  // Initialize the offset used to calculate the position to create windows
  // in |GetWindowCreatePoint|. This should only be invoked from
  // |CaptureDragInfo|.
  void InitWindowCreatePoint();

  // Updates the window create point from |mouse_offset_|.
  void UpdateWindowCreatePoint();

  // Returns the point where a detached window should be created given the
  // current mouse position.
  gfx::Point GetWindowCreatePoint() const;

  void UpdateDockInfo(const gfx::Point& screen_point);

  // Sets the TabContents being dragged with the specified |new_contents|.
  void SetDraggedContents(TabContents* new_contents);

  // Saves focus in the window that the drag initiated from. Focus will be
  // restored appropriately if the drag ends within this same window.
  void SaveFocus();

  // Restore focus to the View that had focus before the drag was started, if
  // the drag ends within the same Window as it began.
  void RestoreFocus();

  // Tests whether the position of the mouse is past a minimum elasticity
  // threshold required to start a drag.
  bool CanStartDrag() const;

  // Move the DraggedTabView according to the current mouse screen position,
  // potentially updating the source and other TabStrips.
  void ContinueDragging();

  // Handles dragging a tab while the tab is attached.
  void MoveAttachedTab(const gfx::Point& screen_point);

  // Handles dragging while the tab is detached.
  void MoveDetachedTab(const gfx::Point& screen_point);

  // Returns the compatible TabStrip that is under the specified point (screen
  // coordinates), or NULL if there is none.
  BaseTabStrip* GetTabStripForPoint(const gfx::Point& screen_point);

  DockInfo GetDockInfoAtPoint(const gfx::Point& screen_point);

  // Returns the specified |tabstrip| if it contains the specified point
  // (screen coordinates), NULL if it does not.
  BaseTabStrip* GetTabStripIfItContains(BaseTabStrip* tabstrip,
                                        const gfx::Point& screen_point) const;

  // Attach the dragged Tab to the specified TabStrip.
  void Attach(BaseTabStrip* attached_tabstrip, const gfx::Point& screen_point);

  // Detach the dragged Tab from the current TabStrip.
  void Detach();

  // Returns the index where the dragged TabContents should be inserted into
  // the attached TabStripModel given the DraggedTabView's bounds
  // |dragged_bounds| in coordinates relative to the attached TabStrip.
  // |is_tab_attached| is true if the tab has already been added.
  int GetInsertionIndexForDraggedBounds(const gfx::Rect& dragged_bounds,
                                        bool is_tab_attached) const;

  // Retrieve the bounds of the DraggedTabView, relative to the attached
  // TabStrip, given location of the dragged tab in screen coordinates.
  gfx::Rect GetDraggedViewTabStripBounds(const gfx::Point& screen_point);

  // Get the position of the dragged tab view relative to the attached tab
  // strip.
  gfx::Point GetAttachedTabDragPoint(const gfx::Point& screen_point);

  // Finds the Tab within the specified TabStrip that corresponds to the
  // dragged TabContents.
  BaseTab* GetTabMatchingDraggedContents(BaseTabStrip* tabstrip) const;

  // Does the work for EndDrag. If we actually started a drag and |how_end| is
  // not TAB_DESTROYED then one of EndDrag or RevertDrag is invoked.
  void EndDragImpl(EndDragType how_end);

  // Reverts a cancelled drag operation.
  void RevertDrag();

  // Finishes a succesful drag operation.
  void CompleteDrag();

  // Create the DraggedTabView, if it does not yet exist.
  void EnsureDraggedView(const TabRendererData& data);

  // Utility for getting the mouse position in screen coordinates.
  gfx::Point GetCursorScreenPoint() const;

  // Returns the bounds (in screen coordinates) of the specified View.
  gfx::Rect GetViewScreenBounds(views::View* tabstrip) const;

  // Utility to convert the specified TabStripModel index to something valid
  // for the attached TabStrip.
  int NormalizeIndexToAttachedTabStrip(int index) const;

  // Hides the frame for the window that contains the TabStrip the current
  // drag session was initiated from.
  void HideFrame();

  // Closes a hidden frame at the end of a drag session.
  void CleanUpHiddenFrame();

  void DockDisplayerDestroyed(DockDisplayer* controller);

  void BringWindowUnderMouseToFront();

  // Returns the TabStripModel for the specified tabstrip.
  TabStripModel* GetModel(BaseTabStrip* tabstrip) const;

  // Handles registering for notifications.
  NotificationRegistrar registrar_;

  // The TabContents being dragged.
  TabContents* dragged_contents_;

  // The original TabContentsDelegate of |dragged_contents_|, before it was
  // detached from the browser window. We store this so that we can forward
  // certain delegate notifications back to it if we can't handle them locally.
  TabContentsDelegate* original_delegate_;

  // The TabStrip |source_tab_| originated from.
  BaseTabStrip* source_tabstrip_;

  // This is the index of the |source_tab_| in |source_tabstrip_| when the drag
  // began. This is used to restore the previous state if the drag is aborted.
  int source_model_index_;

  // The TabStrip the dragged Tab is currently attached to, or NULL if the
  // dragged Tab is detached.
  BaseTabStrip* attached_tabstrip_;

  // If attached this is the tab we're dragging.
  BaseTab* attached_tab_;

  // The visual representation of the dragged Tab.
  scoped_ptr<DraggedTabView> view_;

  // The photo-booth the TabContents sits in when the Tab is detached, to
  // obtain screen shots.
  scoped_ptr<NativeViewPhotobooth> photobooth_;

  // The position of the mouse (in screen coordinates) at the start of the drag
  // operation. This is used to calculate minimum elasticity before a
  // DraggedTabView is constructed.
  gfx::Point start_screen_point_;

  // This is the offset of the mouse from the top left of the Tab where
  // dragging begun. This is used to ensure that the dragged view is always
  // positioned at the correct location during the drag, and to ensure that the
  // detached window is created at the right location.
  gfx::Point mouse_offset_;

  // Ratio of the x-coordinate of the mouse offset to the width of the tab.
  float offset_to_width_ratio_;

  // A hint to use when positioning new windows created by detaching Tabs. This
  // is the distance of the mouse from the top left of the dragged tab as if it
  // were the distance of the mouse from the top left of the first tab in the
  // attached TabStrip from the top left of the window.
  gfx::Point window_create_point_;

  // Location of the first tab in the source tabstrip in screen coordinates.
  // This is used to calculate window_create_point_.
  gfx::Point first_source_tab_point_;

  // The bounds of the browser window before the last Tab was detached. When
  // the last Tab is detached, rather than destroying the frame (which would
  // abort the drag session), the frame is moved off-screen. If the drag is
  // aborted (e.g. by the user pressing Esc, or capture being lost), the Tab is
  // attached to the hidden frame and the frame moved back to these bounds.
  gfx::Rect restore_bounds_;

  // The last view that had focus in the window containing |source_tab_|. This
  // is saved so that focus can be restored properly when a drag begins and
  // ends within this same window.
  views::View* old_focused_view_;

  // The position along the major axis of the mouse cursor in screen coordinates
  // at the time of the last re-order event.
  int last_move_screen_loc_;

  DockInfo dock_info_;

  DockWindows dock_windows_;

  std::vector<DockDisplayer*> dock_controllers_;

  // Is the tab mini?
  const bool mini_;

  // Is the tab pinned?
  const bool pinned_;

  // Timer used to bring the window under the cursor to front. If the user
  // stops moving the mouse for a brief time over a browser window, it is
  // brought to front.
  base::OneShotTimer<DraggedTabController> bring_to_front_timer_;

  // Did the mouse move enough that we started a drag?
  bool started_drag_;

  // Is the drag active?
  bool active_;

  DISALLOW_COPY_AND_ASSIGN(DraggedTabController);
};

#endif  // CHROME_BROWSER_VIEWS_TABS_DRAGGED_TAB_CONTROLLER_H_