dragged_tab_controller.h revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2011 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 CHROME_BROWSER_UI_VIEWS_TABS_DRAGGED_TAB_CONTROLLER_H_ 6#define CHROME_BROWSER_UI_VIEWS_TABS_DRAGGED_TAB_CONTROLLER_H_ 7#pragma once 8 9#include "base/message_loop.h" 10#include "base/scoped_ptr.h" 11#include "base/timer.h" 12#include "chrome/browser/tab_contents/tab_contents_delegate.h" 13#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 14#include "chrome/browser/ui/tabs/dock_info.h" 15#include "chrome/common/notification_observer.h" 16#include "chrome/common/notification_registrar.h" 17#include "ui/gfx/rect.h" 18 19namespace views { 20class View; 21} 22class BaseTab; 23class BaseTabStrip; 24class DraggedTabView; 25class NativeViewPhotobooth; 26class TabStripModel; 27 28struct TabRendererData; 29 30/////////////////////////////////////////////////////////////////////////////// 31// 32// DraggedTabController 33// 34// An object that handles a drag session for an individual Tab within a 35// TabStrip. This object is created whenever the mouse is pressed down on a 36// Tab and destroyed when the mouse is released or the drag operation is 37// aborted. The Tab that the user dragged (the "source tab") owns this object 38// and must be the only one to destroy it (via |DestroyDragController|). 39// 40/////////////////////////////////////////////////////////////////////////////// 41class DraggedTabController : public TabContentsDelegate, 42 public NotificationObserver, 43 public MessageLoopForUI::Observer { 44 public: 45 DraggedTabController(BaseTab* source_tab, 46 BaseTabStrip* source_tabstrip); 47 virtual ~DraggedTabController(); 48 49 // Returns true if there is a drag underway and the drag is attached to 50 // |tab_strip|. 51 // NOTE: this returns false if the dragged tab controller is in the process 52 // of finishing the drag. 53 static bool IsAttachedTo(BaseTabStrip* tab_strip); 54 55 // Capture information needed to be used during a drag session for this 56 // controller's associated source tab and BaseTabStrip. |mouse_offset| is the 57 // distance of the mouse pointer from the tab's origin. 58 void CaptureDragInfo(views::View* tab, const gfx::Point& mouse_offset); 59 60 // Responds to drag events subsequent to StartDrag. If the mouse moves a 61 // sufficient distance before the mouse is released, a drag session is 62 // initiated. 63 void Drag(); 64 65 // Complete the current drag session. If the drag session was canceled 66 // because the user pressed Escape or something interrupted it, |canceled| 67 // is true so the helper can revert the state to the world before the drag 68 // begun. 69 void EndDrag(bool canceled); 70 71 TabContentsWrapper* dragged_contents() { return dragged_contents_; } 72 73 // Returns true if a drag started. 74 bool started_drag() const { return started_drag_; } 75 76 private: 77 class DockDisplayer; 78 friend class DockDisplayer; 79 80 typedef std::set<gfx::NativeView> DockWindows; 81 82 // Enumeration of the ways a drag session can end. 83 enum EndDragType { 84 // Drag session exited normally: the user released the mouse. 85 NORMAL, 86 87 // The drag session was canceled (alt-tab during drag, escape ...) 88 CANCELED, 89 90 // The tab (NavigationController) was destroyed during the drag. 91 TAB_DESTROYED 92 }; 93 94 // Overridden from TabContentsDelegate: 95 virtual void OpenURLFromTab(TabContents* source, 96 const GURL& url, 97 const GURL& referrer, 98 WindowOpenDisposition disposition, 99 PageTransition::Type transition); 100 virtual void NavigationStateChanged(const TabContents* source, 101 unsigned changed_flags); 102 virtual void AddNewContents(TabContents* source, 103 TabContents* new_contents, 104 WindowOpenDisposition disposition, 105 const gfx::Rect& initial_pos, 106 bool user_gesture); 107 virtual void ActivateContents(TabContents* contents); 108 virtual void DeactivateContents(TabContents* contents); 109 virtual void LoadingStateChanged(TabContents* source); 110 virtual void CloseContents(TabContents* source); 111 virtual void MoveContents(TabContents* source, const gfx::Rect& pos); 112 virtual void ToolbarSizeChanged(TabContents* source, bool is_animating); 113 virtual void UpdateTargetURL(TabContents* source, const GURL& url); 114 115 // Overridden from NotificationObserver: 116 virtual void Observe(NotificationType type, 117 const NotificationSource& source, 118 const NotificationDetails& details); 119 120 // Overridden from MessageLoop::Observer: 121#if defined(OS_WIN) 122 virtual void WillProcessMessage(const MSG& msg); 123 virtual void DidProcessMessage(const MSG& msg); 124#else 125 virtual void WillProcessEvent(GdkEvent* event); 126 virtual void DidProcessEvent(GdkEvent* event); 127#endif 128 129 // Initialize the offset used to calculate the position to create windows 130 // in |GetWindowCreatePoint|. This should only be invoked from 131 // |CaptureDragInfo|. 132 void InitWindowCreatePoint(); 133 134 // Updates the window create point from |mouse_offset_|. 135 void UpdateWindowCreatePoint(); 136 137 // Returns the point where a detached window should be created given the 138 // current mouse position. 139 gfx::Point GetWindowCreatePoint() const; 140 141 void UpdateDockInfo(const gfx::Point& screen_point); 142 143 // Sets the TabContents being dragged with the specified |new_contents|. 144 void SetDraggedContents(TabContentsWrapper* new_contents); 145 146 // Saves focus in the window that the drag initiated from. Focus will be 147 // restored appropriately if the drag ends within this same window. 148 void SaveFocus(); 149 150 // Restore focus to the View that had focus before the drag was started, if 151 // the drag ends within the same Window as it began. 152 void RestoreFocus(); 153 154 // Tests whether the position of the mouse is past a minimum elasticity 155 // threshold required to start a drag. 156 bool CanStartDrag() const; 157 158 // Move the DraggedTabView according to the current mouse screen position, 159 // potentially updating the source and other TabStrips. 160 void ContinueDragging(); 161 162 // Handles dragging a tab while the tab is attached. 163 void MoveAttachedTab(const gfx::Point& screen_point); 164 165 // Handles dragging while the tab is detached. 166 void MoveDetachedTab(const gfx::Point& screen_point); 167 168 // Returns the compatible TabStrip that is under the specified point (screen 169 // coordinates), or NULL if there is none. 170 BaseTabStrip* GetTabStripForPoint(const gfx::Point& screen_point); 171 172 DockInfo GetDockInfoAtPoint(const gfx::Point& screen_point); 173 174 // Returns the specified |tabstrip| if it contains the specified point 175 // (screen coordinates), NULL if it does not. 176 BaseTabStrip* GetTabStripIfItContains(BaseTabStrip* tabstrip, 177 const gfx::Point& screen_point) const; 178 179 // Attach the dragged Tab to the specified TabStrip. 180 void Attach(BaseTabStrip* attached_tabstrip, const gfx::Point& screen_point); 181 182 // Detach the dragged Tab from the current TabStrip. 183 void Detach(); 184 185 // Returns the index where the dragged TabContents should be inserted into 186 // the attached TabStripModel given the DraggedTabView's bounds 187 // |dragged_bounds| in coordinates relative to the attached TabStrip. 188 // |is_tab_attached| is true if the tab has already been added. 189 int GetInsertionIndexForDraggedBounds(const gfx::Rect& dragged_bounds, 190 bool is_tab_attached) const; 191 192 // Retrieve the bounds of the DraggedTabView, relative to the attached 193 // TabStrip, given location of the dragged tab in screen coordinates. 194 gfx::Rect GetDraggedViewTabStripBounds(const gfx::Point& screen_point); 195 196 // Get the position of the dragged tab view relative to the attached tab 197 // strip. 198 gfx::Point GetAttachedTabDragPoint(const gfx::Point& screen_point); 199 200 // Finds the Tab within the specified TabStrip that corresponds to the 201 // dragged TabContents. 202 BaseTab* GetTabMatchingDraggedContents(BaseTabStrip* tabstrip) const; 203 204 // Does the work for EndDrag. If we actually started a drag and |how_end| is 205 // not TAB_DESTROYED then one of EndDrag or RevertDrag is invoked. 206 void EndDragImpl(EndDragType how_end); 207 208 // Reverts a cancelled drag operation. 209 void RevertDrag(); 210 211 // Finishes a succesful drag operation. 212 void CompleteDrag(); 213 214 // Create the DraggedTabView, if it does not yet exist. 215 void EnsureDraggedView(const TabRendererData& data); 216 217 // Utility for getting the mouse position in screen coordinates. 218 gfx::Point GetCursorScreenPoint() const; 219 220 // Returns the bounds (in screen coordinates) of the specified View. 221 gfx::Rect GetViewScreenBounds(views::View* tabstrip) const; 222 223 // Utility to convert the specified TabStripModel index to something valid 224 // for the attached TabStrip. 225 int NormalizeIndexToAttachedTabStrip(int index) const; 226 227 // Hides the frame for the window that contains the TabStrip the current 228 // drag session was initiated from. 229 void HideFrame(); 230 231 // Closes a hidden frame at the end of a drag session. 232 void CleanUpHiddenFrame(); 233 234 void DockDisplayerDestroyed(DockDisplayer* controller); 235 236 void BringWindowUnderMouseToFront(); 237 238 // Returns the TabStripModel for the specified tabstrip. 239 TabStripModel* GetModel(BaseTabStrip* tabstrip) const; 240 241 // Handles registering for notifications. 242 NotificationRegistrar registrar_; 243 244 // The TabContentsWrapper being dragged. 245 TabContentsWrapper* dragged_contents_; 246 247 // The original TabContentsDelegate of |dragged_contents_|, before it was 248 // detached from the browser window. We store this so that we can forward 249 // certain delegate notifications back to it if we can't handle them locally. 250 TabContentsDelegate* original_delegate_; 251 252 // The TabStrip |source_tab_| originated from. 253 BaseTabStrip* source_tabstrip_; 254 255 // This is the index of the |source_tab_| in |source_tabstrip_| when the drag 256 // began. This is used to restore the previous state if the drag is aborted. 257 int source_model_index_; 258 259 // The TabStrip the dragged Tab is currently attached to, or NULL if the 260 // dragged Tab is detached. 261 BaseTabStrip* attached_tabstrip_; 262 263 // If attached this is the tab we're dragging. 264 BaseTab* attached_tab_; 265 266 // The visual representation of the dragged Tab. 267 scoped_ptr<DraggedTabView> view_; 268 269 // The photo-booth the TabContents sits in when the Tab is detached, to 270 // obtain screen shots. 271 scoped_ptr<NativeViewPhotobooth> photobooth_; 272 273 // The position of the mouse (in screen coordinates) at the start of the drag 274 // operation. This is used to calculate minimum elasticity before a 275 // DraggedTabView is constructed. 276 gfx::Point start_screen_point_; 277 278 // This is the offset of the mouse from the top left of the Tab where 279 // dragging begun. This is used to ensure that the dragged view is always 280 // positioned at the correct location during the drag, and to ensure that the 281 // detached window is created at the right location. 282 gfx::Point mouse_offset_; 283 284 // Ratio of the x-coordinate of the mouse offset to the width of the tab. 285 float offset_to_width_ratio_; 286 287 // A hint to use when positioning new windows created by detaching Tabs. This 288 // is the distance of the mouse from the top left of the dragged tab as if it 289 // were the distance of the mouse from the top left of the first tab in the 290 // attached TabStrip from the top left of the window. 291 gfx::Point window_create_point_; 292 293 // Location of the first tab in the source tabstrip in screen coordinates. 294 // This is used to calculate window_create_point_. 295 gfx::Point first_source_tab_point_; 296 297 // The bounds of the browser window before the last Tab was detached. When 298 // the last Tab is detached, rather than destroying the frame (which would 299 // abort the drag session), the frame is moved off-screen. If the drag is 300 // aborted (e.g. by the user pressing Esc, or capture being lost), the Tab is 301 // attached to the hidden frame and the frame moved back to these bounds. 302 gfx::Rect restore_bounds_; 303 304 // The last view that had focus in the window containing |source_tab_|. This 305 // is saved so that focus can be restored properly when a drag begins and 306 // ends within this same window. 307 views::View* old_focused_view_; 308 309 // The position along the major axis of the mouse cursor in screen coordinates 310 // at the time of the last re-order event. 311 int last_move_screen_loc_; 312 313 DockInfo dock_info_; 314 315 DockWindows dock_windows_; 316 317 std::vector<DockDisplayer*> dock_controllers_; 318 319 // Is the tab mini? 320 const bool mini_; 321 322 // Is the tab pinned? 323 const bool pinned_; 324 325 // Timer used to bring the window under the cursor to front. If the user 326 // stops moving the mouse for a brief time over a browser window, it is 327 // brought to front. 328 base::OneShotTimer<DraggedTabController> bring_to_front_timer_; 329 330 // Did the mouse move enough that we started a drag? 331 bool started_drag_; 332 333 // Is the drag active? 334 bool active_; 335 336 DISALLOW_COPY_AND_ASSIGN(DraggedTabController); 337}; 338 339#endif // CHROME_BROWSER_UI_VIEWS_TABS_DRAGGED_TAB_CONTROLLER_H_ 340