diff options
-rw-r--r-- | chrome/browser/ui/views/tabs/default_tab_drag_controller.cc | 862 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/default_tab_drag_controller.h | 186 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_drag_controller.h | 75 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_drag_controller2.cc | 1425 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_drag_controller2.h | 395 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_drag_controller2_interactive_uitest.cc | 122 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h | 72 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest_win.cc | 354 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_dragging_test.cc | 514 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_strip.cc | 9 | ||||
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_strip.h | 5 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 3 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 5 |
13 files changed, 1208 insertions, 2819 deletions
diff --git a/chrome/browser/ui/views/tabs/default_tab_drag_controller.cc b/chrome/browser/ui/views/tabs/default_tab_drag_controller.cc index 523e5e4..266db28 100644 --- a/chrome/browser/ui/views/tabs/default_tab_drag_controller.cc +++ b/chrome/browser/ui/views/tabs/default_tab_drag_controller.cc @@ -22,8 +22,10 @@ #include "chrome/browser/ui/views/tabs/tab.h" #include "chrome/browser/ui/views/tabs/tab_strip.h" #include "chrome/browser/ui/views/tabs/touch_tab_strip_layout.h" +#include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_switches.h" #include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/user_metrics.h" @@ -41,11 +43,9 @@ #include "ui/views/widget/root_view.h" #include "ui/views/widget/widget.h" -#if defined(USE_AURA) +#if defined(USE_ASH) #include "ash/shell.h" -#include "chrome/browser/ui/views/tabs/tab_drag_controller2.h" -#elif defined(OS_WIN) -#include "chrome/browser/ui/views/tabs/tab_drag_controller2.h" +#include "ash/wm/property_util.h" #endif using content::OpenURLParams; @@ -59,7 +59,7 @@ static const int kHorizontalMoveThreshold = 16; // Pixels. static const int kStackedDistance = 36; // If non-null there is a drag underway. -static DefaultTabDragController* instance_ = NULL; +static TabDragController* instance_ = NULL; namespace { @@ -187,6 +187,21 @@ class DockView : public views::View { DISALLOW_COPY_AND_ASSIGN(DockView); }; +void SetTrackedByWorkspace(gfx::NativeWindow window, bool value) { +#if defined(USE_ASH) + ash::SetTrackedByWorkspace(window, value); +#endif +} + +bool ShouldDetachIntoNewBrowser() { +#if defined(USE_AURA) + return true; +#else + return CommandLine::ForCurrentProcess()->HasSwitch( + switches::kTabBrowserDragging); +#endif +} + } // namespace /////////////////////////////////////////////////////////////////////////////// @@ -196,19 +211,16 @@ class DockView : public views::View { // possible dock position (as represented by DockInfo). DockDisplayer shows // a window with a DockView in it. Two animations are used that correspond to // the state of DockInfo::in_enable_area. -class DefaultTabDragController::DockDisplayer : public ui::AnimationDelegate { +class TabDragController::DockDisplayer : public ui::AnimationDelegate { public: - DockDisplayer(DefaultTabDragController* controller, - const DockInfo& info) + DockDisplayer(TabDragController* controller, const DockInfo& info) : controller_(controller), popup_(NULL), popup_view_(NULL), ALLOW_THIS_IN_INITIALIZER_LIST(animation_(this)), hidden_(false), in_enable_area_(info.in_enable_area()) { -#if defined(OS_WIN) popup_ = new views::Widget; - // TODO(sky): This should "just work" on Gtk now. views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); params.transparent = true; params.keep_on_top = true; @@ -221,13 +233,10 @@ class DefaultTabDragController::DockDisplayer : public ui::AnimationDelegate { else animation_.Show(); popup_->Show(); -#else - NOTIMPLEMENTED(); -#endif popup_view_ = popup_->GetNativeView(); } - ~DockDisplayer() { + virtual ~DockDisplayer() { if (controller_) controller_->DockDisplayerDestroyed(this); } @@ -240,15 +249,15 @@ class DefaultTabDragController::DockDisplayer : public ui::AnimationDelegate { } } - // Resets the reference to the hosting DefaultTabDragController. This is - // invoked when the DefaultTabDragController is destroyed. + // Resets the reference to the hosting TabDragController. This is + // invoked when the TabDragController is destroyed. void clear_controller() { controller_ = NULL; } // NativeView of the window we create. gfx::NativeView popup_view() { return popup_view_; } // Starts the hide animation. When the window is closed the - // DefaultTabDragController is notified by way of the DockDisplayerDestroyed + // TabDragController is notified by way of the DockDisplayerDestroyed // method void Hide() { if (hidden_) @@ -262,26 +271,26 @@ class DefaultTabDragController::DockDisplayer : public ui::AnimationDelegate { animation_.Hide(); } - virtual void AnimationProgressed(const ui::Animation* animation) { + virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE { UpdateLayeredAlpha(); } - virtual void AnimationEnded(const ui::Animation* animation) { + virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE { if (!hidden_) return; popup_->Close(); delete this; } - virtual void UpdateLayeredAlpha() { + private: + void UpdateLayeredAlpha() { double scale = in_enable_area_ ? 1 : .5; popup_->SetOpacity(static_cast<unsigned char>(animation_.GetCurrentValue() * scale * 255.0)); } - private: - // DefaultTabDragController that created us. - DefaultTabDragController* controller_; + // TabDragController that created us. + TabDragController* controller_; // Window we're showing. views::Widget* popup_; @@ -300,7 +309,7 @@ class DefaultTabDragController::DockDisplayer : public ui::AnimationDelegate { bool in_enable_area_; }; -DefaultTabDragController::TabDragData::TabDragData() +TabDragController::TabDragData::TabDragData() : contents(NULL), original_delegate(NULL), source_model_index(-1), @@ -308,14 +317,15 @@ DefaultTabDragController::TabDragData::TabDragData() pinned(false) { } -DefaultTabDragController::TabDragData::~TabDragData() { +TabDragController::TabDragData::~TabDragData() { } /////////////////////////////////////////////////////////////////////////////// -// DefaultTabDragController, public: +// TabDragController, public: -DefaultTabDragController::DefaultTabDragController() - : source_tabstrip_(NULL), +TabDragController::TabDragController() + : detach_into_browser_(ShouldDetachIntoNewBrowser()), + source_tabstrip_(NULL), attached_tabstrip_(NULL), source_tab_offset_(0), offset_to_width_ratio_(0), @@ -326,14 +336,31 @@ DefaultTabDragController::DefaultTabDragController() source_tab_index_(std::numeric_limits<size_t>::max()), initial_move_(true), move_only_(false), - mouse_move_direction_(0) { + mouse_move_direction_(0), + is_dragging_window_(false), + end_run_loop_behavior_(END_RUN_LOOP_STOP_DRAGGING), + waiting_for_run_loop_to_exit_(false), + tab_strip_to_attach_to_after_exit_(NULL), + move_loop_widget_(NULL), + destroyed_(NULL) { instance_ = this; } -DefaultTabDragController::~DefaultTabDragController() { +TabDragController::~TabDragController() { if (instance_ == this) instance_ = NULL; + if (destroyed_) + *destroyed_ = true; + + if (move_loop_widget_) { + move_loop_widget_->RemoveObserver(this); + SetTrackedByWorkspace(move_loop_widget_->GetNativeView(), true); + } + + if (source_tabstrip_ && detach_into_browser_) + GetModel(source_tabstrip_)->RemoveObserver(this); + MessageLoopForUI::current()->RemoveObserver(this); // Need to delete the view here manually _before_ we reset the dragged @@ -344,10 +371,11 @@ DefaultTabDragController::~DefaultTabDragController() { // Reset the delegate of the dragged WebContents. This ends up doing nothing // if the drag was completed. - ResetDelegates(); + if (!detach_into_browser_) + ResetDelegates(); } -void DefaultTabDragController::Init( +void TabDragController::Init( TabStrip* source_tabstrip, BaseTab* source_tab, const std::vector<BaseTab*>& tabs, @@ -363,11 +391,12 @@ void DefaultTabDragController::Init( mouse_offset_ = mouse_offset; move_only_ = move_only; last_screen_point_ = start_screen_point_; - if (move_only_) { last_move_screen_loc_ = start_screen_point_.x(); initial_tab_positions_ = source_tabstrip->GetTabXCoordinates(); } + if (detach_into_browser_) + GetModel(source_tabstrip_)->AddObserver(this); drag_data_.resize(tabs.size()); for (size_t i = 0; i < tabs.size(); ++i) @@ -386,30 +415,24 @@ void DefaultTabDragController::Init( initial_selection_model_.Copy(initial_selection_model); } -void DefaultTabDragController::InitTabDragData(BaseTab* tab, - TabDragData* drag_data) { - drag_data->source_model_index = - source_tabstrip_->GetModelIndexOfBaseTab(tab); - drag_data->contents = GetModel(source_tabstrip_)->GetTabContentsAt( - drag_data->source_model_index); - drag_data->pinned = source_tabstrip_->IsTabPinned(tab); - registrar_.Add( - this, - content::NOTIFICATION_WEB_CONTENTS_DESTROYED, - content::Source<WebContents>(drag_data->contents->web_contents())); +// static +bool TabDragController::IsAttachedTo(TabStrip* tab_strip) { + return (instance_ && instance_->active() && + instance_->attached_tabstrip() == tab_strip); +} - // We need to be the delegate so we receive messages about stuff, otherwise - // our dragged WebContents may be replaced and subsequently - // collected/destroyed while the drag is in process, leading to nasty crashes. - drag_data->original_delegate = - drag_data->contents->web_contents()->GetDelegate(); - drag_data->contents->web_contents()->SetDelegate(this); +// static +bool TabDragController::IsActive() { + return instance_ && instance_->active(); } -void DefaultTabDragController::Drag() { +void TabDragController::Drag() { bring_to_front_timer_.Stop(); move_stacked_timer_.Stop(); + if (waiting_for_run_loop_to_exit_) + return; + if (!started_drag_) { if (!CanStartDrag()) return; // User hasn't dragged far enough yet. @@ -417,28 +440,43 @@ void DefaultTabDragController::Drag() { started_drag_ = true; SaveFocus(); Attach(source_tabstrip_, gfx::Point()); - // Redirect all mouse events to the TabStrip so that the tab that - // originated the drag can safely be deleted. - static_cast<views::internal::RootView*>( - source_tabstrip_->GetWidget()->GetRootView())->SetMouseHandler( - source_tabstrip_); + if (detach_into_browser_ && static_cast<int>(drag_data_.size()) == + GetModel(source_tabstrip_)->count()) { + RunMoveLoop(); // Runs a nested loop, returning when done. + return; + } } ContinueDragging(); } -void DefaultTabDragController::EndDrag(bool canceled) { - EndDragImpl(canceled ? CANCELED : NORMAL); +void TabDragController::EndDrag(bool canceled) { + EndDragImpl(canceled && source_tabstrip_ ? CANCELED : NORMAL); } -bool DefaultTabDragController::GetStartedDrag() const { - return started_drag_; +void TabDragController::InitTabDragData(BaseTab* tab, + TabDragData* drag_data) { + drag_data->source_model_index = + source_tabstrip_->GetModelIndexOfBaseTab(tab); + drag_data->contents = GetModel(source_tabstrip_)->GetTabContentsAt( + drag_data->source_model_index); + drag_data->pinned = source_tabstrip_->IsTabPinned(tab); + registrar_.Add( + this, + content::NOTIFICATION_WEB_CONTENTS_DESTROYED, + content::Source<WebContents>(drag_data->contents->web_contents())); + + if (!detach_into_browser_) { + drag_data->original_delegate = + drag_data->contents->web_contents()->GetDelegate(); + drag_data->contents->web_contents()->SetDelegate(this); + } } /////////////////////////////////////////////////////////////////////////////// -// DefaultTabDragController, PageNavigator implementation: +// TabDragController, PageNavigator implementation: -WebContents* DefaultTabDragController::OpenURLFromTab( +WebContents* TabDragController::OpenURLFromTab( WebContents* source, const OpenURLParams& params) { if (source_tab_drag_data()->original_delegate) { @@ -453,10 +491,10 @@ WebContents* DefaultTabDragController::OpenURLFromTab( } /////////////////////////////////////////////////////////////////////////////// -// DefaultTabDragController, content::WebContentsDelegate implementation: +// TabDragController, content::WebContentsDelegate implementation: -void DefaultTabDragController::NavigationStateChanged(const WebContents* source, - unsigned changed_flags) { +void TabDragController::NavigationStateChanged(const WebContents* source, + unsigned changed_flags) { if (attached_tabstrip_) { for (size_t i = 0; i < drag_data_.size(); ++i) { if (drag_data_[i].contents->web_contents() == source) { @@ -473,11 +511,11 @@ void DefaultTabDragController::NavigationStateChanged(const WebContents* source, view_->Update(); } -void DefaultTabDragController::AddNewContents(WebContents* source, - WebContents* new_contents, - WindowOpenDisposition disposition, - const gfx::Rect& initial_pos, - bool user_gesture) { +void TabDragController::AddNewContents(WebContents* source, + WebContents* new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture) { DCHECK_NE(CURRENT_TAB, disposition); // Theoretically could be called while dragging if the page tries to @@ -488,14 +526,14 @@ void DefaultTabDragController::AddNewContents(WebContents* source, } } -void DefaultTabDragController::LoadingStateChanged(WebContents* source) { +void TabDragController::LoadingStateChanged(WebContents* source) { // It would be nice to respond to this message by changing the // screen shot in the dragged tab. if (view_.get()) view_->Update(); } -bool DefaultTabDragController::ShouldSuppressDialogs() { +bool TabDragController::ShouldSuppressDialogs() { // When a dialog is about to be shown we revert the drag. Otherwise a modal // dialog might appear and attempt to parent itself to a hidden tabcontents. EndDragImpl(CANCELED); @@ -503,14 +541,14 @@ bool DefaultTabDragController::ShouldSuppressDialogs() { } content::JavaScriptDialogCreator* -DefaultTabDragController::GetJavaScriptDialogCreator() { +TabDragController::GetJavaScriptDialogCreator() { return GetJavaScriptDialogCreatorInstance(); } /////////////////////////////////////////////////////////////////////////////// -// DefaultTabDragController, content::NotificationObserver implementation: +// TabDragController, content::NotificationObserver implementation: -void DefaultTabDragController::Observe( +void TabDragController::Observe( int type, const content::NotificationSource& source, const content::NotificationDetails& details) { @@ -532,15 +570,14 @@ void DefaultTabDragController::Observe( } /////////////////////////////////////////////////////////////////////////////// -// DefaultTabDragController, MessageLoop::Observer implementation: +// TabDragController, MessageLoop::Observer implementation: -#if defined(OS_WIN) || defined(USE_AURA) -base::EventStatus DefaultTabDragController::WillProcessEvent( +base::EventStatus TabDragController::WillProcessEvent( const base::NativeEvent& event) { return base::EVENT_CONTINUE; } -void DefaultTabDragController::DidProcessEvent(const base::NativeEvent& event) { +void TabDragController::DidProcessEvent(const base::NativeEvent& event) { // If the user presses ESC during a drag, we need to abort and revert things // to the way they were. This is the most reliable way to do this since no // single view or window reliably receives events throughout all the various @@ -550,12 +587,23 @@ void DefaultTabDragController::DidProcessEvent(const base::NativeEvent& event) { EndDrag(true); } } -#endif + +void TabDragController::OnWidgetMoved(views::Widget* widget) { + Drag(); +} + +void TabDragController::TabStripEmpty() { + DCHECK(detach_into_browser_); + GetModel(source_tabstrip_)->RemoveObserver(this); + // NULL out source_tabstrip_ so that we don't attempt to add back to it (in + // the case of a revert). + source_tabstrip_ = NULL; +} /////////////////////////////////////////////////////////////////////////////// -// DefaultTabDragController, private: +// TabDragController, private: -void DefaultTabDragController::InitWindowCreatePoint() { +void TabDragController::InitWindowCreatePoint() { // window_create_point_ is only used in CompleteDrag() (through // GetWindowCreatePoint() to get the start point of the docked window) when // the attached_tabstrip_ is NULL and all the window's related bound @@ -569,7 +617,7 @@ void DefaultTabDragController::InitWindowCreatePoint() { window_create_point_.Offset(mouse_offset_.x(), mouse_offset_.y()); } -gfx::Point DefaultTabDragController::GetWindowCreatePoint() const { +gfx::Point TabDragController::GetWindowCreatePoint() const { gfx::Point cursor_point = GetCursorScreenPoint(); if (dock_info_.type() != DockInfo::NONE && dock_info_.in_enable_area()) { // If we're going to dock, we need to return the exact coordinate, @@ -594,7 +642,7 @@ gfx::Point DefaultTabDragController::GetWindowCreatePoint() const { cursor_point.y() - window_create_point_.y()); } -void DefaultTabDragController::UpdateDockInfo(const gfx::Point& screen_point) { +void TabDragController::UpdateDockInfo(const gfx::Point& screen_point) { // Update the DockInfo for the current mouse coordinates. DockInfo dock_info = GetDockInfoAtPoint(screen_point); if (!dock_info.equals(dock_info_)) { @@ -623,19 +671,20 @@ void DefaultTabDragController::UpdateDockInfo(const gfx::Point& screen_point) { } } -void DefaultTabDragController::SaveFocus() { +void TabDragController::SaveFocus() { DCHECK(!old_focused_view_); // This should only be invoked once. + DCHECK(source_tabstrip_); old_focused_view_ = source_tabstrip_->GetFocusManager()->GetFocusedView(); source_tabstrip_->GetFocusManager()->SetFocusedView(source_tabstrip_); } -void DefaultTabDragController::RestoreFocus() { +void TabDragController::RestoreFocus() { if (old_focused_view_ && attached_tabstrip_ == source_tabstrip_) old_focused_view_->GetFocusManager()->SetFocusedView(old_focused_view_); old_focused_view_ = NULL; } -bool DefaultTabDragController::CanStartDrag() const { +bool TabDragController::CanStartDrag() const { // Determine if the mouse has moved beyond a minimum elasticity distance in // any direction from the starting point. static const int kMinimumDragDistance = 10; @@ -646,7 +695,9 @@ bool DefaultTabDragController::CanStartDrag() const { pow(static_cast<float>(y_offset), 2)) > kMinimumDragDistance; } -void DefaultTabDragController::ContinueDragging() { +void TabDragController::ContinueDragging() { + DCHECK(!detach_into_browser_ || attached_tabstrip_); + // Note that the coordinates given to us by |drag_event| are basically // useless, since they're in source_tab_ coordinates. On the surface, you'd // think we could just convert them to screen coordinates, however in the @@ -659,41 +710,104 @@ void DefaultTabDragController::ContinueDragging() { // guaranteed to be correct regardless of monitor config. gfx::Point screen_point = GetCursorScreenPoint(); - // TODO(sky): this file shouldn't be built on chromeos. -#if defined(OS_WIN) && !defined(USE_AURA) TabStrip* target_tabstrip = move_only_ ? source_tabstrip_ : GetTabStripForPoint(screen_point); -#else - TabStrip* target_tabstrip = source_tabstrip_; -#endif + bool tab_strip_changed = (target_tabstrip != attached_tabstrip_); - if (target_tabstrip != attached_tabstrip_) { - // Make sure we're fully detached from whatever TabStrip we're attached to - // (if any). - if (attached_tabstrip_) - Detach(); - if (target_tabstrip) - Attach(target_tabstrip, screen_point); + if (tab_strip_changed) { + if (detach_into_browser_ && + DragBrowserToNewTabStrip(target_tabstrip, screen_point) == + DRAG_BROWSER_RESULT_STOP) { + return; + } else if (!detach_into_browser_) { + if (attached_tabstrip_) + Detach(); + if (target_tabstrip) + Attach(target_tabstrip, screen_point); + } } - if (!target_tabstrip) { + if (view_.get() || is_dragging_window_) { bring_to_front_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kBringToFrontDelay), this, - &DefaultTabDragController::BringWindowUnderMouseToFront); + &TabDragController::BringWindowUnderMouseToFront); } UpdateDockInfo(screen_point); - if (attached_tabstrip_) { - if (move_only_) - DragActiveTabStacked(screen_point); - else - MoveAttached(screen_point); - } else { - MoveDetached(screen_point); + if (!is_dragging_window_) { + if (attached_tabstrip_) { + if (move_only_) { + DragActiveTabStacked(screen_point); + } else { + MoveAttached(screen_point); + if (tab_strip_changed) { + // Move the corresponding window to the front. We do this after the + // move as on windows activate triggers a synchronous paint. + attached_tabstrip_->GetWidget()->Activate(); + } + } + } else { + MoveDetached(screen_point); + } + } +} + +TabDragController::DragBrowserResultType +TabDragController::DragBrowserToNewTabStrip( + TabStrip* target_tabstrip, + const gfx::Point& screen_point) { + if (!target_tabstrip) { + DetachIntoNewBrowserAndRunMoveLoop(screen_point); + return DRAG_BROWSER_RESULT_STOP; + } + if (is_dragging_window_) { +#if defined(USE_ASH) + // ReleaseMouseCapture() is going to result in calling back to us (because + // it results in a move). That'll cause all sorts of problems. Reset the + // observer so we don't get notified and process the event. + move_loop_widget_->RemoveObserver(this); + move_loop_widget_ = NULL; +#endif + views::Widget* browser_widget = GetAttachedBrowserWidget(); + // Need to release the drag controller before starting the move loop as it's + // going to trigger capture lost, which cancels drag. + attached_tabstrip_->ReleaseDragController(); + target_tabstrip->OwnDragController(this); + // Disable animations so that we don't see a close animation on aero. + browser_widget->SetVisibilityChangedAnimationsEnabled(false); + browser_widget->ReleaseMouseCapture(); + // EndMoveLoop is going to snap the window back to its original location. + // Hide it so users don't see this. + browser_widget->Hide(); + browser_widget->EndMoveLoop(); + + // Ideally we would always swap the tabs now, but on windows it seems that + // running the move loop implicitly activates the window when done, leading + // to all sorts of flicker. So, on windows, instead we process the move + // after the loop completes. But on chromeos, we can do tab swapping now to + // avoid the tab flashing issue(crbug.com/116329). +#if defined(USE_ASH) + is_dragging_window_ = false; + Detach(); + gfx::Point screen_point(GetCursorScreenPoint()); + Attach(target_tabstrip, screen_point); + // Move the tabs into position. + MoveAttached(screen_point); + attached_tabstrip_->GetWidget()->Activate(); +#else + tab_strip_to_attach_to_after_exit_ = target_tabstrip; +#endif + + waiting_for_run_loop_to_exit_ = true; + end_run_loop_behavior_ = END_RUN_LOOP_CONTINUE_DRAGGING; + return DRAG_BROWSER_RESULT_STOP; } + Detach(); + Attach(target_tabstrip, screen_point); + return DRAG_BROWSER_RESULT_CONTINUE; } -void DefaultTabDragController::DragActiveTabStacked( +void TabDragController::DragActiveTabStacked( const gfx::Point& screen_point) { if (attached_tabstrip_->tab_count() != static_cast<int>(initial_tab_positions_.size())) @@ -703,7 +817,7 @@ void DefaultTabDragController::DragActiveTabStacked( attached_tabstrip_->DragActiveTab(initial_tab_positions_, delta); } -void DefaultTabDragController::MoveAttachedToNextStackedIndex() { +void TabDragController::MoveAttachedToNextStackedIndex() { int index = attached_tabstrip_->touch_layout_->active_index(); if (index + 1 >= attached_tabstrip_->tab_count()) return; @@ -712,7 +826,7 @@ void DefaultTabDragController::MoveAttachedToNextStackedIndex() { StartMoveStackedTimerIfNecessary(kMoveAttachedSubsequentDelay); } -void DefaultTabDragController::MoveAttachedToPreviousStackedIndex() { +void TabDragController::MoveAttachedToPreviousStackedIndex() { int index = attached_tabstrip_->touch_layout_->active_index(); if (index <= attached_tabstrip_->GetMiniTabCount()) return; @@ -721,9 +835,10 @@ void DefaultTabDragController::MoveAttachedToPreviousStackedIndex() { StartMoveStackedTimerIfNecessary(kMoveAttachedSubsequentDelay); } -void DefaultTabDragController::MoveAttached(const gfx::Point& screen_point) { +void TabDragController::MoveAttached(const gfx::Point& screen_point) { DCHECK(attached_tabstrip_); DCHECK(!view_.get()); + DCHECK(!is_dragging_window_); int move_delta = screen_point.x() - last_screen_point_.x(); if (move_delta > 0) @@ -794,15 +909,16 @@ void DefaultTabDragController::MoveAttached(const gfx::Point& screen_point) { initial_move_ = false; } -void DefaultTabDragController::MoveDetached(const gfx::Point& screen_point) { +void TabDragController::MoveDetached(const gfx::Point& screen_point) { DCHECK(!attached_tabstrip_); DCHECK(view_.get()); + DCHECK(!is_dragging_window_); // Move the View. There are no changes to the model if we're detached. view_->MoveTo(screen_point); } -void DefaultTabDragController::StartMoveStackedTimerIfNecessary(int delay_ms) { +void TabDragController::StartMoveStackedTimerIfNecessary(int delay_ms) { DCHECK(attached_tabstrip_); TouchTabStripLayout* touch_layout = attached_tabstrip_->touch_layout_.get(); @@ -817,18 +933,30 @@ void DefaultTabDragController::StartMoveStackedTimerIfNecessary(int delay_ms) { move_stacked_timer_.Start( FROM_HERE, base::TimeDelta::FromMilliseconds(delay_ms), this, - &DefaultTabDragController::MoveAttachedToNextStackedIndex); + &TabDragController::MoveAttachedToNextStackedIndex); } else if (ShouldDragToPreviousStackedTab(bounds, index)) { move_stacked_timer_.Start( FROM_HERE, base::TimeDelta::FromMilliseconds(delay_ms), this, - &DefaultTabDragController::MoveAttachedToPreviousStackedIndex); + &TabDragController::MoveAttachedToPreviousStackedIndex); } } -DockInfo DefaultTabDragController::GetDockInfoAtPoint( +TabDragController::DetachPosition TabDragController::GetDetachPosition( const gfx::Point& screen_point) { - if (attached_tabstrip_) { + DCHECK(attached_tabstrip_); + gfx::Point attached_point(screen_point); + views::View::ConvertPointToView(NULL, attached_tabstrip_, &attached_point); + if (attached_point.x() < 0) + return DETACH_BEFORE; + if (attached_point.x() >= attached_tabstrip_->width()) + return DETACH_AFTER; + return DETACH_ABOVE_OR_BELOW; +} + +DockInfo TabDragController::GetDockInfoAtPoint(const gfx::Point& screen_point) { + // TODO: add support for dock info when |detach_into_browser_| is true. + if (attached_tabstrip_ || detach_into_browser_) { // If the mouse is over a tab strip, don't offer a dock position. return DockInfo(); } @@ -840,45 +968,53 @@ DockInfo DefaultTabDragController::GetDockInfoAtPoint( return dock_info_; } - gfx::NativeView dragged_hwnd = view_->GetWidget()->GetNativeView(); - dock_windows_.insert(dragged_hwnd); + gfx::NativeView dragged_view = view_->GetWidget()->GetNativeView(); + dock_windows_.insert(dragged_view); DockInfo info = DockInfo::GetDockInfoAtPoint(screen_point, dock_windows_); - dock_windows_.erase(dragged_hwnd); + dock_windows_.erase(dragged_view); return info; } -#if defined(OS_WIN) && !defined(USE_AURA) -TabStrip* DefaultTabDragController::GetTabStripForPoint( +TabStrip* TabDragController::GetTabStripForPoint( const gfx::Point& screen_point) { gfx::NativeView dragged_view = NULL; - if (view_.get()) { + if (view_.get()) dragged_view = view_->GetWidget()->GetNativeView(); + else if (is_dragging_window_) + dragged_view = attached_tabstrip_->GetWidget()->GetNativeView(); + if (dragged_view) dock_windows_.insert(dragged_view); - } gfx::NativeWindow local_window = DockInfo::GetLocalProcessWindowAtPoint(screen_point, dock_windows_); if (dragged_view) dock_windows_.erase(dragged_view); - if (!local_window) + TabStrip* tab_strip = GetTabStripForWindow(local_window); + if (tab_strip && DoesTabStripContain(tab_strip, screen_point)) + return tab_strip; + return is_dragging_window_ ? attached_tabstrip_ : NULL; +} + +TabStrip* TabDragController::GetTabStripForWindow(gfx::NativeWindow window) { + if (!window) return NULL; - BrowserView* browser = - BrowserView::GetBrowserViewForNativeWindow(local_window); + BrowserView* browser_view = + BrowserView::GetBrowserViewForNativeWindow(window); // We don't allow drops on windows that don't have tabstrips. - if (!browser || - !browser->browser()->SupportsWindowFeature(Browser::FEATURE_TABSTRIP)) + if (!browser_view || + !browser_view->browser()->SupportsWindowFeature( + Browser::FEATURE_TABSTRIP)) return NULL; - // This cast seems ugly, but the controller and the view are tighly coupled at - // creation time, so it will be okay. - TabStrip* other_tabstrip = static_cast<TabStrip*>(browser->tabstrip()); + TabStrip* other_tabstrip = browser_view->tabstrip(); + TabStrip* tab_strip = + attached_tabstrip_ ? attached_tabstrip_ : source_tabstrip_; + DCHECK(tab_strip); - if (!other_tabstrip->controller()->IsCompatibleWith(source_tabstrip_)) - return NULL; - return GetTabStripIfItContains(other_tabstrip, screen_point); + return other_tabstrip->controller()->IsCompatibleWith(tab_strip) ? + other_tabstrip : NULL; } -#endif -TabStrip* DefaultTabDragController::GetTabStripIfItContains( +bool TabDragController::DoesTabStripContain( TabStrip* tabstrip, const gfx::Point& screen_point) const { static const int kVerticalDetachMagnetism = 15; @@ -891,16 +1027,14 @@ TabStrip* DefaultTabDragController::GetTabStripIfItContains( // for the source TabStrip. int upper_threshold = tabstrip_bounds.bottom() + kVerticalDetachMagnetism; int lower_threshold = tabstrip_bounds.y() - kVerticalDetachMagnetism; - if (screen_point.y() >= lower_threshold && - screen_point.y() <= upper_threshold) { - return tabstrip; - } + return screen_point.y() >= lower_threshold && + screen_point.y() <= upper_threshold; } - return NULL; + return false; } -void DefaultTabDragController::Attach(TabStrip* attached_tabstrip, - const gfx::Point& screen_point) { +void TabDragController::Attach(TabStrip* attached_tabstrip, + const gfx::Point& screen_point) { DCHECK(!attached_tabstrip_); // We should already have detached by the time // we get here. @@ -913,20 +1047,22 @@ void DefaultTabDragController::Attach(TabStrip* attached_tabstrip, GetTabsMatchingDraggedContents(attached_tabstrip_); if (tabs.empty()) { - // There is no Tab in |attached_tabstrip| that corresponds to the dragged - // WebContents. We must now create one. + // Transitioning from detached to attached to a new tabstrip. Add tabs to + // the new model. selection_model_before_attach_.Copy(attached_tabstrip->GetSelectionModel()); - // Remove ourselves as the delegate now that the dragged WebContents is - // being inserted back into a Browser. - for (size_t i = 0; i < drag_data_.size(); ++i) { - drag_data_[i].contents->web_contents()->SetDelegate(NULL); - drag_data_[i].original_delegate = NULL; - } + if (!detach_into_browser_) { + // Remove ourselves as the delegate now that the dragged WebContents is + // being inserted back into a Browser. + for (size_t i = 0; i < drag_data_.size(); ++i) { + drag_data_[i].contents->web_contents()->SetDelegate(NULL); + drag_data_[i].original_delegate = NULL; + } - // Return the WebContents to normalcy. - source_dragged_contents()->web_contents()->SetCapturingContents(false); + // Return the WebContents to normalcy. + source_dragged_contents()->web_contents()->SetCapturingContents(false); + } // Inserting counts as a move. We don't want the tabs to jitter when the // user moves the tab immediately after attaching it. @@ -978,25 +1114,24 @@ void DefaultTabDragController::Attach(TabStrip* attached_tabstrip, tabs[source_tab_index_]->width()); mouse_offset_.set_x(new_x); - // Move the corresponding window to the front. - attached_tabstrip_->GetWidget()->Activate(); + // Redirect all mouse events to the TabStrip so that the tab that originated + // the drag can safely be deleted. + if (detach_into_browser_ || attached_tabstrip_ == source_tabstrip_) { + static_cast<views::internal::RootView*>( + attached_tabstrip_->GetWidget()->GetRootView())->SetMouseHandler( + attached_tabstrip_); + } } -void DefaultTabDragController::Detach() { +void TabDragController::Detach() { mouse_move_direction_ = kMovedMouseLeft | kMovedMouseRight; // Prevent the WebContents HWND from being hidden by any of the model // operations performed during the drag. - source_dragged_contents()->web_contents()->SetCapturingContents(true); - - // Calculate the drag bounds. - std::vector<gfx::Rect> drag_bounds; - std::vector<BaseTab*> attached_tabs; - for (size_t i = 0; i < drag_data_.size(); ++i) - attached_tabs.push_back(drag_data_[i].attached_tab); - attached_tabstrip_->CalculateBoundsForDraggedTabs(attached_tabs, - &drag_bounds); + if (!detach_into_browser_) + source_dragged_contents()->web_contents()->SetCapturingContents(true); + std::vector<gfx::Rect> drag_bounds = CalculateBoundsForDraggedTabs(0); TabStripModel* attached_model = GetModel(attached_tabstrip_); std::vector<TabRendererData> tab_data; for (size_t i = 0; i < drag_data_.size(); ++i) { @@ -1010,50 +1145,139 @@ void DefaultTabDragController::Detach() { attached_model->DetachTabContentsAt(index); // Detaching resets the delegate, but we still want to be the delegate. - drag_data_[i].contents->web_contents()->SetDelegate(this); + if (!detach_into_browser_) + drag_data_[i].contents->web_contents()->SetDelegate(this); // Detaching may end up deleting the tab, drop references to it. drag_data_[i].attached_tab = NULL; } // If we've removed the last Tab from the TabStrip, hide the frame now. - if (attached_model->empty()) { - HideFrame(); - } else if (!selection_model_before_attach_.empty() && - selection_model_before_attach_.active() >= 0 && - selection_model_before_attach_.active() < - attached_model->count()) { - // Restore the selection. - attached_model->SetSelectionFromModel(selection_model_before_attach_); - } else if (attached_tabstrip_ == source_tabstrip_ && - !initial_selection_model_.empty()) { - // First time detaching from the source tabstrip. Reset selection model to - // initial_selection_model_. Before resetting though we have to remove all - // the tabs from initial_selection_model_ as it was created with the tabs - // still there. - TabStripSelectionModel selection_model; - selection_model.Copy(initial_selection_model_); - for (DragData::const_reverse_iterator i = drag_data_.rbegin(); - i != drag_data_.rend(); ++i) { - selection_model.DecrementFrom(i->source_model_index); + if (!attached_model->empty()) { + if (!selection_model_before_attach_.empty() && + selection_model_before_attach_.active() >= 0 && + selection_model_before_attach_.active() < attached_model->count()) { + // Restore the selection. + attached_model->SetSelectionFromModel(selection_model_before_attach_); + } else if (attached_tabstrip_ == source_tabstrip_ && + !initial_selection_model_.empty()) { + // First time detaching from the source tabstrip. Reset selection model to + // initial_selection_model_. Before resetting though we have to remove all + // the tabs from initial_selection_model_ as it was created with the tabs + // still there. + TabStripSelectionModel selection_model; + selection_model.Copy(initial_selection_model_); + for (DragData::const_reverse_iterator i = drag_data_.rbegin(); + i != drag_data_.rend(); ++i) { + selection_model.DecrementFrom(i->source_model_index); + } + // We may have cleared out the selection model. Only reset it if it + // contains something. + if (!selection_model.empty()) + attached_model->SetSelectionFromModel(selection_model); } - // We may have cleared out the selection model. Only reset it if it contains - // something. - if (!selection_model.empty()) - attached_model->SetSelectionFromModel(selection_model); + } else if (!detach_into_browser_) { + HideFrame(); } // Create the dragged view. - CreateDraggedView(tab_data, drag_bounds); + if (!detach_into_browser_) + CreateDraggedView(tab_data, drag_bounds); attached_tabstrip_->DraggedTabsDetached(); attached_tabstrip_ = NULL; } -int DefaultTabDragController::GetInsertionIndexFrom( - const gfx::Rect& dragged_bounds, - int start, - int delta) const { +void TabDragController::DetachIntoNewBrowserAndRunMoveLoop( + const gfx::Point& screen_point) { + if (GetModel(attached_tabstrip_)->count() == + static_cast<int>(drag_data_.size())) { + // All the tabs in a browser are being dragged but all the tabs weren't + // initially being dragged. For this to happen the user would have to + // start dragging a set of tabs, the other tabs close, then detach. + RunMoveLoop(); + return; + } + + // Create a new browser to house the dragged tabs and have the OS run a move + // loop. + + gfx::Point attached_point = GetAttachedDragPoint(screen_point); + + // Calculate the bounds for the tabs from the attached_tab_strip. We do this + // so that the tabs don't change size when detached. + std::vector<gfx::Rect> drag_bounds = + CalculateBoundsForDraggedTabs(attached_point.x()); + + Browser* browser = CreateBrowserForDrag( + attached_tabstrip_, screen_point, &drag_bounds); + attached_tabstrip_->ReleaseDragController(); + Detach(); + BrowserView* dragged_browser_view = + BrowserView::GetBrowserViewForBrowser(browser); + dragged_browser_view->GetWidget()->SetVisibilityChangedAnimationsEnabled( + false); + Attach(dragged_browser_view->tabstrip(), gfx::Point()); + attached_tabstrip_->OwnDragController(this); + // TODO: come up with a cleaner way to do this. + attached_tabstrip_->SetTabBoundsForDrag(drag_bounds); + + browser->window()->Show(); + browser->window()->Activate(); + dragged_browser_view->GetWidget()->SetVisibilityChangedAnimationsEnabled( + true); + RunMoveLoop(); +} + +void TabDragController::RunMoveLoop() { + move_loop_widget_ = GetAttachedBrowserWidget(); + move_loop_widget_->AddObserver(this); + is_dragging_window_ = true; + bool destroyed = false; + destroyed_ = &destroyed; + // Running the move loop releases mouse capture on windows, which triggers + // destroying the drag loop. Release mouse capture ourself before this while + // the DragController isn't owned by the TabStrip. + attached_tabstrip_->ReleaseDragController(); + attached_tabstrip_->GetWidget()->ReleaseMouseCapture(); + attached_tabstrip_->OwnDragController(this); + views::Widget::MoveLoopResult result = move_loop_widget_->RunMoveLoop(); + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE, + content::NotificationService::AllBrowserContextsAndSources(), + content::NotificationService::NoDetails()); + + if (destroyed) + return; + destroyed_ = NULL; + // Under chromeos we immediately set the |move_loop_widget_| to NULL. + if (move_loop_widget_) { + move_loop_widget_->RemoveObserver(this); + move_loop_widget_ = NULL; + } + is_dragging_window_ = false; + waiting_for_run_loop_to_exit_ = false; + if (end_run_loop_behavior_ == END_RUN_LOOP_CONTINUE_DRAGGING) { + end_run_loop_behavior_ = END_RUN_LOOP_STOP_DRAGGING; + if (tab_strip_to_attach_to_after_exit_) { + Detach(); + gfx::Point screen_point(GetCursorScreenPoint()); + Attach(tab_strip_to_attach_to_after_exit_, screen_point); + // Move the tabs into position. + MoveAttached(screen_point); + attached_tabstrip_->GetWidget()->Activate(); + tab_strip_to_attach_to_after_exit_ = NULL; + } + DCHECK(attached_tabstrip_); + attached_tabstrip_->GetWidget()->SetMouseCapture(attached_tabstrip_); + } else if (active_) { + EndDrag(result == views::Widget::MOVE_LOOP_CANCELED); + } +} + +int TabDragController::GetInsertionIndexFrom(const gfx::Rect& dragged_bounds, + int start, + int delta) const { for (int i = start, tab_count = attached_tabstrip_->tab_count(); i >= 0 && i < tab_count; i += delta) { const gfx::Rect& ideal_bounds = attached_tabstrip_->ideal_bounds(i); @@ -1070,7 +1294,7 @@ int DefaultTabDragController::GetInsertionIndexFrom( return -1; } -int DefaultTabDragController::GetInsertionIndexForDraggedBounds( +int TabDragController::GetInsertionIndexForDraggedBounds( const gfx::Rect& dragged_bounds) const { int index = -1; if (attached_tabstrip_->touch_layout_.get()) { @@ -1112,7 +1336,7 @@ int DefaultTabDragController::GetInsertionIndexForDraggedBounds( return std::max(0, std::min(max_index, index)); } -bool DefaultTabDragController::ShouldDragToNextStackedTab( +bool TabDragController::ShouldDragToNextStackedTab( const gfx::Rect& dragged_bounds, int index) const { if (index + 1 >= attached_tabstrip_->tab_count() || @@ -1127,7 +1351,7 @@ bool DefaultTabDragController::ShouldDragToNextStackedTab( return dragged_bounds.x() >= mid_x; } -bool DefaultTabDragController::ShouldDragToPreviousStackedTab( +bool TabDragController::ShouldDragToPreviousStackedTab( const gfx::Rect& dragged_bounds, int index) const { if (index - 1 < attached_tabstrip_->GetMiniTabCount() || @@ -1142,7 +1366,7 @@ bool DefaultTabDragController::ShouldDragToPreviousStackedTab( return dragged_bounds.x() <= mid_x; } -int DefaultTabDragController::GetInsertionIndexForDraggedBoundsStacked( +int TabDragController::GetInsertionIndexForDraggedBoundsStacked( const gfx::Rect& dragged_bounds) const { TouchTabStripLayout* touch_layout = attached_tabstrip_->touch_layout_.get(); int active_index = touch_layout->active_index(); @@ -1171,7 +1395,7 @@ int DefaultTabDragController::GetInsertionIndexForDraggedBoundsStacked( return index; } -gfx::Rect DefaultTabDragController::GetDraggedViewTabStripBounds( +gfx::Rect TabDragController::GetDraggedViewTabStripBounds( const gfx::Point& tab_strip_point) { // attached_tab is NULL when inserting into a new tabstrip. if (source_tab_drag_data()->attached_tab) { @@ -1181,14 +1405,13 @@ gfx::Rect DefaultTabDragController::GetDraggedViewTabStripBounds( } double sel_width, unselected_width; - static_cast<TabStrip*>(attached_tabstrip_)->GetCurrentTabWidths( - &sel_width, &unselected_width); + attached_tabstrip_->GetCurrentTabWidths(&sel_width, &unselected_width); return gfx::Rect(tab_strip_point.x(), tab_strip_point.y(), static_cast<int>(sel_width), Tab::GetStandardSize().height()); } -gfx::Point DefaultTabDragController::GetAttachedDragPoint( +gfx::Point TabDragController::GetAttachedDragPoint( const gfx::Point& screen_point) { DCHECK(attached_tabstrip_); // The tab must be attached. @@ -1206,7 +1429,7 @@ gfx::Point DefaultTabDragController::GetAttachedDragPoint( return gfx::Point(std::min(std::max(x, 0), max_x), 0); } -std::vector<BaseTab*> DefaultTabDragController::GetTabsMatchingDraggedContents( +std::vector<BaseTab*> TabDragController::GetTabsMatchingDraggedContents( TabStrip* tabstrip) { TabStripModel* model = GetModel(attached_tabstrip_); std::vector<BaseTab*> tabs; @@ -1219,12 +1442,37 @@ std::vector<BaseTab*> DefaultTabDragController::GetTabsMatchingDraggedContents( return tabs; } -void DefaultTabDragController::EndDragImpl(EndDragType type) { +std::vector<gfx::Rect> TabDragController::CalculateBoundsForDraggedTabs( + int x_offset) { + std::vector<gfx::Rect> drag_bounds; + std::vector<BaseTab*> attached_tabs; + for (size_t i = 0; i < drag_data_.size(); ++i) + attached_tabs.push_back(drag_data_[i].attached_tab); + attached_tabstrip_->CalculateBoundsForDraggedTabs(attached_tabs, + &drag_bounds); + if (x_offset != 0) { + for (size_t i = 0; i < drag_bounds.size(); ++i) + drag_bounds[i].set_x(drag_bounds[i].x() + x_offset); + } + return drag_bounds; +} + +void TabDragController::EndDragImpl(EndDragType type) { + DCHECK(active_); active_ = false; bring_to_front_timer_.Stop(); move_stacked_timer_.Stop(); + if (is_dragging_window_) { + if (type == NORMAL || (type == TAB_DESTROYED && drag_data_.size() > 1)) + SetTrackedByWorkspace(GetAttachedBrowserWidget()->GetNativeView(), true); + + // End the nested drag loop. + GetAttachedBrowserWidget()->EndMoveLoop(); + waiting_for_run_loop_to_exit_ = true; + } + // Hide the current dock controllers. for (size_t i = 0; i < dock_controllers_.size(); ++i) { // Be sure and clear the controller first, that way if Hide ends up @@ -1250,15 +1498,18 @@ void DefaultTabDragController::EndDragImpl(EndDragType type) { RevertDrag(); } // else case the only tab we were dragging was deleted. Nothing to do. - ResetDelegates(); + if (!detach_into_browser_) + ResetDelegates(); // Clear out drag data so we don't attempt to do anything with it. drag_data_.clear(); - source_tabstrip_->DestroyDragController(); + TabStrip* owning_tabstrip = (attached_tabstrip_ && detach_into_browser_) ? + attached_tabstrip_ : source_tabstrip_; + owning_tabstrip->DestroyDragController(); } -void DefaultTabDragController::RevertDrag() { +void TabDragController::RevertDrag() { std::vector<BaseTab*> tabs; for (size_t i = 0; i < drag_data_.size(); ++i) { if (drag_data_[i].contents) { @@ -1268,36 +1519,31 @@ void DefaultTabDragController::RevertDrag() { } } - bool restore_frame = attached_tabstrip_ != source_tabstrip_; - if (attached_tabstrip_ && attached_tabstrip_ == source_tabstrip_) - source_tabstrip_->StoppedDraggingTabs(tabs); - - attached_tabstrip_ = source_tabstrip_; - - if (initial_selection_model_.empty()) { - ResetSelection(GetModel(attached_tabstrip_)); - } else { - GetModel(attached_tabstrip_)->SetSelectionFromModel( - initial_selection_model_); + bool restore_frame = !detach_into_browser_ && + attached_tabstrip_ != source_tabstrip_; + if (attached_tabstrip_) { + if (attached_tabstrip_ == source_tabstrip_) + source_tabstrip_->StoppedDraggingTabs(tabs); + else + attached_tabstrip_->DraggedTabsDetached(); } + if (initial_selection_model_.empty()) + ResetSelection(GetModel(source_tabstrip_)); + else + GetModel(source_tabstrip_)->SetSelectionFromModel(initial_selection_model_); + // If we're not attached to any TabStrip, or attached to some other TabStrip, // we need to restore the bounds of the original TabStrip's frame, in case // it has been hidden. - if (restore_frame) { - if (!restore_bounds_.IsEmpty()) { -#if defined(OS_WIN) && !defined(USE_AURA) - HWND frame_hwnd = source_tabstrip_->GetWidget()->GetNativeView(); - MoveWindow(frame_hwnd, restore_bounds_.x(), restore_bounds_.y(), - restore_bounds_.width(), restore_bounds_.height(), TRUE); -#else - NOTIMPLEMENTED(); -#endif - } - } + if (restore_frame && !restore_bounds_.IsEmpty()) + source_tabstrip_->GetWidget()->SetBounds(restore_bounds_); + + if (detach_into_browser_ && source_tabstrip_) + source_tabstrip_->GetWidget()->Activate(); } -void DefaultTabDragController::ResetSelection(TabStripModel* model) { +void TabDragController::ResetSelection(TabStripModel* model) { DCHECK(model); TabStripSelectionModel selection_model; bool has_one_valid_tab = false; @@ -1322,7 +1568,7 @@ void DefaultTabDragController::ResetSelection(TabStripModel* model) { model->SetSelectionFromModel(selection_model); } -void DefaultTabDragController::RevertDragAt(size_t drag_index) { +void TabDragController::RevertDragAt(size_t drag_index) { DCHECK(started_drag_); TabDragData* data = &(drag_data_[drag_index]); @@ -1354,7 +1600,7 @@ void DefaultTabDragController::RevertDragAt(size_t drag_index) { } } -void DefaultTabDragController::CompleteDrag() { +void TabDragController::CompleteDrag() { DCHECK(started_drag_); if (attached_tabstrip_) { @@ -1439,7 +1685,8 @@ void DefaultTabDragController::CompleteDrag() { CleanUpHiddenFrame(); } -void DefaultTabDragController::ResetDelegates() { +void TabDragController::ResetDelegates() { + DCHECK(!detach_into_browser_); for (size_t i = 0; i < drag_data_.size(); ++i) { if (drag_data_[i].contents && drag_data_[i].contents->web_contents()->GetDelegate() == this) { @@ -1449,7 +1696,7 @@ void DefaultTabDragController::ResetDelegates() { } } -void DefaultTabDragController::CreateDraggedView( +void TabDragController::CreateDraggedView( const std::vector<TabRendererData>& data, const std::vector<gfx::Rect>& renderer_bounds) { #if !defined(USE_AURA) @@ -1476,12 +1723,12 @@ void DefaultTabDragController::CreateDraggedView( view_.reset(new DraggedTabView(renderers, renderer_bounds, mouse_offset_, content_bounds.size(), photobooth)); #else - // TODO(beng): - NOTIMPLEMENTED(); + // Aura always hits the |detach_into_browser_| path. + NOTREACHED(); #endif } -gfx::Point DefaultTabDragController::GetCursorScreenPoint() const { +gfx::Point TabDragController::GetCursorScreenPoint() const { // TODO(sky): see if we can convert to using Screen every where. #if defined(OS_WIN) && !defined(USE_AURA) DWORD pos = GetMessagePos(); @@ -1491,7 +1738,7 @@ gfx::Point DefaultTabDragController::GetCursorScreenPoint() const { #endif } -gfx::Rect DefaultTabDragController::GetViewScreenBounds( +gfx::Rect TabDragController::GetViewScreenBounds( views::View* view) const { gfx::Point view_topleft; views::View::ConvertPointToScreen(view, &view_topleft); @@ -1500,7 +1747,7 @@ gfx::Rect DefaultTabDragController::GetViewScreenBounds( return view_screen_bounds; } -void DefaultTabDragController::HideFrame() { +void TabDragController::HideFrame() { #if defined(OS_WIN) && !defined(USE_AURA) // We don't actually hide the window, rather we just move it way off-screen. // If we actually hide it, we stop receiving drag events. @@ -1514,18 +1761,19 @@ void DefaultTabDragController::HideFrame() { // the drag session is aborted we can restore them. restore_bounds_ = gfx::Rect(wr); #else - NOTIMPLEMENTED(); + // Shouldn't hit as aura triggers the |detach_into_browser_| path. + NOTREACHED(); #endif } -void DefaultTabDragController::CleanUpHiddenFrame() { +void TabDragController::CleanUpHiddenFrame() { // If the model we started dragging from is now empty, we must ask the // delegate to close the frame. - if (GetModel(source_tabstrip_)->empty()) + if (!detach_into_browser_ && GetModel(source_tabstrip_)->empty()) GetModel(source_tabstrip_)->delegate()->CloseFrameAfterDragSession(); } -void DefaultTabDragController::DockDisplayerDestroyed( +void TabDragController::DockDisplayerDestroyed( DockDisplayer* controller) { DockWindows::iterator dock_i = dock_windows_.find(controller->popup_view()); @@ -1543,39 +1791,50 @@ void DefaultTabDragController::DockDisplayerDestroyed( NOTREACHED(); } -void DefaultTabDragController::BringWindowUnderMouseToFront() { +void TabDragController::BringWindowUnderMouseToFront() { // If we're going to dock to another window, bring it to the front. gfx::NativeWindow window = dock_info_.window(); if (!window) { - gfx::NativeView dragged_view = view_->GetWidget()->GetNativeView(); - dock_windows_.insert(dragged_view); + views::View* dragged_view; + if (view_.get()) + dragged_view = view_.get(); + else + dragged_view = attached_tabstrip_; + gfx::NativeView dragged_native_view = + dragged_view->GetWidget()->GetNativeView(); + dock_windows_.insert(dragged_native_view); window = DockInfo::GetLocalProcessWindowAtPoint(GetCursorScreenPoint(), dock_windows_); - dock_windows_.erase(dragged_view); + dock_windows_.erase(dragged_native_view); } if (window) { -#if defined(OS_WIN) && !defined(USE_AURA) - // Move the window to the front. - SetWindowPos(window, HWND_TOP, 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + views::Widget* widget_window = views::Widget::GetWidgetForNativeView( + window); + if (widget_window) + widget_window->StackAtTop(); + else + return; // The previous call made the window appear on top of the dragged window, // move the dragged window to the front. - SetWindowPos(view_->GetWidget()->GetNativeView(), HWND_TOP, 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); -#else - NOTIMPLEMENTED(); -#endif + if (view_.get()) + view_->GetWidget()->StackAtTop(); + else if (is_dragging_window_) + attached_tabstrip_->GetWidget()->StackAtTop(); } } -TabStripModel* DefaultTabDragController::GetModel( +TabStripModel* TabDragController::GetModel( TabStrip* tabstrip) const { return static_cast<BrowserTabStripController*>(tabstrip->controller())-> model(); } -bool DefaultTabDragController::AreTabsConsecutive() { +views::Widget* TabDragController::GetAttachedBrowserWidget() { + return attached_tabstrip_->GetWidget(); +} + +bool TabDragController::AreTabsConsecutive() { for (size_t i = 1; i < drag_data_.size(); ++i) { if (drag_data_[i - 1].source_model_index + 1 != drag_data_[i].source_model_index) { @@ -1585,58 +1844,37 @@ bool DefaultTabDragController::AreTabsConsecutive() { return true; } -#if defined(USE_AURA) || defined(OS_WIN) -static bool ShouldCreateTabDragController2() { -#if defined(USE_AURA) - return true; -#else - return CommandLine::ForCurrentProcess()->HasSwitch( - switches::kTabBrowserDragging); -#endif -} -#endif +Browser* TabDragController::CreateBrowserForDrag( + TabStrip* source, + const gfx::Point& screen_point, + std::vector<gfx::Rect>* drag_bounds) { + Browser* browser = Browser::Create(drag_data_[0].contents->profile()); + gfx::Point center(0, source->height() / 2); + views::View::ConvertPointToWidget(source, ¢er); + gfx::Rect new_bounds(source->GetWidget()->GetWindowScreenBounds()); + new_bounds.set_y(screen_point.y() - center.y()); + switch (GetDetachPosition(screen_point)) { + case DETACH_BEFORE: + new_bounds.set_x(screen_point.x() - center.x()); + new_bounds.Offset(-mouse_offset_.x(), 0); + break; + + case DETACH_AFTER: { + gfx::Point right_edge(source->width(), 0); + views::View::ConvertPointToWidget(source, &right_edge); + new_bounds.set_x(screen_point.x() - right_edge.x()); + new_bounds.Offset(drag_bounds->back().right() - mouse_offset_.x(), 0); + int delta = (*drag_bounds)[0].x(); + for (size_t i = 0; i < drag_bounds->size(); ++i) + (*drag_bounds)[i].Offset(-delta, 0); + break; + } -// static -TabDragController* TabDragController::Create( - TabStrip* source_tabstrip, - BaseTab* source_tab, - const std::vector<BaseTab*>& tabs, - const gfx::Point& mouse_offset, - int source_tab_offset, - const TabStripSelectionModel& initial_selection_model, - bool move_only) { -#if defined(USE_AURA) || defined(OS_WIN) - if (ShouldCreateTabDragController2()) { - TabDragController2* controller = new TabDragController2; - // TODO: get TabDragController2 working with move_only. - controller->Init(source_tabstrip, source_tab, tabs, mouse_offset, - source_tab_offset, initial_selection_model); - return controller; + default: + break; // Nothing to do for DETACH_ABOVE_OR_BELOW. } -#endif - DefaultTabDragController* controller = new DefaultTabDragController; - controller->Init(source_tabstrip, source_tab, tabs, mouse_offset, - source_tab_offset, initial_selection_model, move_only); - return controller; -} - -// static -bool TabDragController::IsAttachedTo(TabStrip* tab_strip) { -#if defined(USE_AURA) || defined(OS_WIN) - return TabDragController2::IsActiveAndAttachedTo(tab_strip) || - (instance_ && instance_->active() && - instance_->attached_tabstrip() == tab_strip); -#else - return (instance_ && instance_->active() && - instance_->attached_tabstrip() == tab_strip); -#endif -} -// static -bool TabDragController::IsActive() { -#if defined(USE_AURA) || defined(OS_WIN) - return TabDragController2::IsActive() || (instance_ && instance_->active()); -#else - return instance_ && instance_->active(); -#endif + SetTrackedByWorkspace(browser->window()->GetNativeHandle(), false); + browser->window()->SetBounds(new_bounds); + return browser; } diff --git a/chrome/browser/ui/views/tabs/default_tab_drag_controller.h b/chrome/browser/ui/views/tabs/default_tab_drag_controller.h index f296fed..81bc8f4 100644 --- a/chrome/browser/ui/views/tabs/default_tab_drag_controller.h +++ b/chrome/browser/ui/views/tabs/default_tab_drag_controller.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_VIEWS_TABS_DEFAULT_TAB_DRAG_CONTROLLER_H_ -#define CHROME_BROWSER_UI_VIEWS_TABS_DEFAULT_TAB_DRAG_CONTROLLER_H_ +#ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER_H_ +#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER_H_ #pragma once #include <vector> @@ -11,36 +11,53 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "base/timer.h" +#include "chrome/browser/tabs/tab_strip_model_observer.h" #include "chrome/browser/tabs/tab_strip_selection_model.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/browser/ui/tabs/dock_info.h" -#include "chrome/browser/ui/views/tabs/tab_drag_controller.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_delegate.h" #include "ui/gfx/rect.h" +#include "ui/views/widget/widget.h" namespace views { class View; } class BaseTab; +class Browser; class DraggedTabView; +struct TabRendererData; class TabStrip; class TabStripModel; - -struct TabRendererData; - -// TabDragController implementation that creates a widget representing the -// dragged tabs when detached (dragged out of the source window). -class DefaultTabDragController : public TabDragController, - public content::WebContentsDelegate, - public content::NotificationObserver, - public MessageLoopForUI::Observer { +class TabStripSelectionModel; + +// TabDragController is responsible for managing the tab dragging session. When +// the user presses the mouse on a tab a new TabDragController is created and +// Drag() is invoked as the mouse is dragged. If the mouse is dragged far enough +// TabDragController starts a drag session. The drag session is completed when +// EndDrag() is invoked (or the TabDragController is destroyed). +// +// While dragging within a tab strip TabDragController sets the bounds of the +// tabs (this is referred to as attached). When the user drags far enough such +// that the tabs should be moved out of the tab strip two possible things +// can happen (this state is referred to as detached): +// . If |detach_into_browser_| is true then a new Browser is created and +// RunMoveLoop() is invoked on the Widget to drag the browser around. This is +// the default on chromeos and can be enabled on windows with a flag. +// . If |detach_into_browser_| is false a small representation of the active tab +// is created and that is dragged around. This mode does not run a nested +// message loop. +class TabDragController : public content::WebContentsDelegate, + public content::NotificationObserver, + public MessageLoopForUI::Observer, + public views::Widget::Observer, + public TabStripModelObserver { public: - DefaultTabDragController(); - virtual ~DefaultTabDragController(); + TabDragController(); + virtual ~TabDragController(); - // Initializes DefaultTabDragController to drag the tabs in |tabs| originating + // Initializes TabDragController to drag the tabs in |tabs| originating // from |source_tabstrip|. |source_tab| is the tab that initiated the drag and // is contained in |tabs|. |mouse_offset| is the distance of the mouse // pointer from the origin of the first tab in |tabs| and |source_tab_offset| @@ -57,10 +74,31 @@ class DefaultTabDragController : public TabDragController, const TabStripSelectionModel& initial_selection_model, bool move_only); + // Returns true if there is a drag underway and the drag is attached to + // |tab_strip|. + // NOTE: this returns false if the TabDragController is in the process of + // finishing the drag. + static bool IsAttachedTo(TabStrip* tab_strip); + + // Returns true if there is a drag underway. + static bool IsActive(); + // See description above fields for details on these. bool active() const { return active_; } const TabStrip* attached_tabstrip() const { return attached_tabstrip_; } + // Returns true if a drag started. + bool started_drag() const { return started_drag_; } + + // Invoked as the mouse is dragged. 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 and the drag is reverted. + void EndDrag(bool canceled); + private: class DockDisplayer; friend class DockDisplayer; @@ -83,6 +121,33 @@ class DefaultTabDragController : public TabDragController, TAB_DESTROYED }; + // Specifies what should happen when RunMoveLoop completes. + enum EndRunLoopBehavior { + // Indicates the drag should end. + END_RUN_LOOP_STOP_DRAGGING, + + // Indicates the drag should continue. + END_RUN_LOOP_CONTINUE_DRAGGING + }; + + // Enumeration of the possible positions the detached tab may detach from. + enum DetachPosition { + DETACH_BEFORE, + DETACH_AFTER, + DETACH_ABOVE_OR_BELOW + }; + + // Indicates what should happen after invoking DragBrowserToNewTabStrip(). + enum DragBrowserResultType { + // The caller should return immediately. This return value is used if a + // nested message loop was created or we're in a nested message loop and + // need to exit it. + DRAG_BROWSER_RESULT_STOP, + + // The caller should continue. + DRAG_BROWSER_RESULT_CONTINUE, + }; + // Stores the date associated with a single tab that is being dragged. struct TabDragData { TabDragData(); @@ -114,11 +179,6 @@ class DefaultTabDragController : public TabDragController, // notifications and resets the delegate of the TabContentsWrapper. void InitTabDragData(BaseTab* tab, TabDragData* drag_data); - // TabDragController overrides: - virtual void Drag() OVERRIDE; - virtual void EndDrag(bool canceled) OVERRIDE; - virtual bool GetStartedDrag() const OVERRIDE; - // Overridden from content::WebContentsDelegate: virtual content::WebContents* OpenURLFromTab( content::WebContents* source, @@ -141,11 +201,15 @@ class DefaultTabDragController : public TabDragController, const content::NotificationDetails& details) OVERRIDE; // Overridden from MessageLoop::Observer: -#if defined(OS_WIN) || defined(USE_AURA) virtual base::EventStatus WillProcessEvent( const base::NativeEvent& event) OVERRIDE; virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE; -#endif + + // Overriden from views::Widget::Observer: + virtual void OnWidgetMoved(views::Widget* widget) OVERRIDE; + + // Overriden from TabStripModelObserver: + virtual void TabStripEmpty() OVERRIDE; // Initialize the offset used to calculate the position to create windows // in |GetWindowCreatePoint|. This should only be invoked from |Init|. @@ -173,6 +237,13 @@ class DefaultTabDragController : public TabDragController, // potentially updating the source and other TabStrips. void ContinueDragging(); + // Transitions dragging from |attached_tabstrip_| to |target_tabstrip|. + // |target_tabstrip| is NULL if the mouse is not over a valid tab strip. See + // DragBrowserResultType for details of the return type. + DragBrowserResultType DragBrowserToNewTabStrip( + TabStrip* target_tabstrip, + const gfx::Point& screen_point); + // Handles dragging for a touch tabstrip when the tabs are stacked. Doesn't // actually reorder the tabs in anyway, just changes what's visible. void DragActiveTabStacked(const gfx::Point& screen_point); @@ -192,18 +263,24 @@ class DefaultTabDragController : public TabDragController, // close enough to an edge with stacked tabs. void StartMoveStackedTimerIfNecessary(int delay_ms); -#if defined(OS_WIN) && !defined(USE_AURA) + // Returns the TabStrip for the specified window, or NULL if one doesn't exist + // or isn't compatible. + TabStrip* GetTabStripForWindow(gfx::NativeWindow window); + // Returns the compatible TabStrip that is under the specified point (screen // coordinates), or NULL if there is none. TabStrip* GetTabStripForPoint(const gfx::Point& screen_point); -#endif - DockInfo GetDockInfoAtPoint(const gfx::Point& screen_point); + // Returns true if |tabstrip| contains the specified point in screen + // coordinates. + bool DoesTabStripContain(TabStrip* tabstrip, + const gfx::Point& screen_point) const; + + // Returns the DetachPosition given the specified location in screen + // coordinates. + DetachPosition GetDetachPosition(const gfx::Point& screen_point); - // Returns the specified |tabstrip| if it contains the specified point - // (screen coordinates), NULL if it does not. - TabStrip* GetTabStripIfItContains(TabStrip* tabstrip, - const gfx::Point& screen_point) const; + DockInfo GetDockInfoAtPoint(const gfx::Point& screen_point); // Attach the dragged Tab to the specified TabStrip. void Attach(TabStrip* attached_tabstrip, const gfx::Point& screen_point); @@ -211,6 +288,13 @@ class DefaultTabDragController : public TabDragController, // Detach the dragged Tab from the current TabStrip. void Detach(); + // Detaches the tabs being dragged, creates a new Browser to contain them and + // runs a nested move loop. + void DetachIntoNewBrowserAndRunMoveLoop(const gfx::Point& screen_point); + + // Runs a nested message loop that handles moving the current Browser. + void RunMoveLoop(); + // Determines the index to insert tabs at. |dragged_bounds| is the bounds of // the tabs being dragged, |start| the index of the tab to start looking from // and |delta| the amount to increment (1 or -1). @@ -252,6 +336,10 @@ class DefaultTabDragController : public TabDragController, // WebContents of the dragged tabs. Returns an empty vector if not attached. std::vector<BaseTab*> GetTabsMatchingDraggedContents(TabStrip* tabstrip); + // Returns the bounds for the tabs based on the attached tab strip. The + // x-coordinate of each tab is offset by |x_offset|. + std::vector<gfx::Rect> CalculateBoundsForDraggedTabs(int x_offset); + // 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); @@ -305,13 +393,24 @@ class DefaultTabDragController : public TabDragController, return source_tab_drag_data()->contents; } + // Returns the Widget of the currently attached TabStrip's BrowserView. + views::Widget* GetAttachedBrowserWidget(); + // Returns true if the tabs were originality one after the other in // |source_tabstrip_|. bool AreTabsConsecutive(); + // Creates and returns a new Browser to handle the drag. + Browser* CreateBrowserForDrag(TabStrip* source, + const gfx::Point& screen_point, + std::vector<gfx::Rect>* drag_bounds); + // Returns the TabStripModel for the specified tabstrip. TabStripModel* GetModel(TabStrip* tabstrip) const; + // If true Detaching creates a new browser and enters a nested message loop. + const bool detach_into_browser_; + // Handles registering for notifications. content::NotificationRegistrar registrar_; @@ -378,11 +477,11 @@ class DefaultTabDragController : public TabDragController, // 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<DefaultTabDragController> bring_to_front_timer_; + base::OneShotTimer<TabDragController> bring_to_front_timer_; // Timer used to move the stacked tabs. See comment aboue // StartMoveStackedTimerIfNecessary(). - base::OneShotTimer<DefaultTabDragController> move_stacked_timer_; + base::OneShotTimer<TabDragController> move_stacked_timer_; // Did the mouse move enough that we started a drag? bool started_drag_; @@ -420,7 +519,28 @@ class DefaultTabDragController : public TabDragController, // Coordinate last used in MoveAttached(). gfx::Point last_screen_point_; - DISALLOW_COPY_AND_ASSIGN(DefaultTabDragController); + // The following are needed when detaching into a browser + // (|detach_into_browser_| is true). + + // Set to true if we've detached from a tabstrip and are running a nested + // move message loop. + bool is_dragging_window_; + + EndRunLoopBehavior end_run_loop_behavior_; + + // If true, we're waiting for a move loop to complete. + bool waiting_for_run_loop_to_exit_; + + // The TabStrip to attach to after the move loop completes. + TabStrip* tab_strip_to_attach_to_after_exit_; + + // Non-null for the duration of RunMoveLoop. + views::Widget* move_loop_widget_; + + // If non-null set to true from destructor. + bool* destroyed_; + + DISALLOW_COPY_AND_ASSIGN(TabDragController); }; -#endif // CHROME_BROWSER_UI_VIEWS_TABS_DEFAULT_TAB_DRAG_CONTROLLER_H_ +#endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER_H_ diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.h b/chrome/browser/ui/views/tabs/tab_drag_controller.h deleted file mode 100644 index 7d0df87..0000000 --- a/chrome/browser/ui/views/tabs/tab_drag_controller.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2012 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_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER_H_ -#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER_H_ -#pragma once - -#include <vector> - -class BaseTab; -class TabStrip; -class TabStripSelectionModel; - -namespace gfx { -class Point; -} - -/////////////////////////////////////////////////////////////////////////////// -// -// TabDragController -// -// An object that handles a drag session for a set of Tabs 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 TabStrip that the drag originated from owns this object. -// -/////////////////////////////////////////////////////////////////////////////// -class TabDragController { - public: - virtual ~TabDragController() {} - - // Creates and returns a new TabDragController to drag the tabs in |tabs| - // originating from |source_tabstrip|. |source_tab| is the tab that initiated - // the drag (the one the user pressed the moused down on) and is contained in - // |tabs|. |mouse_offset| is the distance of the mouse pointer from the - // origin of the first tab in |tabs| and |source_tab_offset| the offset from - // |source_tab| (along the horizontal axis). |initial_selection_model| is the - // selection model before the drag started and is only non-empty if - // |source_tab| was not initially selected. |move_only| is true if the drag - // is the result of a touch event. - static TabDragController* Create( - TabStrip* source_tabstrip, - BaseTab* source_tab, - const std::vector<BaseTab*>& tabs, - const gfx::Point& mouse_offset, - int source_tab_offset, - const TabStripSelectionModel& initial_selection_model, - bool move_only); - - // Returns true if there is a drag underway and the drag is attached to - // |tab_strip|. - // NOTE: this returns false if the TabDragController is in the process of - // finishing the drag. - static bool IsAttachedTo(TabStrip* tab_strip); - - // Returns true if there is a drag underway. - static bool IsActive(); - - // Responds to drag events subsequent to StartDrag. If the mouse moves a - // sufficient distance before the mouse is released, a drag session is - // initiated. - virtual void Drag() = 0; - - // 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. - virtual void EndDrag(bool canceled) = 0; - - // Returns true if a drag started. - virtual bool GetStartedDrag() const = 0; -}; - -#endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER_H_ diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller2.cc b/chrome/browser/ui/views/tabs/tab_drag_controller2.cc deleted file mode 100644 index 5ace1e8..0000000 --- a/chrome/browser/ui/views/tabs/tab_drag_controller2.cc +++ /dev/null @@ -1,1425 +0,0 @@ -// Copyright (c) 2012 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. - -#include "chrome/browser/ui/views/tabs/tab_drag_controller2.h" - -#include <math.h> -#include <set> - -#include "base/callback.h" -#include "base/i18n/rtl.h" -#include "chrome/browser/extensions/extension_function_dispatcher.h" -#include "chrome/browser/tabs/tab_strip_model.h" -#include "chrome/browser/ui/app_modal_dialogs/message_box_handler.h" -#include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" -#include "chrome/browser/ui/views/frame/browser_view.h" -#include "chrome/browser/ui/views/tabs/base_tab.h" -#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h" -#include "chrome/browser/ui/views/tabs/dragged_tab_view.h" -#include "chrome/browser/ui/views/tabs/tab.h" -#include "chrome/browser/ui/views/tabs/tab_strip.h" -#include "chrome/common/chrome_notification_types.h" -#include "content/public/browser/notification_details.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/notification_source.h" -#include "content/public/browser/notification_types.h" -#include "content/public/browser/user_metrics.h" -#include "content/public/browser/web_contents.h" -#include "grit/theme_resources.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/base/animation/animation.h" -#include "ui/base/animation/animation_delegate.h" -#include "ui/base/animation/slide_animation.h" -#include "ui/base/events.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/screen.h" -#include "ui/views/events/event.h" -#include "ui/views/widget/root_view.h" - -#if defined(USE_ASH) -#include "ash/wm/property_util.h" -#endif - -using content::UserMetricsAction; -using content::WebContents; - -static const int kHorizontalMoveThreshold = 16; // Pixels. - -// If non-null there is a drag underway. -static TabDragController2* instance_; - -namespace { - -// Delay, in ms, during dragging before we bring a window to front. -const int kBringToFrontDelay = 750; - -// Radius of the rect drawn by DockView. -const int kRoundedRectRadius = 4; - -// Spacing between tab icons when DockView is showing a docking location that -// contains more than one tab. -const int kTabSpacing = 4; - -// DockView is the view responsible for giving a visual indicator of where a -// dock is going to occur. - -class DockView : public views::View { - public: - explicit DockView(DockInfo::Type type) : type_(type) {} - - virtual gfx::Size GetPreferredSize() { - return gfx::Size(DockInfo::popup_width(), DockInfo::popup_height()); - } - - virtual void OnPaintBackground(gfx::Canvas* canvas) { - SkRect outer_rect = { SkIntToScalar(0), SkIntToScalar(0), - SkIntToScalar(width()), - SkIntToScalar(height()) }; - - // Fill the background rect. - SkPaint paint; - paint.setColor(SkColorSetRGB(108, 108, 108)); - paint.setStyle(SkPaint::kFill_Style); - canvas->sk_canvas()->drawRoundRect( - outer_rect, SkIntToScalar(kRoundedRectRadius), - SkIntToScalar(kRoundedRectRadius), paint); - - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - - SkBitmap* high_icon = rb.GetBitmapNamed(IDR_DOCK_HIGH); - SkBitmap* wide_icon = rb.GetBitmapNamed(IDR_DOCK_WIDE); - - canvas->Save(); - bool rtl_ui = base::i18n::IsRTL(); - if (rtl_ui) { - // Flip canvas to draw the mirrored tab images for RTL UI. - canvas->Translate(gfx::Point(width(), 0)); - canvas->Scale(-1, 1); - } - int x_of_active_tab = width() / 2 + kTabSpacing / 2; - int x_of_inactive_tab = width() / 2 - high_icon->width() - kTabSpacing / 2; - switch (type_) { - case DockInfo::LEFT_OF_WINDOW: - case DockInfo::LEFT_HALF: - if (!rtl_ui) - std::swap(x_of_active_tab, x_of_inactive_tab); - canvas->DrawBitmapInt(*high_icon, x_of_active_tab, - (height() - high_icon->height()) / 2); - if (type_ == DockInfo::LEFT_OF_WINDOW) { - DrawBitmapWithAlpha(canvas, *high_icon, x_of_inactive_tab, - (height() - high_icon->height()) / 2); - } - break; - - - case DockInfo::RIGHT_OF_WINDOW: - case DockInfo::RIGHT_HALF: - if (rtl_ui) - std::swap(x_of_active_tab, x_of_inactive_tab); - canvas->DrawBitmapInt(*high_icon, x_of_active_tab, - (height() - high_icon->height()) / 2); - if (type_ == DockInfo::RIGHT_OF_WINDOW) { - DrawBitmapWithAlpha(canvas, *high_icon, x_of_inactive_tab, - (height() - high_icon->height()) / 2); - } - break; - - case DockInfo::TOP_OF_WINDOW: - canvas->DrawBitmapInt(*wide_icon, (width() - wide_icon->width()) / 2, - height() / 2 - high_icon->height()); - break; - - case DockInfo::MAXIMIZE: { - SkBitmap* max_icon = rb.GetBitmapNamed(IDR_DOCK_MAX); - canvas->DrawBitmapInt(*max_icon, (width() - max_icon->width()) / 2, - (height() - max_icon->height()) / 2); - break; - } - - case DockInfo::BOTTOM_HALF: - case DockInfo::BOTTOM_OF_WINDOW: - canvas->DrawBitmapInt(*wide_icon, (width() - wide_icon->width()) / 2, - height() / 2 + kTabSpacing / 2); - if (type_ == DockInfo::BOTTOM_OF_WINDOW) { - DrawBitmapWithAlpha(canvas, *wide_icon, - (width() - wide_icon->width()) / 2, - height() / 2 - kTabSpacing / 2 - wide_icon->height()); - } - break; - - default: - NOTREACHED(); - break; - } - canvas->Restore(); - } - - private: - void DrawBitmapWithAlpha(gfx::Canvas* canvas, const SkBitmap& image, - int x, int y) { - SkPaint paint; - paint.setAlpha(128); - canvas->DrawBitmapInt(image, x, y, paint); - } - - DockInfo::Type type_; - - DISALLOW_COPY_AND_ASSIGN(DockView); -}; - -} // namespace - -/////////////////////////////////////////////////////////////////////////////// -// DockDisplayer - -// DockDisplayer is responsible for giving the user a visual indication of a -// possible dock position (as represented by DockInfo). DockDisplayer shows -// a window with a DockView in it. Two animations are used that correspond to -// the state of DockInfo::in_enable_area. -class TabDragController2::DockDisplayer : public ui::AnimationDelegate { - public: - DockDisplayer(TabDragController2* controller, - const DockInfo& info) - : controller_(controller), - popup_(NULL), - popup_view_(NULL), - ALLOW_THIS_IN_INITIALIZER_LIST(animation_(this)), - hidden_(false), - in_enable_area_(info.in_enable_area()) { - popup_ = new views::Widget; - views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); - params.transparent = true; - params.keep_on_top = true; - params.bounds = info.GetPopupRect(); - popup_->Init(params); - popup_->SetContentsView(new DockView(info.type())); - popup_->SetOpacity(0x00); - if (info.in_enable_area()) - animation_.Reset(1); - else - animation_.Show(); - popup_->Show(); - popup_view_ = popup_->GetNativeView(); - } - - ~DockDisplayer() { - if (controller_) - controller_->DockDisplayerDestroyed(this); - } - - // Updates the state based on |in_enable_area|. - void UpdateInEnabledArea(bool in_enable_area) { - if (in_enable_area != in_enable_area_) { - in_enable_area_ = in_enable_area; - UpdateLayeredAlpha(); - } - } - - // Resets the reference to the hosting TabDragController2. This is invoked - // when the TabDragController2 is destoryed. - void clear_controller() { controller_ = NULL; } - - // NativeView of the window we create. - gfx::NativeView popup_view() { return popup_view_; } - - // Starts the hide animation. When the window is closed the - // TabDragController2 is notified by way of the DockDisplayerDestroyed - // method - void Hide() { - if (hidden_) - return; - - if (!popup_) { - delete this; - return; - } - hidden_ = true; - animation_.Hide(); - } - - virtual void AnimationProgressed(const ui::Animation* animation) { - UpdateLayeredAlpha(); - } - - virtual void AnimationEnded(const ui::Animation* animation) { - if (!hidden_) - return; - popup_->Close(); - delete this; - } - - virtual void UpdateLayeredAlpha() { - double scale = in_enable_area_ ? 1 : .5; - popup_->SetOpacity(static_cast<unsigned char>(animation_.GetCurrentValue() * - scale * 255.0)); - } - - private: - // TabDragController2 that created us. - TabDragController2* controller_; - - // Window we're showing. - views::Widget* popup_; - - // NativeView of |popup_|. We cache this to avoid the possibility of - // invoking a method on popup_ after we close it. - gfx::NativeView popup_view_; - - // Animation for when first made visible. - ui::SlideAnimation animation_; - - // Have we been hidden? - bool hidden_; - - // Value of DockInfo::in_enable_area. - bool in_enable_area_; -}; - -TabDragController2::TabDragData::TabDragData() - : contents(NULL), - source_model_index(-1), - attached_tab(NULL), - pinned(false) { -} - -TabDragController2::TabDragData::~TabDragData() { -} - -/////////////////////////////////////////////////////////////////////////////// -// TabDragController2, public: - -TabDragController2::TabDragController2() - : source_tabstrip_(NULL), - attached_tabstrip_(NULL), - is_dragging_window_(false), - source_tab_offset_(0), - offset_to_width_ratio_(0), - old_focused_view_(NULL), - last_move_screen_loc_(0), - started_drag_(false), - active_(true), - source_tab_index_(std::numeric_limits<size_t>::max()), - initial_move_(true), - end_run_loop_behavior_(END_RUN_LOOP_STOP_DRAGGING), - waiting_for_run_loop_to_exit_(false), - tab_strip_to_attach_to_after_exit_(NULL), - move_loop_widget_(NULL), - destroyed_(NULL) { - instance_ = this; -} - -TabDragController2::~TabDragController2() { - if (instance_ == this) - instance_ = NULL; - - if (destroyed_) - *destroyed_ = true; - - if (move_loop_widget_) { - move_loop_widget_->RemoveObserver(this); - SetTrackedByWorkspace(move_loop_widget_->GetNativeView(), true); - } - - if (source_tabstrip_) - GetModel(source_tabstrip_)->RemoveObserver(this); - - MessageLoopForUI::current()->RemoveObserver(this); -} - -void TabDragController2::Init( - TabStrip* source_tabstrip, - BaseTab* source_tab, - const std::vector<BaseTab*>& tabs, - const gfx::Point& mouse_offset, - int source_tab_offset, - const TabStripSelectionModel& initial_selection_model) { - DCHECK(!tabs.empty()); - DCHECK(std::find(tabs.begin(), tabs.end(), source_tab) != tabs.end()); - source_tabstrip_ = source_tabstrip; - GetModel(source_tabstrip_)->AddObserver(this); - source_tab_offset_ = source_tab_offset; - start_screen_point_ = GetCursorScreenPoint(); - mouse_offset_ = mouse_offset; - - drag_data_.resize(tabs.size()); - for (size_t i = 0; i < tabs.size(); ++i) - InitTabDragData(tabs[i], &(drag_data_[i])); - source_tab_index_ = - std::find(tabs.begin(), tabs.end(), source_tab) - tabs.begin(); - - // Listen for Esc key presses. - MessageLoopForUI::current()->AddObserver(this); - - if (source_tab->width() > 0) { - offset_to_width_ratio_ = static_cast<float>(source_tab_offset_) / - static_cast<float>(source_tab->width()); - } - InitWindowCreatePoint(source_tabstrip); - initial_selection_model_.Copy(initial_selection_model); -} - -// static -bool TabDragController2::IsActiveAndAttachedTo(TabStrip* tab_strip) { - return instance_ && instance_->active_ && - instance_->attached_tabstrip_ == tab_strip; -} - -// static -bool TabDragController2::IsActive() { - return instance_ && instance_->active_; -} - -void TabDragController2::InitTabDragData(BaseTab* tab, - TabDragData* drag_data) { - drag_data->source_model_index = - source_tabstrip_->GetModelIndexOfBaseTab(tab); - drag_data->contents = GetModel(source_tabstrip_)->GetTabContentsAt( - drag_data->source_model_index); - drag_data->pinned = source_tabstrip_->IsTabPinned(tab); - registrar_.Add( - this, - content::NOTIFICATION_WEB_CONTENTS_DESTROYED, - content::Source<WebContents>(drag_data->contents->web_contents())); -} - -void TabDragController2::Drag() { - bring_to_front_timer_.Stop(); - - if (waiting_for_run_loop_to_exit_) - return; - - if (!started_drag_) { - if (!CanStartDrag()) - return; // User hasn't dragged far enough yet. - - started_drag_ = true; - SaveFocus(); - Attach(source_tabstrip_, gfx::Point()); - if (static_cast<int>(drag_data_.size()) == - GetModel(source_tabstrip_)->count()) { - RunMoveLoop(); // Runs a nested loop, returning when done. - return; - } - } - - ContinueDragging(); -} - -void TabDragController2::EndDrag(bool canceled) { - // We can't revert if the source tabstrip was destroyed during the drag. - EndDragImpl(canceled && source_tabstrip_ ? CANCELED : NORMAL); -} - -bool TabDragController2::GetStartedDrag() const { - return started_drag_; -} - -/////////////////////////////////////////////////////////////////////////////// -// TabDragController2, content::NotificationObserver implementation: - -void TabDragController2::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK_EQ(type, content::NOTIFICATION_WEB_CONTENTS_DESTROYED); - WebContents* destroyed_contents = content::Source<WebContents>(source).ptr(); - for (size_t i = 0; i < drag_data_.size(); ++i) { - if (drag_data_[i].contents->web_contents() == destroyed_contents) { - drag_data_[i].contents = NULL; - EndDragImpl(TAB_DESTROYED); - return; - } - } - // If we get here it means we got notification for a tab we don't know about. - NOTREACHED(); -} - -/////////////////////////////////////////////////////////////////////////////// -// TabDragController2, MessageLoop::Observer implementation: - -#if defined(OS_WIN) || defined(USE_AURA) -base::EventStatus TabDragController2::WillProcessEvent( - const base::NativeEvent& event) { - return base::EVENT_CONTINUE; -} - -void TabDragController2::DidProcessEvent(const base::NativeEvent& event) { - // If the user presses ESC during a drag, we need to abort and revert things - // to the way they were. This is the most reliable way to do this since no - // single view or window reliably receives events throughout all the various - // kinds of tab dragging. - if (ui::EventTypeFromNative(event) == ui::ET_KEY_PRESSED && - ui::KeyboardCodeFromNative(event) == ui::VKEY_ESCAPE) { - EndDrag(true); - } -} -#endif - -void TabDragController2::OnWidgetMoved(views::Widget* widget) { - Drag(); -} - -void TabDragController2::TabStripEmpty() { - GetModel(source_tabstrip_)->RemoveObserver(this); - // NULL out source_tabstrip_ so that we don't attempt to add back to in (in - // the case of a revert). - source_tabstrip_ = NULL; -} - -/////////////////////////////////////////////////////////////////////////////// -// TabDragController2, private: - -void TabDragController2::InitWindowCreatePoint(TabStrip* tab_strip) { - // window_create_point_ is only used in CompleteDrag() (through - // GetWindowCreatePoint() to get the start point of the docked window) when - // the attached_tabstrip_ is NULL and all the window's related bound - // information are obtained from tab_strip. So, we need to get the - // first_tab based on tab_strip, not attached_tabstrip_. Otherwise, - // the window_create_point_ is not in the correct coordinate system. Please - // refer to http://crbug.com/6223 comment #15 for detailed information. - views::View* first_tab = tab_strip->tab_at(0); - views::View::ConvertPointToWidget(first_tab, &first_source_tab_point_); - window_create_point_ = first_source_tab_point_; - window_create_point_.Offset(mouse_offset_.x(), mouse_offset_.y()); -} - -gfx::Point TabDragController2::GetWindowCreatePoint() const { - gfx::Point cursor_point = GetCursorScreenPoint(); - if (dock_info_.type() != DockInfo::NONE && dock_info_.in_enable_area()) { - // If we're going to dock, we need to return the exact coordinate, - // otherwise we may attempt to maximize on the wrong monitor. - return cursor_point; - } - // If the cursor is outside the monitor area, move it inside. For example, - // dropping a tab onto the task bar on Windows produces this situation. - gfx::Rect work_area = gfx::Screen::GetMonitorNearestPoint( - cursor_point).work_area(); - if (!work_area.IsEmpty()) { - if (cursor_point.x() < work_area.x()) - cursor_point.set_x(work_area.x()); - else if (cursor_point.x() > work_area.right()) - cursor_point.set_x(work_area.right()); - if (cursor_point.y() < work_area.y()) - cursor_point.set_y(work_area.y()); - else if (cursor_point.y() > work_area.bottom()) - cursor_point.set_y(work_area.bottom()); - } - return gfx::Point(cursor_point.x() - window_create_point_.x(), - cursor_point.y() - window_create_point_.y()); -} - -void TabDragController2::UpdateDockInfo(const gfx::Point& screen_point) { - // Update the DockInfo for the current mouse coordinates. - DockInfo dock_info = GetDockInfoAtPoint(screen_point); - if (!dock_info.equals(dock_info_)) { - // DockInfo for current position differs. - if (dock_info_.type() != DockInfo::NONE && - !dock_controllers_.empty()) { - // Hide old visual indicator. - dock_controllers_.back()->Hide(); - } - dock_info_ = dock_info; - if (dock_info_.type() != DockInfo::NONE) { - // Show new docking position. - DockDisplayer* controller = new DockDisplayer(this, dock_info_); - if (controller->popup_view()) { - dock_controllers_.push_back(controller); - dock_windows_.insert(controller->popup_view()); - } else { - delete controller; - } - } - } else if (dock_info_.type() != DockInfo::NONE && - !dock_controllers_.empty()) { - // Current dock position is the same as last, update the controller's - // in_enable_area state as it may have changed. - dock_controllers_.back()->UpdateInEnabledArea(dock_info_.in_enable_area()); - } -} - -void TabDragController2::SaveFocus() { - DCHECK(!old_focused_view_); // This should only be invoked once. - DCHECK(source_tabstrip_); - old_focused_view_ = source_tabstrip_->GetFocusManager()->GetFocusedView(); - source_tabstrip_->GetFocusManager()->SetFocusedView(source_tabstrip_); -} - -void TabDragController2::RestoreFocus() { - if (old_focused_view_ && attached_tabstrip_ == source_tabstrip_) - old_focused_view_->GetFocusManager()->SetFocusedView(old_focused_view_); - old_focused_view_ = NULL; -} - -bool TabDragController2::CanStartDrag() const { - // Determine if the mouse has moved beyond a minimum elasticity distance in - // any direction from the starting point. - static const int kMinimumDragDistance = 10; - gfx::Point screen_point = GetCursorScreenPoint(); - int x_offset = abs(screen_point.x() - start_screen_point_.x()); - int y_offset = abs(screen_point.y() - start_screen_point_.y()); - return sqrt(pow(static_cast<float>(x_offset), 2) + - pow(static_cast<float>(y_offset), 2)) > kMinimumDragDistance; -} - -void TabDragController2::ContinueDragging() { - DCHECK(attached_tabstrip_); - - // Note that the coordinates given to us by |drag_event| are basically - // useless, since they're in source_tab_ coordinates. On the surface, you'd - // think we could just convert them to screen coordinates, however in the - // situation where we're dragging the last tab in a window when multiple - // windows are open, the coordinates of |source_tab_| are way off in - // hyperspace since the window was moved there instead of being closed so - // that we'd keep receiving events. And our ConvertPointToScreen methods - // aren't really multi-screen aware. So really it's just safer to get the - // actual position of the mouse cursor directly from Windows here, which is - // guaranteed to be correct regardless of monitor config. - gfx::Point screen_point = GetCursorScreenPoint(); - - // Determine whether or not we have dragged over a compatible TabStrip in - // another browser window. If we have, we should attach to it and start - // dragging within it. - TabStrip* target_tabstrip = GetTabStripForPoint(screen_point); - bool tab_strip_changed = (target_tabstrip != attached_tabstrip_); - if (tab_strip_changed) { - if (!target_tabstrip) { - DetachIntoNewBrowserAndRunMoveLoop(screen_point); - return; - } - if (is_dragging_window_) { -#if defined(USE_ASH) - // ReleaseMouseCapture() is going to result in calling back to us (because - // it results in a move). That'll cause all sorts of problems. Reset the - // observer so we don't get notified and process the event. - move_loop_widget_->RemoveObserver(this); - move_loop_widget_ = NULL; -#endif - views::Widget* browser_widget = GetAttachedBrowserWidget(); - // Need to release the drag controller before starting the move loop as - // it's going to trigger capture lost, which cancels drag. - attached_tabstrip_->ReleaseDragController(); - target_tabstrip->OwnDragController(this); - // Disable animations so that we don't see a close animation on aero. - browser_widget->SetVisibilityChangedAnimationsEnabled(false); - browser_widget->ReleaseMouseCapture(); - // EndMoveLoop is going to snap the window back to its original location. - // Hide it so users don't see this. - browser_widget->Hide(); - browser_widget->EndMoveLoop(); - - // Ideally we would always swap the tabs now, but on windows it seems that - // running the move loop implicitly activates the window when done, - // leading to all sorts of flicker. So, on windows, instead we process - // the move after the loop completes. But on chromeos, we can do tab - // swapping now to avoid the tab flashing issue(crbug.com/116329). -#if defined(USE_ASH) - is_dragging_window_ = false; - Detach(); - gfx::Point screen_point(GetCursorScreenPoint()); - Attach(target_tabstrip, screen_point); - // Move the tabs into position. - MoveAttached(screen_point); - attached_tabstrip_->GetWidget()->Activate(); -#else - tab_strip_to_attach_to_after_exit_ = target_tabstrip; -#endif - - waiting_for_run_loop_to_exit_ = true; - end_run_loop_behavior_ = END_RUN_LOOP_CONTINUE_DRAGGING; - return; - } - Detach(); - Attach(target_tabstrip, screen_point); - } - if (is_dragging_window_) { - bring_to_front_timer_.Start(FROM_HERE, - base::TimeDelta::FromMilliseconds(kBringToFrontDelay), this, - &TabDragController2::BringWindowUnderMouseToFront); - } - - UpdateDockInfo(screen_point); - - if (!is_dragging_window_) { - MoveAttached(screen_point); - if (tab_strip_changed) { - // Move the corresponding window to the front. We do this after the move - // as on windows activate triggers a synchronous paint. - attached_tabstrip_->GetWidget()->Activate(); - } - } -} - -void TabDragController2::MoveAttached(const gfx::Point& screen_point) { - DCHECK(attached_tabstrip_); - DCHECK(!is_dragging_window_); - - gfx::Point dragged_view_point = GetAttachedDragPoint(screen_point); - - TabStrip* tab_strip = static_cast<TabStrip*>(attached_tabstrip_); - - // Determine the horizontal move threshold. This is dependent on the width - // of tabs. The smaller the tabs compared to the standard size, the smaller - // the threshold. - double unselected, selected; - tab_strip->GetCurrentTabWidths(&unselected, &selected); - double ratio = unselected / Tab::GetStandardSize().width(); - int threshold = static_cast<int>(ratio * kHorizontalMoveThreshold); - - std::vector<BaseTab*> tabs(drag_data_.size()); - for (size_t i = 0; i < drag_data_.size(); ++i) - tabs[i] = drag_data_[i].attached_tab; - - bool did_layout = false; - // Update the model, moving the WebContents from one index to another. Do this - // only if we have moved a minimum distance since the last reorder (to prevent - // jitter) or if this the first move and the tabs are not consecutive. - if (abs(screen_point.x() - last_move_screen_loc_) > threshold || - (initial_move_ && !AreTabsConsecutive())) { - TabStripModel* attached_model = GetModel(attached_tabstrip_); - gfx::Rect bounds = GetDraggedViewTabStripBounds(dragged_view_point); - int to_index = GetInsertionIndexForDraggedBounds(bounds); - TabContentsWrapper* last_contents = - drag_data_[drag_data_.size() - 1].contents; - int index_of_last_item = - attached_model->GetIndexOfTabContents(last_contents); - if (initial_move_) { - // TabStrip determines if the tabs needs to be animated based on model - // position. This means we need to invoke LayoutDraggedTabsAt before - // changing the model. - attached_tabstrip_->LayoutDraggedTabsAt( - tabs, source_tab_drag_data()->attached_tab, dragged_view_point, - initial_move_); - did_layout = true; - } - attached_model->MoveSelectedTabsTo(to_index); - // Move may do nothing in certain situations (such as when dragging pinned - // tabs). Make sure the tabstrip actually changed before updating - // last_move_screen_loc_. - if (index_of_last_item != - attached_model->GetIndexOfTabContents(last_contents)) { - last_move_screen_loc_ = screen_point.x(); - } - } - - if (!did_layout) { - attached_tabstrip_->LayoutDraggedTabsAt( - tabs, source_tab_drag_data()->attached_tab, dragged_view_point, - initial_move_); - } - - initial_move_ = false; -} - -TabDragController2::DetachPosition TabDragController2::GetDetachPosition( - const gfx::Point& screen_point) { - DCHECK(attached_tabstrip_); - gfx::Point attached_point(screen_point); - views::View::ConvertPointToView(NULL, attached_tabstrip_, &attached_point); - if (attached_point.x() < 0) - return DETACH_BEFORE; - if (attached_point.x() >= attached_tabstrip_->width()) - return DETACH_AFTER; - return DETACH_ABOVE_OR_BELOW; -} - -DockInfo TabDragController2::GetDockInfoAtPoint( - const gfx::Point& screen_point) { - // TODO: add support for dock info. - if (true) { - return DockInfo(); - } - - if (attached_tabstrip_) { - // If the mouse is over a tab strip, don't offer a dock position. - return DockInfo(); - } - - if (dock_info_.IsValidForPoint(screen_point)) { - // It's possible any given screen coordinate has multiple docking - // positions. Check the current info first to avoid having the docking - // position bounce around. - return dock_info_; - } - - // gfx::NativeView dragged_hwnd = view_->GetWidget()->GetNativeView(); - // dock_windows_.insert(dragged_hwnd); - DockInfo info = DockInfo::GetDockInfoAtPoint(screen_point, dock_windows_); - // dock_windows_.erase(dragged_hwnd); - return info; -} - -TabStrip* TabDragController2::GetTabStripForPoint( - const gfx::Point& screen_point) { - gfx::NativeView dragged_view = NULL; - if (is_dragging_window_) { - dragged_view = attached_tabstrip_->GetWidget()->GetNativeView(); - dock_windows_.insert(dragged_view); - } - gfx::NativeWindow local_window = - DockInfo::GetLocalProcessWindowAtPoint(screen_point, dock_windows_); - if (dragged_view) - dock_windows_.erase(dragged_view); - TabStrip* tab_strip = GetTabStripForWindow(local_window); - if (tab_strip && DoesTabStripContain(tab_strip, screen_point)) - return tab_strip; - return is_dragging_window_ ? attached_tabstrip_ : NULL; -} - -TabStrip* TabDragController2::GetTabStripForWindow( - gfx::NativeWindow window) { - if (!window) - return NULL; - BrowserView* browser = BrowserView::GetBrowserViewForNativeWindow(window); - // We only allow drops on windows that have tabstrips. - if (!browser || - !browser->browser()->SupportsWindowFeature(Browser::FEATURE_TABSTRIP)) - return NULL; - - TabStrip* other_tabstrip = static_cast<TabStrip*>(browser->tabstrip()); - TabStrip* tab_strip = - attached_tabstrip_ ? attached_tabstrip_ : source_tabstrip_; - DCHECK(tab_strip); - if (!other_tabstrip->controller()->IsCompatibleWith(tab_strip)) - return NULL; - return other_tabstrip; -} - -bool TabDragController2::DoesTabStripContain( - TabStrip* tabstrip, - const gfx::Point& screen_point) const { - static const int kVerticalDetachMagnetism = 15; - // Make sure the specified screen point is actually within the bounds of the - // specified tabstrip... - gfx::Rect tabstrip_bounds = GetViewScreenBounds(tabstrip); - if (screen_point.x() < tabstrip_bounds.right() && - screen_point.x() >= tabstrip_bounds.x()) { - // TODO(beng): make this be relative to the start position of the mouse - // for the source TabStrip. - int upper_threshold = tabstrip_bounds.bottom() + kVerticalDetachMagnetism; - int lower_threshold = tabstrip_bounds.y() - kVerticalDetachMagnetism; - return screen_point.y() >= lower_threshold && - screen_point.y() <= upper_threshold; - } - return false; -} - -void TabDragController2::Attach(TabStrip* attached_tabstrip, - const gfx::Point& screen_point) { - DCHECK(!attached_tabstrip_); // We should already have detached by the time - // we get here. - - attached_tabstrip_ = attached_tabstrip; - - std::vector<BaseTab*> tabs = - GetTabsMatchingDraggedContents(attached_tabstrip_); - - if (tabs.empty()) { - // Transitioning from detached to attached to a new tabstrip. Add tabs to - // the new model. - - selection_model_before_attach_.Copy(attached_tabstrip->GetSelectionModel()); - - // Inserting counts as a move. We don't want the tabs to jitter when the - // user moves the tab immediately after attaching it. - last_move_screen_loc_ = screen_point.x(); - - // Figure out where to insert the tab based on the bounds of the dragged - // representation and the ideal bounds of the other Tabs already in the - // strip. ("ideal bounds" are stable even if the Tabs' actual bounds are - // changing due to animation). - gfx::Point tab_strip_point(screen_point); - views::View::ConvertPointToView(NULL, attached_tabstrip_, &tab_strip_point); - tab_strip_point.set_x( - attached_tabstrip_->GetMirroredXInView(tab_strip_point.x())); - tab_strip_point.Offset(-mouse_offset_.x(), -mouse_offset_.y()); - gfx::Rect bounds = GetDraggedViewTabStripBounds(tab_strip_point); - int index = GetInsertionIndexForDraggedBounds(bounds); - for (size_t i = 0; i < drag_data_.size(); ++i) { - int add_types = TabStripModel::ADD_NONE; - if (drag_data_[i].pinned) - add_types |= TabStripModel::ADD_PINNED; - GetModel(attached_tabstrip_)->InsertTabContentsAt( - index + i, drag_data_[i].contents, add_types); - } - - tabs = GetTabsMatchingDraggedContents(attached_tabstrip_); - } - DCHECK_EQ(tabs.size(), drag_data_.size()); - for (size_t i = 0; i < drag_data_.size(); ++i) - drag_data_[i].attached_tab = tabs[i]; - - attached_tabstrip_->StartedDraggingTabs(tabs); - - ResetSelection(GetModel(attached_tabstrip_)); - - // The size of the dragged tab may have changed. Adjust the x offset so that - // ratio of mouse_offset_ to original width is maintained. - std::vector<BaseTab*> tabs_to_source(tabs); - tabs_to_source.erase(tabs_to_source.begin() + source_tab_index_ + 1, - tabs_to_source.end()); - int new_x = attached_tabstrip_->GetSizeNeededForTabs(tabs_to_source) - - tabs[source_tab_index_]->width() + - static_cast<int>(offset_to_width_ratio_ * - tabs[source_tab_index_]->width()); - mouse_offset_.set_x(new_x); - - // Redirect all mouse events to the TabStrip so that the tab that originated - // the drag can safely be deleted. - static_cast<views::internal::RootView*>( - attached_tabstrip_->GetWidget()->GetRootView())->SetMouseHandler( - attached_tabstrip_); -} - -void TabDragController2::Detach() { - TabStripModel* attached_model = GetModel(attached_tabstrip_); - for (size_t i = 0; i < drag_data_.size(); ++i) { - int index = attached_model->GetIndexOfTabContents(drag_data_[i].contents); - DCHECK_NE(-1, index); - - // Hide the tab so that the user doesn't see it animate closed. - drag_data_[i].attached_tab->SetVisible(false); - - attached_model->DetachTabContentsAt(index); - - // Detaching may end up deleting the tab, drop references to it. - drag_data_[i].attached_tab = NULL; - } - - if (!attached_model->empty()) { - if (!selection_model_before_attach_.empty() && - selection_model_before_attach_.active() >= 0 && - selection_model_before_attach_.active() < - attached_model->count()) { - // Restore the selection. - attached_model->SetSelectionFromModel(selection_model_before_attach_); - } else if (attached_tabstrip_ == source_tabstrip_ && - !initial_selection_model_.empty()) { - // First time detaching from the source tabstrip. Reset selection model to - // initial_selection_model_. Before resetting though we have to remove all - // the tabs from initial_selection_model_ as it was created with the tabs - // still there. - TabStripSelectionModel selection_model; - selection_model.Copy(initial_selection_model_); - for (DragData::const_reverse_iterator i = drag_data_.rbegin(); - i != drag_data_.rend(); ++i) { - selection_model.DecrementFrom(i->source_model_index); - } - // We may have cleared out the selection model. Only reset it if it - // contains something. - if (!selection_model.empty()) - attached_model->SetSelectionFromModel(selection_model); - } - } - - attached_tabstrip_->DraggedTabsDetached(); - - attached_tabstrip_ = NULL; -} - -void TabDragController2::DetachIntoNewBrowserAndRunMoveLoop( - const gfx::Point& screen_point) { - if (GetModel(attached_tabstrip_)->count() == - static_cast<int>(drag_data_.size())) { - // All the tabs in a browser are being dragged but all the tabs weren't - // initially being dragged. For this to happen the user would have to - // start dragging a set of tabs, the other tabs close, then detach. - RunMoveLoop(); - return; - } - - // Create a new browser to house the dragged tabs and have the OS run a move - // loop. - - gfx::Point attached_point = GetAttachedDragPoint(screen_point); - - // Calculate the bounds for the tabs from the attached_tab_strip. We do this - // so that the tabs don't change size when detached. - std::vector<gfx::Rect> drag_bounds; - std::vector<BaseTab*> attached_tabs; - for (size_t i = 0; i < drag_data_.size(); ++i) - attached_tabs.push_back(drag_data_[i].attached_tab); - attached_tabstrip_->CalculateBoundsForDraggedTabs(attached_tabs, - &drag_bounds); - for (size_t i = 0; i < drag_bounds.size(); ++i) - drag_bounds[i].set_x(attached_point.x() + drag_bounds[i].x()); - - Browser* browser = CreateBrowserForDrag( - attached_tabstrip_, screen_point, &drag_bounds); - attached_tabstrip_->ReleaseDragController(); - Detach(); - BrowserView* dragged_browser_view = - BrowserView::GetBrowserViewForBrowser(browser); - dragged_browser_view->GetWidget()->SetVisibilityChangedAnimationsEnabled( - false); - Attach(static_cast<TabStrip*>(dragged_browser_view->tabstrip()), - gfx::Point()); - attached_tabstrip_->OwnDragController(this); - // TODO: come up with a cleaner way to do this. - static_cast<TabStrip*>(attached_tabstrip_)->SetTabBoundsForDrag( - drag_bounds); - - browser->window()->Show(); - browser->window()->Activate(); - dragged_browser_view->GetWidget()->SetVisibilityChangedAnimationsEnabled( - true); - RunMoveLoop(); -} - -void TabDragController2::RunMoveLoop() { - move_loop_widget_ = GetAttachedBrowserWidget(); - move_loop_widget_->AddObserver(this); - is_dragging_window_ = true; - bool destroyed = false; - destroyed_ = &destroyed; - // Running the move loop release mouse capture on windows, which triggers - // destroying the drag loop. Release mouse capture ourself before this while - // the Dragcontroller isn't owned by the TabStrip. - attached_tabstrip_->ReleaseDragController(); - attached_tabstrip_->GetWidget()->ReleaseMouseCapture(); - attached_tabstrip_->OwnDragController(this); - views::Widget::MoveLoopResult result = move_loop_widget_->RunMoveLoop(); - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE, - content::NotificationService::AllBrowserContextsAndSources(), - content::NotificationService::NoDetails()); - - if (destroyed) - return; - destroyed_ = NULL; - // Under chromeos we immediately set the |move_loop_widget_| to NULL. - if (move_loop_widget_) { - move_loop_widget_->RemoveObserver(this); - move_loop_widget_ = NULL; - } - is_dragging_window_ = false; - waiting_for_run_loop_to_exit_ = false; - if (end_run_loop_behavior_ == END_RUN_LOOP_CONTINUE_DRAGGING) { - end_run_loop_behavior_ = END_RUN_LOOP_STOP_DRAGGING; - if (tab_strip_to_attach_to_after_exit_) { - Detach(); - gfx::Point screen_point(GetCursorScreenPoint()); - Attach(tab_strip_to_attach_to_after_exit_, screen_point); - // Move the tabs into position. - MoveAttached(screen_point); - attached_tabstrip_->GetWidget()->Activate(); - tab_strip_to_attach_to_after_exit_ = NULL; - } - DCHECK(attached_tabstrip_); - attached_tabstrip_->GetWidget()->SetMouseCapture(attached_tabstrip_); - } else if (active_) { - EndDrag(result == views::Widget::MOVE_LOOP_CANCELED); - } -} - -int TabDragController2::GetInsertionIndexForDraggedBounds( - const gfx::Rect& dragged_bounds) const { - // TODO: this is wrong. It needs to calculate the bounds after adjusting for - // the tabs that will be inserted. - int right_tab_x = 0; - int index = -1; - for (int i = 0; i < attached_tabstrip_->tab_count(); ++i) { - const gfx::Rect& ideal_bounds = attached_tabstrip_->ideal_bounds(i); - gfx::Rect left_half, right_half; - ideal_bounds.SplitVertically(&left_half, &right_half); - right_tab_x = right_half.right(); - if (dragged_bounds.x() >= right_half.x() && - dragged_bounds.x() < right_half.right()) { - index = i + 1; - break; - } else if (dragged_bounds.x() >= left_half.x() && - dragged_bounds.x() < left_half.right()) { - index = i; - break; - } - } - if (index == -1) { - if (dragged_bounds.right() > right_tab_x) { - index = GetModel(attached_tabstrip_)->count(); - } else { - index = 0; - } - } - - if (!drag_data_[0].attached_tab) { - // If 'attached_tab' is NULL, it means we're in the process of attaching and - // don't need to constrain the index. - return index; - } - - int max_index = GetModel(attached_tabstrip_)->count() - - static_cast<int>(drag_data_.size()); - return std::max(0, std::min(max_index, index)); -} - -gfx::Rect TabDragController2::GetDraggedViewTabStripBounds( - const gfx::Point& tab_strip_point) { - // attached_tab is NULL when inserting into a new tabstrip. - if (source_tab_drag_data()->attached_tab) { - return gfx::Rect(tab_strip_point.x(), tab_strip_point.y(), - source_tab_drag_data()->attached_tab->width(), - source_tab_drag_data()->attached_tab->height()); - } - - double sel_width, unselected_width; - static_cast<TabStrip*>(attached_tabstrip_)->GetCurrentTabWidths( - &sel_width, &unselected_width); - return gfx::Rect(tab_strip_point.x(), tab_strip_point.y(), - static_cast<int>(sel_width), - Tab::GetStandardSize().height()); -} - -gfx::Point TabDragController2::GetAttachedDragPoint( - const gfx::Point& screen_point) { - DCHECK(attached_tabstrip_); // The tab must be attached. - - gfx::Point tab_loc(screen_point); - views::View::ConvertPointToView(NULL, attached_tabstrip_, &tab_loc); - int x = - attached_tabstrip_->GetMirroredXInView(tab_loc.x()) - mouse_offset_.x(); - int y = tab_loc.y() - mouse_offset_.y(); - - // TODO: consider caching this. - std::vector<BaseTab*> attached_tabs; - for (size_t i = 0; i < drag_data_.size(); ++i) - attached_tabs.push_back(drag_data_[i].attached_tab); - - int size = attached_tabstrip_->GetSizeNeededForTabs(attached_tabs); - - int max_x = attached_tabstrip_->width() - size; - x = std::min(std::max(x, 0), max_x); - y = 0; - return gfx::Point(x, y); -} - -std::vector<BaseTab*> TabDragController2::GetTabsMatchingDraggedContents( - TabStrip* tabstrip) { - TabStripModel* model = GetModel(attached_tabstrip_); - std::vector<BaseTab*> tabs; - for (size_t i = 0; i < drag_data_.size(); ++i) { - int model_index = model->GetIndexOfTabContents(drag_data_[i].contents); - if (model_index == TabStripModel::kNoTab) - return std::vector<BaseTab*>(); - tabs.push_back(tabstrip->tab_at(model_index)); - } - return tabs; -} - -void TabDragController2::EndDragImpl(EndDragType type) { - DCHECK(active_); - active_ = false; - - bring_to_front_timer_.Stop(); - - if (is_dragging_window_) { - if (type == NORMAL || (type == TAB_DESTROYED && drag_data_.size() > 1)) - SetTrackedByWorkspace(GetAttachedBrowserWidget()->GetNativeView(), true); - - // End the nested drag loop. - GetAttachedBrowserWidget()->EndMoveLoop(); - waiting_for_run_loop_to_exit_ = true; - } - - // Hide the current dock controllers. - for (size_t i = 0; i < dock_controllers_.size(); ++i) { - // Be sure and clear the controller first, that way if Hide ends up - // deleting the controller it won't call us back. - dock_controllers_[i]->clear_controller(); - dock_controllers_[i]->Hide(); - } - dock_controllers_.clear(); - dock_windows_.clear(); - - if (type != TAB_DESTROYED) { - // We only finish up the drag if we were actually dragging. If start_drag_ - // is false, the user just clicked and released and didn't move the mouse - // enough to trigger a drag. - if (started_drag_) { - RestoreFocus(); - if (type == CANCELED) - RevertDrag(); - else - CompleteDrag(); - } - } else if (drag_data_.size() > 1) { - RevertDrag(); - } // else case the only tab we were dragging was deleted. Nothing to do. - - // Clear out drag data so we don't attempt to do anything with it. - drag_data_.clear(); - - TabStrip* owning_tabstrip = - attached_tabstrip_ ? attached_tabstrip_ : source_tabstrip_; - owning_tabstrip->DestroyDragController(); -} - -void TabDragController2::RevertDrag() { - std::vector<BaseTab*> tabs; - for (size_t i = 0; i < drag_data_.size(); ++i) { - if (drag_data_[i].contents) { - // Contents is NULL if a tab was destroyed while the drag was under way. - tabs.push_back(drag_data_[i].attached_tab); - RevertDragAt(i); - } - } - - if (attached_tabstrip_ && attached_tabstrip_ == source_tabstrip_) - attached_tabstrip_->StoppedDraggingTabs(tabs); - - if (initial_selection_model_.empty()) - ResetSelection(GetModel(source_tabstrip_)); - else - GetModel(source_tabstrip_)->SetSelectionFromModel(initial_selection_model_); - - if (source_tabstrip_) - source_tabstrip_->GetWidget()->Activate(); -} - -void TabDragController2::ResetSelection(TabStripModel* model) { - DCHECK(model); - TabStripSelectionModel selection_model; - bool has_one_valid_tab = false; - for (size_t i = 0; i < drag_data_.size(); ++i) { - // |contents| is NULL if a tab was deleted out from under us. - if (drag_data_[i].contents) { - int index = model->GetIndexOfTabContents(drag_data_[i].contents); - DCHECK_NE(-1, index); - selection_model.AddIndexToSelection(index); - if (!has_one_valid_tab || i == source_tab_index_) { - // Reset the active/lead to the first tab. If the source tab is still - // valid we'll reset these again later on. - selection_model.set_active(index); - selection_model.set_anchor(index); - has_one_valid_tab = true; - } - } - } - if (!has_one_valid_tab) - return; - - model->SetSelectionFromModel(selection_model); -} - -void TabDragController2::RevertDragAt(size_t drag_index) { - DCHECK(started_drag_); - - TabDragData* data = &(drag_data_[drag_index]); - int index = - GetModel(attached_tabstrip_)->GetIndexOfTabContents(data->contents); - if (attached_tabstrip_ != source_tabstrip_) { - // The Tab was inserted into another TabStrip. We need to put it back into - // the original one. - GetModel(attached_tabstrip_)->DetachTabContentsAt(index); - // TODO(beng): (Cleanup) seems like we should use Attach() for this - // somehow. - GetModel(source_tabstrip_)->InsertTabContentsAt( - data->source_model_index, data->contents, - (data->pinned ? TabStripModel::ADD_PINNED : 0)); - } else { - // The Tab was moved within the TabStrip where the drag was initiated. Move - // it back to the starting location. - GetModel(source_tabstrip_)->MoveTabContentsAt( - index, data->source_model_index, false); - } -} - -void TabDragController2::CompleteDrag() { - DCHECK(started_drag_); - - if (attached_tabstrip_) { - attached_tabstrip_->StoppedDraggingTabs( - GetTabsMatchingDraggedContents(attached_tabstrip_)); - } else { - NOTIMPLEMENTED(); - - if (dock_info_.type() != DockInfo::NONE) { - switch (dock_info_.type()) { - case DockInfo::LEFT_OF_WINDOW: - content::RecordAction(UserMetricsAction("DockingWindow_Left")); - break; - - case DockInfo::RIGHT_OF_WINDOW: - content::RecordAction(UserMetricsAction("DockingWindow_Right")); - break; - - case DockInfo::BOTTOM_OF_WINDOW: - content::RecordAction(UserMetricsAction("DockingWindow_Bottom")); - break; - - case DockInfo::TOP_OF_WINDOW: - content::RecordAction(UserMetricsAction("DockingWindow_Top")); - break; - - case DockInfo::MAXIMIZE: - content::RecordAction(UserMetricsAction("DockingWindow_Maximize")); - break; - - case DockInfo::LEFT_HALF: - content::RecordAction(UserMetricsAction("DockingWindow_LeftHalf")); - break; - - case DockInfo::RIGHT_HALF: - content::RecordAction(UserMetricsAction("DockingWindow_RightHalf")); - break; - - case DockInfo::BOTTOM_HALF: - content::RecordAction(UserMetricsAction("DockingWindow_BottomHalf")); - break; - - default: - NOTREACHED(); - break; - } - } - // Compel the model to construct a new window for the detached WebContents. - views::Widget* widget = source_tabstrip_->GetWidget(); - gfx::Rect window_bounds(widget->GetRestoredBounds()); - window_bounds.set_origin(GetWindowCreatePoint()); - // When modifying the following if statement, please make sure not to - // introduce issue listed in http://crbug.com/6223 comment #11. - bool rtl_ui = base::i18n::IsRTL(); - bool has_dock_position = (dock_info_.type() != DockInfo::NONE); - if (rtl_ui && has_dock_position) { - // Mirror X axis so the docked tab is aligned using the mouse click as - // the top-right corner. - window_bounds.set_x(window_bounds.x() - window_bounds.width()); - } - Browser* new_browser = - GetModel(source_tabstrip_)->delegate()->CreateNewStripWithContents( - drag_data_[0].contents, window_bounds, dock_info_, - widget->IsMaximized()); - TabStripModel* new_model = new_browser->tabstrip_model(); - new_model->SetTabPinned( - new_model->GetIndexOfTabContents(drag_data_[0].contents), - drag_data_[0].pinned); - for (size_t i = 1; i < drag_data_.size(); ++i) { - new_model->InsertTabContentsAt( - static_cast<int>(i), - drag_data_[i].contents, - drag_data_[i].pinned ? TabStripModel::ADD_PINNED : - TabStripModel::ADD_NONE); - } - ResetSelection(new_browser->tabstrip_model()); - new_browser->window()->Show(); - } -} - -gfx::Point TabDragController2::GetCursorScreenPoint() const { - // TODO(sky): see if we can convert to using Screen every where. -#if defined(OS_WIN) && !defined(USE_AURA) - DWORD pos = GetMessagePos(); - return gfx::Point(pos); -#else - return gfx::Screen::GetCursorScreenPoint(); -#endif -} - -gfx::Rect TabDragController2::GetViewScreenBounds(views::View* view) const { - gfx::Point view_topleft; - views::View::ConvertPointToScreen(view, &view_topleft); - gfx::Rect view_screen_bounds = view->GetLocalBounds(); - view_screen_bounds.Offset(view_topleft.x(), view_topleft.y()); - return view_screen_bounds; -} - -void TabDragController2::DockDisplayerDestroyed( - DockDisplayer* controller) { - DockWindows::iterator dock_i = - dock_windows_.find(controller->popup_view()); - if (dock_i != dock_windows_.end()) - dock_windows_.erase(dock_i); - else - NOTREACHED(); - - std::vector<DockDisplayer*>::iterator i = - std::find(dock_controllers_.begin(), dock_controllers_.end(), - controller); - if (i != dock_controllers_.end()) - dock_controllers_.erase(i); - else - NOTREACHED(); -} - -void TabDragController2::BringWindowUnderMouseToFront() { - gfx::NativeWindow window = dock_info_.window(); - if (!window) { - gfx::NativeView dragged_view = - attached_tabstrip_->GetWidget()->GetNativeView(); - dock_windows_.insert(dragged_view); - window = DockInfo::GetLocalProcessWindowAtPoint(GetCursorScreenPoint(), - dock_windows_); - dock_windows_.erase(dragged_view); - } - if (window) { - views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window); - if (widget) { - widget->StackAtTop(); - attached_tabstrip_->GetWidget()->StackAtTop(); - } - } -} - -// static -TabStripModel* TabDragController2::GetModel(TabStrip* tabstrip) { - return static_cast<BrowserTabStripController*>(tabstrip->controller())-> - model(); -} - -views::Widget* TabDragController2::GetAttachedBrowserWidget() { - return BrowserView::GetBrowserViewForNativeWindow( - attached_tabstrip_->GetWidget()->GetNativeView())->GetWidget(); -} - -bool TabDragController2::AreTabsConsecutive() { - for (size_t i = 1; i < drag_data_.size(); ++i) { - if (drag_data_[i - 1].source_model_index + 1 != - drag_data_[i].source_model_index) { - return false; - } - } - return true; -} - -Browser* TabDragController2::CreateBrowserForDrag( - TabStrip* source, - const gfx::Point& screen_point, - std::vector<gfx::Rect>* drag_bounds) { - Browser* browser = Browser::Create(drag_data_[0].contents->profile()); - gfx::Point center(0, source->height() / 2); - views::View::ConvertPointToWidget(source, ¢er); - gfx::Rect new_bounds(source->GetWidget()->GetWindowScreenBounds()); - new_bounds.set_y(screen_point.y() - center.y()); - switch (GetDetachPosition(screen_point)) { - case DETACH_BEFORE: - new_bounds.set_x(screen_point.x() - center.x()); - new_bounds.Offset(-mouse_offset_.x(), 0); - break; - - case DETACH_AFTER: { - gfx::Point right_edge(source->width(), 0); - views::View::ConvertPointToWidget(source, &right_edge); - new_bounds.set_x(screen_point.x() - right_edge.x()); - new_bounds.Offset(drag_bounds->back().right() - mouse_offset_.x(), 0); - int delta = (*drag_bounds)[0].x(); - for (size_t i = 0; i < drag_bounds->size(); ++i) - (*drag_bounds)[i].Offset(-delta, 0); - break; - } - - default: - break; // Nothing to do for DETACH_ABOVE_OR_BELOW. - } - - SetTrackedByWorkspace(browser->window()->GetNativeHandle(), false); - browser->window()->SetBounds(new_bounds); - return browser; -} - -void TabDragController2::SetTrackedByWorkspace(gfx::NativeWindow window, - bool value) { -#if defined(USE_ASH) - ash::SetTrackedByWorkspace(window, value); -#endif -} diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller2.h b/chrome/browser/ui/views/tabs/tab_drag_controller2.h deleted file mode 100644 index 8af2a28..0000000 --- a/chrome/browser/ui/views/tabs/tab_drag_controller2.h +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright (c) 2012 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_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER2_H_ -#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER2_H_ -#pragma once - -#include <vector> - -#include "base/memory/scoped_ptr.h" -#include "base/message_loop.h" -#include "base/timer.h" -#include "chrome/browser/tabs/tab_strip_model_observer.h" -#include "chrome/browser/tabs/tab_strip_selection_model.h" -#include "chrome/browser/ui/tabs/dock_info.h" -#include "chrome/browser/ui/views/tabs/tab_drag_controller.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" -#include "ui/gfx/rect.h" -#include "ui/views/widget/widget.h" - -namespace views { -class View; -} // namespace views - -class BaseTab; -class Browser; -class TabContentsWrapper; -struct TabRendererData; -class TabStripModel; - -// Implementation of TabDragController that creates a real Browser. -class TabDragController2 : public TabDragController, - public content::NotificationObserver, - public MessageLoopForUI::Observer, - public views::Widget::Observer, - public TabStripModelObserver { - public: - TabDragController2(); - virtual ~TabDragController2(); - - // Initializes TabDragController2 to drag the tabs in |tabs| originating - // from |source_tabstrip|. |source_tab| is the tab that initiated the drag and - // is contained in |tabs|. |mouse_offset| is the distance of the mouse - // pointer from the origin of the first tab in |tabs| and |source_tab_offset| - // the offset from |source_tab|. |source_tab_offset| is the horizontal distant - // for a horizontal tab strip, and the vertical distance for a vertical tab - // strip. |initial_selection_model| is the selection model before the drag - // started and is only non-empty if |source_tab| was not initially selected. - void Init(TabStrip* source_tabstrip, - BaseTab* source_tab, - const std::vector<BaseTab*>& tabs, - const gfx::Point& mouse_offset, - int source_tab_offset, - const TabStripSelectionModel& initial_selection_model); - - // Returns true if there is an active TabDragController2 that is attached to - // |tab_strip|. - static bool IsActiveAndAttachedTo(TabStrip* tab_strip); - - // Returns true if there is an active TabDragController2. - static bool IsActive(); - - private: - class DockDisplayer; - friend class DockDisplayer; - - typedef std::set<gfx::NativeView> DockWindows; - - // Specifies what should happen when RunMoveLoop complets. - enum EndRunLoopBehavior { - // Indicates the drag should end. - END_RUN_LOOP_STOP_DRAGGING, - - // Indicates the drag should continue. - END_RUN_LOOP_CONTINUE_DRAGGING - }; - - // 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 - }; - - // Enumeration of the possible positions the detached tab may detach from. - enum DetachPosition { - DETACH_BEFORE, - DETACH_AFTER, - DETACH_ABOVE_OR_BELOW - }; - - // Stores the date associated with a single tab that is being dragged. - struct TabDragData { - TabDragData(); - ~TabDragData(); - - // The TabContentsWrapper being dragged. - TabContentsWrapper* contents; - - // This is the index of the 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; - - // If attached this is the tab in |attached_tabstrip_|. - BaseTab* attached_tab; - - // Is the tab pinned? - bool pinned; - }; - - typedef std::vector<TabDragData> DragData; - - // Sets |drag_data| from |tab|. This also registers for necessary - // notifications and resets the delegate of the TabContentsWrapper. - void InitTabDragData(BaseTab* tab, TabDragData* drag_data); - - // TabDragController overrides; - virtual void Drag() OVERRIDE; - virtual void EndDrag(bool canceled) OVERRIDE; - virtual bool GetStartedDrag() const OVERRIDE; - - // Overridden from content::NotificationObserver: - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE; - - // Overridden from MessageLoop::Observer: -#if defined(OS_WIN) || defined(USE_AURA) - virtual base::EventStatus WillProcessEvent( - const base::NativeEvent& event) OVERRIDE; - virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE; -#endif - - // Overriden from views::Widget::Observer: - virtual void OnWidgetMoved(views::Widget* widget) OVERRIDE; - - // Overriden from TabStripModelObserver: - virtual void TabStripEmpty() OVERRIDE; - - // Initialize the offset used to calculate the position to create windows - // in |GetWindowCreatePoint|. This should only be invoked from |Init|. - void InitWindowCreatePoint(TabStrip* tab_strip); - - // 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); - - // 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 tabs while the tabs are attached. - void MoveAttached(const gfx::Point& screen_point); - - // Returns the DetachPosition given the specified location in screen - // coordinates. - DetachPosition GetDetachPosition(const gfx::Point& screen_point); - - // Returns the TabStrip for the specified window, or NULL if one doesn't exist - // or isn't appropriate. - TabStrip* GetTabStripForWindow(gfx::NativeWindow window); - - // Returns the compatible TabStrip that is under the specified point (screen - // coordinates), or NULL if there is none. - TabStrip* GetTabStripForPoint(const gfx::Point& screen_point); - - DockInfo GetDockInfoAtPoint(const gfx::Point& screen_point); - - // Returns true if |tabstrip| contains the specified point in screen - // coordinates. - bool DoesTabStripContain(TabStrip* tabstrip, - const gfx::Point& screen_point) const; - - // Attach the dragged Tab to the specified TabStrip. - void Attach(TabStrip* attached_tabstrip, const gfx::Point& screen_point); - - // Detach the dragged Tab from the current TabStrip. - void Detach(); - - // Detaches the tabs being dragged, creates a new Browser to contain them and - // runs a nested move loop. - void DetachIntoNewBrowserAndRunMoveLoop(const gfx::Point& screen_point); - - // Runs a nested message loop that handles moving the current Browser. - void RunMoveLoop(); - - // Returns the index where the dragged WebContents should be inserted into - // |attached_tabstrip_| given the DraggedTabView's bounds |dragged_bounds| in - // coordinates relative to |attached_tabstrip_| and has had the mirroring - // transformation applied. - // NOTE: this is invoked from |Attach| before the tabs have been inserted. - int GetInsertionIndexForDraggedBounds(const gfx::Rect& dragged_bounds) const; - - // Retrieve the bounds of the DraggedTabView relative to the attached - // TabStrip. |tab_strip_point| is in the attached TabStrip's coordinate - // system. - gfx::Rect GetDraggedViewTabStripBounds(const gfx::Point& tab_strip_point); - - // Get the position of the dragged tab view relative to the attached tab - // strip with the mirroring transform applied. - gfx::Point GetAttachedDragPoint(const gfx::Point& screen_point); - - // Finds the Tabs within the specified TabStrip that corresponds to the - // WebContents of the dragged tabs. Returns an empty vector if not attached. - std::vector<BaseTab*> GetTabsMatchingDraggedContents(TabStrip* tabstrip); - - // 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(); - - // Reverts the tab at |drag_index| in |drag_data_|. - void RevertDragAt(size_t drag_index); - - // Selects the dragged tabs in |model|. Does nothing if there are no longer - // any dragged contents (as happens when a WebContents is deleted out from - // under us). - void ResetSelection(TabStripModel* model); - - // Finishes a succesful drag operation. - void CompleteDrag(); - - // 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; - - void DockDisplayerDestroyed(DockDisplayer* controller); - - void BringWindowUnderMouseToFront(); - - // Convenience for getting the TabDragData corresponding to the tab the user - // started dragging. - TabDragData* source_tab_drag_data() { - return &(drag_data_[source_tab_index_]); - } - - // Convenience for |source_tab_drag_data()->contents|. - TabContentsWrapper* source_dragged_contents() { - return source_tab_drag_data()->contents; - } - - // Returns true if the tabs were originality one after the other in - // |source_tabstrip_|. - bool AreTabsConsecutive(); - - // Returns the TabStripModel for the specified tabstrip. - static TabStripModel* GetModel(TabStrip* tabstrip); - - // Returns the Widget of the currently attached TabStrip's BrowserView. - views::Widget* GetAttachedBrowserWidget(); - - // Creates and returns a new Browser to handle the drag. - Browser* CreateBrowserForDrag(TabStrip* source, - const gfx::Point& screen_point, - std::vector<gfx::Rect>* drag_bounds); - - // Marks whether |window| is constrained. While dragging we set this to false - // to allow maximized windows to move any where. - void SetTrackedByWorkspace(gfx::NativeWindow window, bool value); - - // Handles registering for notifications. - content::NotificationRegistrar registrar_; - - // The TabStrip the drag originated from. This is set to NULL if the source - // tabstrip is deleted while we're detached. - TabStrip* source_tabstrip_; - - // The TabStrip the dragged Tab is currently attached to, or NULL if the - // dragged Tab is detached. - TabStrip* attached_tabstrip_; - - // Set to true if we've detached from a tabstrip and are running a nested - // move message loop. - bool is_dragging_window_; - - // 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_; - - // Offset of the mouse relative to the source tab. - int source_tab_offset_; - - // Ratio of the x-coordinate of the |source_tab_offset_| to the width of the - // tab. Not used for vertical tabs. - 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. - // TODO(sky): clean this up, can likely be removed. - 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_; - - // 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<TabDragController2> bring_to_front_timer_; - - // Did the mouse move enough that we started a drag? - bool started_drag_; - - // Is the drag active? - bool active_; - - DragData drag_data_; - - // Index of the source tab in drag_data_. - size_t source_tab_index_; - - // True until |MoveAttached| is invoked once. - bool initial_move_; - - // The selection model before the drag started. See comment above Init() for - // details. - TabStripSelectionModel initial_selection_model_; - - // The selection model of |attached_tabstrip_| before the tabs were attached. - TabStripSelectionModel selection_model_before_attach_; - - EndRunLoopBehavior end_run_loop_behavior_; - - // If true, we're waiting for a move loop to complete. - bool waiting_for_run_loop_to_exit_; - - // The TabStrip to attach to after the move loop completes. - TabStrip* tab_strip_to_attach_to_after_exit_; - - // Non-null for the duration of RunMoveLoop. - views::Widget* move_loop_widget_; - - // If non-null set to true from destructor. - bool* destroyed_; - - DISALLOW_COPY_AND_ASSIGN(TabDragController2); -}; - -#endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER2_H_ diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller2_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller2_interactive_uitest.cc index 3e0390a..7984afc 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller2_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller2_interactive_uitest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/views/tabs/tab_drag_controller2.h" +#include "chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h" #include "base/bind.h" #include "base/callback.h" @@ -14,6 +14,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/tabs/default_tab_drag_controller.h" #include "chrome/browser/ui/views/tabs/tab.h" #include "chrome/browser/ui/views/tabs/tab_strip.h" #include "chrome/common/chrome_switches.h" @@ -30,9 +31,8 @@ #include "ui/views/view.h" #include "ui/views/widget/widget.h" -namespace { +namespace test { -// See comments above QuitWhenNotDragging. class QuitDraggingObserver : public content::NotificationObserver { public: QuitDraggingObserver() { @@ -98,59 +98,70 @@ void QuitWhenNotDragging() { new QuitDraggingObserver(); // QuitDraggingObserver deletes itself. } +TabStrip* GetTabStripForBrowser(Browser* browser) { + BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser); + return static_cast<TabStrip*>(browser_view->tabstrip()); } -class TabDragController2Test : public InProcessBrowserTest { - public: - TabDragController2Test() {} +} // namespace test - static TabStrip* GetTabStripForBrowser(Browser* browser) { - BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser); - return static_cast<TabStrip*>(browser_view->tabstrip()); - } +using test::GetCenterInScreenCoordinates; +using test::SetID; +using test::ResetIDs; +using test::IDString; +using test::QuitWhenNotDragging; +using test::GetTabStripForBrowser; - void StopAnimating(TabStrip* tab_strip) { - tab_strip->StopAnimating(true); - } +TabDragControllerTest::TabDragControllerTest() { +} - void AddTabAndResetBrowser(Browser* browser) { - AddBlankTabAndShow(browser); - StopAnimating(GetTabStripForBrowser(browser)); - ResetIDs(browser->tabstrip_model(), 0); - } +TabDragControllerTest::~TabDragControllerTest() { +} - // Creates another window and resizes |browser()| and the new browser to - // be side by side. - Browser* CreateAnotherWindowBrowserAndRelayout() { - // Add another tab. - AddTabAndResetBrowser(browser()); - - // Create another browser. - Browser* browser2 = CreateBrowser(browser()->profile()); - ResetIDs(browser2->tabstrip_model(), 100); - - // Resize the two windows so they're right next to each other. - gfx::Rect work_area = gfx::Screen::GetMonitorNearestWindow( - browser()->window()->GetNativeHandle()).work_area(); - gfx::Size half_size = - gfx::Size(work_area.width() / 3 - 10, work_area.height() / 2 - 10); - browser()->window()->SetBounds(gfx::Rect(work_area.origin(), half_size)); - browser2->window()->SetBounds(gfx::Rect( - work_area.x() + half_size.width(), work_area.y(), - half_size.width(), half_size.height())); - return browser2; - } +void TabDragControllerTest::StopAnimating(TabStrip* tab_strip) { + tab_strip->StopAnimating(true); +} + +void TabDragControllerTest::AddTabAndResetBrowser(Browser* browser) { + AddBlankTabAndShow(browser); + StopAnimating(GetTabStripForBrowser(browser)); + ResetIDs(browser->tabstrip_model(), 0); +} + +Browser* TabDragControllerTest::CreateAnotherWindowBrowserAndRelayout() { + // Add another tab. + AddTabAndResetBrowser(browser()); + + // Create another browser. + Browser* browser2 = CreateBrowser(browser()->profile()); + ResetIDs(browser2->tabstrip_model(), 100); + + // Resize the two windows so they're right next to each other. + gfx::Rect work_area = gfx::Screen::GetMonitorNearestWindow( + browser()->window()->GetNativeHandle()).work_area(); + gfx::Size half_size = + gfx::Size(work_area.width() / 3 - 10, work_area.height() / 2 - 10); + browser()->window()->SetBounds(gfx::Rect(work_area.origin(), half_size)); + browser2->window()->SetBounds(gfx::Rect( + work_area.x() + half_size.width(), work_area.y(), + half_size.width(), half_size.height())); + return browser2; +} + +class DetachToBrowserTabDragControllerTest : public TabDragControllerTest { + public: + DetachToBrowserTabDragControllerTest() {} virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { command_line->AppendSwitch(switches::kTabBrowserDragging); } private: - DISALLOW_COPY_AND_ASSIGN(TabDragController2Test); + DISALLOW_COPY_AND_ASSIGN(DetachToBrowserTabDragControllerTest); }; // Creates a browser with two tabs, drags the second to the first. -IN_PROC_BROWSER_TEST_F(TabDragController2Test, DragInSameWindow) { +IN_PROC_BROWSER_TEST_F(DetachToBrowserTabDragControllerTest, DragInSameWindow) { AddTabAndResetBrowser(browser()); TabStrip* tab_strip = GetTabStripForBrowser(browser()); @@ -165,7 +176,7 @@ IN_PROC_BROWSER_TEST_F(TabDragController2Test, DragInSameWindow) { ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( ui_controls::LEFT, ui_controls::UP)); EXPECT_EQ("1 0", IDString(model)); - EXPECT_FALSE(TabDragController2::IsActive()); + EXPECT_FALSE(TabDragController::IsActive()); EXPECT_FALSE(tab_strip->IsDragSessionActive()); } @@ -189,7 +200,8 @@ void DragToSeparateWindowStep2(TabStrip* not_attached_tab_strip, } // namespace // Creates two browsers, drags from first into second. -IN_PROC_BROWSER_TEST_F(TabDragController2Test, DragToSeparateWindow) { +IN_PROC_BROWSER_TEST_F(DetachToBrowserTabDragControllerTest, + DragToSeparateWindow) { TabStrip* tab_strip = GetTabStripForBrowser(browser()); // Create another browser. @@ -227,7 +239,8 @@ IN_PROC_BROWSER_TEST_F(TabDragController2Test, DragToSeparateWindow) { } // Drags from browser to separate window and releases mouse. -IN_PROC_BROWSER_TEST_F(TabDragController2Test, DetachToOwnWindow) { +IN_PROC_BROWSER_TEST_F(DetachToBrowserTabDragControllerTest, + DetachToOwnWindow) { // Add another tab. AddTabAndResetBrowser(browser()); TabStrip* tab_strip = GetTabStripForBrowser(browser()); @@ -263,7 +276,8 @@ IN_PROC_BROWSER_TEST_F(TabDragController2Test, DetachToOwnWindow) { } // Deletes a tab being dragged before the user moved enough to start a drag. -IN_PROC_BROWSER_TEST_F(TabDragController2Test, DeleteBeforeStartedDragging) { +IN_PROC_BROWSER_TEST_F(DetachToBrowserTabDragControllerTest, + DeleteBeforeStartedDragging) { // Add another tab. AddTabAndResetBrowser(browser()); TabStrip* tab_strip = GetTabStripForBrowser(browser()); @@ -289,7 +303,8 @@ IN_PROC_BROWSER_TEST_F(TabDragController2Test, DeleteBeforeStartedDragging) { } // Deletes a tab being dragged while still attached. -IN_PROC_BROWSER_TEST_F(TabDragController2Test, DeleteTabWhileAttached) { +IN_PROC_BROWSER_TEST_F(DetachToBrowserTabDragControllerTest, + DeleteTabWhileAttached) { // Add another tab. AddTabAndResetBrowser(browser()); TabStrip* tab_strip = GetTabStripForBrowser(browser()); @@ -327,7 +342,8 @@ void DeleteWhileDetachedStep2(TabContentsWrapper* tab) { // Deletes a tab being dragged after dragging a tab so that a new window is // created. -IN_PROC_BROWSER_TEST_F(TabDragController2Test, DeleteTabWhileDetached) { +IN_PROC_BROWSER_TEST_F(DetachToBrowserTabDragControllerTest, + DeleteTabWhileDetached) { // Add another tab. AddTabAndResetBrowser(browser()); TabStrip* tab_strip = GetTabStripForBrowser(browser()); @@ -367,7 +383,8 @@ void DeleteSourceDetachedStep2(TabContentsWrapper* tab) { // Detaches a tab and while detached deletes a tab from the source so that the // source window closes then presses escape to cancel the drag. -IN_PROC_BROWSER_TEST_F(TabDragController2Test, DeleteSourceDetached) { +IN_PROC_BROWSER_TEST_F(DetachToBrowserTabDragControllerTest, + DeleteSourceDetached) { // Add another tab. AddTabAndResetBrowser(browser()); TabStrip* tab_strip = GetTabStripForBrowser(browser()); @@ -406,7 +423,7 @@ void PressEscapeWhileDetachedStep2() { // This is disabled until NativeViewHost::Detach really detaches. // Detaches a tab and while detached presses escape to revert the drag. -IN_PROC_BROWSER_TEST_F(TabDragController2Test, +IN_PROC_BROWSER_TEST_F(DetachToBrowserTabDragControllerTest, DISABLED_PressEscapeWhileDetached) { // Add another tab. AddTabAndResetBrowser(browser()); @@ -448,7 +465,7 @@ void DragAllStep2() { } // namespace // Selects multiple tabs and starts dragging the window. -IN_PROC_BROWSER_TEST_F(TabDragController2Test, DragAll) { +IN_PROC_BROWSER_TEST_F(DetachToBrowserTabDragControllerTest, DragAll) { // Add another tab. AddTabAndResetBrowser(browser()); TabStrip* tab_strip = GetTabStripForBrowser(browser()); @@ -500,7 +517,8 @@ void DragAllToSeparateWindowStep2(TabStrip* attached_tab_strip, } // namespace // Creates two browsers, selects all tabs in first and drags into second. -IN_PROC_BROWSER_TEST_F(TabDragController2Test, DragAllToSeparateWindow) { +IN_PROC_BROWSER_TEST_F(DetachToBrowserTabDragControllerTest, + DragAllToSeparateWindow) { TabStrip* tab_strip = GetTabStripForBrowser(browser()); // Create another browser. @@ -560,7 +578,7 @@ void DragAllToSeparateWindowAndCancelStep2(TabStrip* attached_tab_strip, // Creates two browsers, selects all tabs in first, drags into second, then hits // escape. -IN_PROC_BROWSER_TEST_F(TabDragController2Test, +IN_PROC_BROWSER_TEST_F(DetachToBrowserTabDragControllerTest, DragAllToSeparateWindowAndCancel) { TabStrip* tab_strip = GetTabStripForBrowser(browser()); diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h new file mode 100644 index 0000000..401342e --- /dev/null +++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h @@ -0,0 +1,72 @@ +// Copyright (c) 2012 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_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER_INTERACTIVE_UITEST_H_ +#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER_INTERACTIVE_UITEST_H_ +#pragma once + +#include <string> + +#include "chrome/test/base/in_process_browser_test.h" + +class Browser; +class TabStrip; +class TabStripModel; + +namespace content { +class WebContents; +} + +namespace gfx { +class Point; +} + +namespace views { +class View; +} + +// TabDragControllerTest is the basis for the two tests that exercise +// TabDragController. +class TabDragControllerTest : public InProcessBrowserTest { + public: + TabDragControllerTest(); + virtual ~TabDragControllerTest(); + + // Cover for TabStrip::StopAnimating(true). + void StopAnimating(TabStrip* tab_strip); + + // Adds a new blank tab to |browser|, stops animations and resets the ids of + // the tabs in |browser|. + void AddTabAndResetBrowser(Browser* browser); + + // Creates a new Browser and resizes |browser()| and the new browser to be + // side by side. + Browser* CreateAnotherWindowBrowserAndRelayout(); + + private: + DISALLOW_COPY_AND_ASSIGN(TabDragControllerTest); +}; + +namespace test { + +// Returns the TabStrip for |browser|. +TabStrip* GetTabStripForBrowser(Browser* browser); + +// Returns the center of |view| in screen coordinates. +gfx::Point GetCenterInScreenCoordinates(const views::View* view); + +// Sets the id of |tab_contents| to |id|. +void SetID(content::WebContents* tab_contents, int id); + +// Resets the ids of all the tabs in |model| starting at |start|. That is, the +// id of the first tab is set to |start|, the second tab |start + 1| ... +void ResetIDs(TabStripModel* model, int start); + +// Returns a string representation of the ids of the tabs in |model|. Each id +// is separated by a space. +std::string IDString(TabStripModel* model); + +} + +#endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER_INTERACTIVE_UITEST_H_ diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest_win.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest_win.cc new file mode 100644 index 0000000..b5eded7 --- /dev/null +++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest_win.cc @@ -0,0 +1,354 @@ +// Copyright (c) 2012 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. + +#include "chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h" + +#include "base/bind.h" +#include "base/callback.h" +#include "base/command_line.h" +#include "base/property_bag.h" +#include "base/string_number_conversions.h" +#include "chrome/browser/tabs/tab_strip_model.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/tabs/default_tab_drag_controller.h" +#include "chrome/browser/ui/views/tabs/tab.h" +#include "chrome/browser/ui/views/tabs/tab_strip.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_source.h" +#include "content/public/browser/web_contents.h" +#include "ui/ui_controls/ui_controls.h" +#include "ui/gfx/screen.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +using test::GetCenterInScreenCoordinates; +using test::SetID; +using test::ResetIDs; +using test::IDString; +using test::GetTabStripForBrowser; + +// The tests in this file exercise detaching the dragged tab into a standalone +// window (not a Browser). + +// Creates a browser with two tabs, drags the second to the first. +IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DragInSameWindow) { + AddTabAndResetBrowser(browser()); + + TabStrip* tab_strip = GetTabStripForBrowser(browser()); + TabStripModel* model = browser()->tabstrip_model(); + + gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1))); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_1_center)); + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::DOWN)); + gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::UP)); + EXPECT_EQ("1 0", IDString(model)); + EXPECT_FALSE(TabDragController::IsActive()); + EXPECT_FALSE(tab_strip->IsDragSessionActive()); +} + +// Creates two browsers, drags from first into second. +IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DragToSeparateWindow) { + TabStrip* tab_strip = GetTabStripForBrowser(browser()); + + // Create another browser. + Browser* browser2 = CreateAnotherWindowBrowserAndRelayout(); + TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); + + // Move to the first tab and drag it enough so that it detaches, but not + // enough that it attaches to browser2. + gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::DOWN)); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( + gfx::Point(tab_0_center.x(), + tab_0_center.y() + tab_strip->height() + 20))); + ASSERT_TRUE(TabDragController::IsActive()); + + // Drag into the second browser. + gfx::Point target_point(tab_strip2->width() -1, tab_strip2->height() / 2); + views::View::ConvertPointToScreen(tab_strip2, &target_point); + ASSERT_TRUE(ui_controls::SendMouseMove(target_point.x(), target_point.y())); + + ASSERT_TRUE(TabDragController::IsActive()); + + // Release the mouse, ending the drag session. + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::UP)); + ASSERT_FALSE(tab_strip2->IsDragSessionActive()); + ASSERT_FALSE(tab_strip->IsDragSessionActive()); + ASSERT_FALSE(TabDragController::IsActive()); + EXPECT_EQ("100 0", IDString(browser2->tabstrip_model())); + EXPECT_EQ("1", IDString(browser()->tabstrip_model())); +} + +// Drags from browser to separate window and releases mouse. +IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DetachToOwnWindow) { + // Add another tab. + AddTabAndResetBrowser(browser()); + TabStrip* tab_strip = GetTabStripForBrowser(browser()); + + // Move to the first tab and drag it enough so that it detaches. + gfx::Point tab_0_center( + GetCenterInScreenCoordinates(tab_strip->tab_at(0))); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::DOWN)); + ASSERT_TRUE(ui_controls::SendMouseMove( + tab_0_center.x(), tab_0_center.y() + tab_strip->height() + 20)); + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::UP)); + + // Should no longer be dragging. + ASSERT_FALSE(tab_strip->IsDragSessionActive()); + ASSERT_FALSE(TabDragController::IsActive()); + + // There should now be another browser. + ASSERT_EQ(2u, BrowserList::size()); + Browser* new_browser = BrowserList::GetLastActive(); + ASSERT_NE(browser(), new_browser); + TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser); + ASSERT_FALSE(tab_strip2->IsDragSessionActive()); + + EXPECT_EQ("0", IDString(new_browser->tabstrip_model())); + EXPECT_EQ("1", IDString(browser()->tabstrip_model())); +} + +// Deletes a tab being dragged before the user moved enough to start a drag. +IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DeleteBeforeStartedDragging) { + // Add another tab. + AddTabAndResetBrowser(browser()); + TabStrip* tab_strip = GetTabStripForBrowser(browser()); + + // Click on the first tab, but don't move it. + gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::DOWN)); + + // Should be dragging. + ASSERT_TRUE(tab_strip->IsDragSessionActive()); + ASSERT_TRUE(TabDragController::IsActive()); + + // Delete the tab being dragged. + delete browser()->tabstrip_model()->GetTabContentsAt(0); + + // Should have canceled dragging. + ASSERT_FALSE(tab_strip->IsDragSessionActive()); + ASSERT_FALSE(TabDragController::IsActive()); + + EXPECT_EQ("1", IDString(browser()->tabstrip_model())); +} + +// Deletes a tab being dragged while still attached. +IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DeleteTabWhileAttached) { + // Add another tab. + AddTabAndResetBrowser(browser()); + TabStrip* tab_strip = GetTabStripForBrowser(browser()); + + // Click on the first tab and move it enough so that it starts dragging but is + // still attached. + gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::DOWN)); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( + gfx::Point(tab_0_center.x() + 20, tab_0_center.y()))); + + // Should be dragging. + ASSERT_TRUE(tab_strip->IsDragSessionActive()); + ASSERT_TRUE(TabDragController::IsActive()); + + // Delete the tab being dragged. + delete browser()->tabstrip_model()->GetTabContentsAt(0); + + // Should have canceled dragging. + ASSERT_FALSE(tab_strip->IsDragSessionActive()); + ASSERT_FALSE(TabDragController::IsActive()); + + EXPECT_EQ("1", IDString(browser()->tabstrip_model())); +} + +// Deletes a tab being dragged after dragging a tab so that a new window is +// created. +IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DeleteTabWhileDetached) { + // Add another tab. + AddTabAndResetBrowser(browser()); + TabStrip* tab_strip = GetTabStripForBrowser(browser()); + + // Move to the first tab and drag it enough so that it detaches. + gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); + TabContentsWrapper* to_delete = + browser()->tabstrip_model()->GetTabContentsAt(0); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::DOWN)); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( + gfx::Point(tab_0_center.x(), + tab_0_center.y() + tab_strip->height() + 20))); + delete to_delete; + + // Should not be dragging. + ASSERT_FALSE(tab_strip->IsDragSessionActive()); + ASSERT_FALSE(TabDragController::IsActive()); + + EXPECT_EQ("1", IDString(browser()->tabstrip_model())); +} + +namespace { + +void DeleteSourceDetachedStep2(TabContentsWrapper* tab) { + // This ends up closing the source window. + delete tab; + // Cancel the drag. + ui_controls::SendKeyPress(NULL, ui::VKEY_ESCAPE, false, false, false, false); +} + +} // namespace + +// Detaches a tab and while detached deletes a tab from the source and releases +// the mouse. +IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DeleteSourceDetached) { + // Add another tab. + AddTabAndResetBrowser(browser()); + TabStrip* tab_strip = GetTabStripForBrowser(browser()); + + // Move to the first tab and drag it enough so that it detaches. + gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); + TabContentsWrapper* to_delete = + browser()->tabstrip_model()->GetTabContentsAt(1); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::DOWN)); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( + gfx::Point(tab_0_center.x(), + tab_0_center.y() + tab_strip->height() + 20))); + delete to_delete; + + // Should still be dragging. + ASSERT_TRUE(tab_strip->IsDragSessionActive()); + ASSERT_TRUE(TabDragController::IsActive()); + + // Release the mouse. + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::UP)); + + // Releasing the mouse should destroy the existing browser and create a new + // one. + ASSERT_EQ(1u, BrowserList::size()); + Browser* new_browser = *BrowserList::begin(); + EXPECT_NE(new_browser, browser()); + + ASSERT_FALSE(GetTabStripForBrowser(new_browser)->IsDragSessionActive()); + ASSERT_FALSE(TabDragController::IsActive()); + + EXPECT_EQ("0", IDString(new_browser->tabstrip_model())); +} + +// Creates two browsers, selects all tabs in first and drags into second. +IN_PROC_BROWSER_TEST_F(TabDragControllerTest, DragAllToSeparateWindow) { + TabStrip* tab_strip = GetTabStripForBrowser(browser()); + + // Create another browser. + Browser* browser2 = CreateAnotherWindowBrowserAndRelayout(); + TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); + + browser()->tabstrip_model()->AddTabAtToSelection(0); + browser()->tabstrip_model()->AddTabAtToSelection(1); + + // Move to the first tab and drag it enough so that it detaches, but not + // enough that it attaches to browser2. + gfx::Point tab_0_center( + GetCenterInScreenCoordinates(tab_strip->tab_at(0))); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::DOWN)); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( + gfx::Point(tab_0_center.x(), + tab_0_center.y() + tab_strip->height() + 20))); + + ASSERT_TRUE(tab_strip->IsDragSessionActive()); + ASSERT_FALSE(tab_strip2->IsDragSessionActive()); + ASSERT_TRUE(TabDragController::IsActive()); + ASSERT_EQ(2u, BrowserList::size()); + + // Drag to tab_strip2. + gfx::Point target_point(tab_strip2->width() - 1, + tab_strip2->height() / 2); + views::View::ConvertPointToScreen(tab_strip2, &target_point); + ASSERT_TRUE(ui_controls::SendMouseMove(target_point.x(), target_point.y())); + + // Should now be attached to tab_strip2. + ASSERT_TRUE(tab_strip->IsDragSessionActive()); + ASSERT_TRUE(TabDragController::IsActive()); + + // Release the mouse, stopping the drag session. + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::UP)); + ASSERT_FALSE(TabDragController::IsActive()); + EXPECT_EQ("100 0 1", IDString(browser2->tabstrip_model())); +} + +// Creates two browsers, selects all tabs in first, drags into second, then hits +// escape. +IN_PROC_BROWSER_TEST_F(TabDragControllerTest, + DragAllToSeparateWindowAndCancel) { + TabStrip* tab_strip = GetTabStripForBrowser(browser()); + + // Create another browser. + Browser* browser2 = CreateAnotherWindowBrowserAndRelayout(); + TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); + + browser()->tabstrip_model()->AddTabAtToSelection(0); + browser()->tabstrip_model()->AddTabAtToSelection(1); + + // Move to the first tab and drag it enough so that it detaches, but not + // enough that it attaches to browser2. + gfx::Point tab_0_center( + GetCenterInScreenCoordinates(tab_strip->tab_at(0))); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_0_center)); + ASSERT_TRUE(ui_test_utils::SendMouseEventsSync( + ui_controls::LEFT, ui_controls::DOWN)); + ASSERT_TRUE(ui_test_utils::SendMouseMoveSync( + gfx::Point(tab_0_center.x(), + tab_0_center.y() + tab_strip->height() + 20))); + ASSERT_TRUE(tab_strip->IsDragSessionActive()); + ASSERT_FALSE(tab_strip2->IsDragSessionActive()); + ASSERT_TRUE(TabDragController::IsActive()); + ASSERT_EQ(2u, BrowserList::size()); + + // Drag to tab_strip2. + gfx::Point target_point(tab_strip2->width() - 1, + tab_strip2->height() / 2); + views::View::ConvertPointToScreen(tab_strip2, &target_point); + ASSERT_TRUE(ui_controls::SendMouseMove(target_point.x(), target_point.y())); + + ASSERT_TRUE(tab_strip->IsDragSessionActive()); + ASSERT_TRUE(TabDragController::IsActive()); + ASSERT_EQ(2u, BrowserList::size()); + + // Cancel the drag. + ASSERT_TRUE(ui_test_utils::SendKeyPressSync( + browser2, ui::VKEY_ESCAPE, false, false, false, false)); + + ASSERT_FALSE(tab_strip->IsDragSessionActive()); + ASSERT_FALSE(tab_strip2->IsDragSessionActive()); + ASSERT_FALSE(TabDragController::IsActive()); + ASSERT_EQ(2u, BrowserList::size()); + EXPECT_EQ("0 1", IDString(browser()->tabstrip_model())); + EXPECT_EQ("100", IDString(browser2->tabstrip_model())); +} diff --git a/chrome/browser/ui/views/tabs/tab_dragging_test.cc b/chrome/browser/ui/views/tabs/tab_dragging_test.cc deleted file mode 100644 index 900d2a2..0000000 --- a/chrome/browser/ui/views/tabs/tab_dragging_test.cc +++ /dev/null @@ -1,514 +0,0 @@ -// Copyright (c) 2011 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. - -#include "base/command_line.h" -#include "base/file_util.h" -#include "chrome/app/chrome_command_ids.h" -#include "chrome/browser/ui/view_ids.h" -#include "chrome/common/chrome_paths.h" -#include "chrome/test/automation/automation_proxy.h" -#include "chrome/test/automation/browser_proxy.h" -#include "chrome/test/automation/tab_proxy.h" -#include "chrome/test/automation/window_proxy.h" -#include "chrome/test/ui/ui_test.h" -#include "googleurl/src/gurl.h" -#include "net/base/net_util.h" -#include "ui/gfx/rect.h" -#include "ui/views/events/event.h" - -#if defined(OS_LINUX) -// This test doesn't make sense on chromeos as chromeos doesn't allow dragging -// tabs out. -#define MAYBE_Tab2OutOfTabStrip DISABLED_Tab2OutOfTabStrip -#else -// Flaky, http://crbug.com/62311. -#define MAYBE_Tab2OutOfTabStrip DISABLED_Tab2OutOfTabStrip -#endif - -#if defined(OS_LINUX) -// Disabled on Toolkit views bot. See http://crbug.com/42614 -#define MAYBE_Tab1Tab3Escape DISABLED_Tab1Tab3Escape -#elif defined(OS_WIN) -// Disabled on Windows. See http://crbug.com/57687 -#define MAYBE_Tab1Tab3Escape DISABLED_Tab1Tab3Escape -#else -#define MAYBE_Tab1Tab3Escape Tab1Tab3Escape -#endif - -// These tests fail on Linux because we haven't implemented all of tab dragging -// (it's not needed on chromeos). See http://crbug.com/10941 -#if defined(OS_LINUX) -#define MAYBE_Tab1Tab2 DISABLED_Tab1Tab2 -#define MAYBE_Tab1Tab3 DISABLED_Tab1Tab3 -#else -// Flaky, http://crbug.com/62311. -#define MAYBE_Tab1Tab2 DISABLED_Tab1Tab2 -#define MAYBE_Tab1Tab3 DISABLED_Tab1Tab3 -#endif - -class TabDraggingTest : public UITest { - protected: - TabDraggingTest() { - show_window_ = true; - } -}; - -// Automated UI test to open three tabs in a new window, and drag Tab_1 into -// the position of Tab_2. -TEST_F(TabDraggingTest, MAYBE_Tab1Tab2) { - scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); - ASSERT_TRUE(browser.get()); - scoped_refptr<WindowProxy> window(browser->GetWindow()); - ASSERT_TRUE(window.get()); - - // Get initial tab count. - int initial_tab_count = 0; - ASSERT_TRUE(browser->GetTabCount(&initial_tab_count)); - ASSERT_TRUE(1 == initial_tab_count); - - // Get Tab_1 which comes with the browser window. - scoped_refptr<TabProxy> tab1(browser->GetTab(0)); - ASSERT_TRUE(tab1.get()); - GURL tab1_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_url)); - - // Add Tab_2. - GURL tab2_url("about:"); - ASSERT_TRUE(browser->AppendTab(tab2_url)); - scoped_refptr<TabProxy> tab2(browser->GetTab(1)); - ASSERT_TRUE(tab2.get()); - - // Add Tab_3. - GURL tab3_url("about:plugins"); - ASSERT_TRUE(browser->AppendTab(tab3_url)); - scoped_refptr<TabProxy> tab3(browser->GetTab(2)); - ASSERT_TRUE(tab3.get()); - - // Make sure 3 tabs are open. - ASSERT_TRUE(browser->WaitForTabCountToBecome(initial_tab_count + 2)); - - // Get bounds for the tabs. - gfx::Rect bounds1; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_0, &bounds1, false)); - EXPECT_LT(0, bounds1.x()); - EXPECT_LT(0, bounds1.width()); - EXPECT_LT(0, bounds1.height()); - - gfx::Rect bounds2; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_1, &bounds2, false)); - EXPECT_LT(0, bounds2.width()); - EXPECT_LT(0, bounds2.height()); - EXPECT_LT(bounds1.x(), bounds2.x()); - EXPECT_EQ(bounds2.y(), bounds1.y()); - - gfx::Rect bounds3; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_2, &bounds3, false)); - EXPECT_LT(0, bounds3.width()); - EXPECT_LT(0, bounds3.height()); - EXPECT_LT(bounds2.x(), bounds3.x()); - EXPECT_EQ(bounds3.y(), bounds2.y()); - - // Get url Bar bounds. - gfx::Rect urlbar_bounds; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_LOCATION_BAR, &urlbar_bounds, - false)); - EXPECT_LT(0, urlbar_bounds.x()); - EXPECT_LT(0, urlbar_bounds.y()); - EXPECT_LT(0, urlbar_bounds.width()); - EXPECT_LT(0, urlbar_bounds.height()); - - /* - TEST: Move Tab_1 to the position of Tab_2 - ____________ ____________ ____________ - / \ / \ / \ - | Tab_1 | Tab_2 | Tab_3 | - ---- ---- ---- ---- ---- ---- ---- ---- ---- - x---- ----> - ____________ - / X \ - | Tab_1 | - ---- ---- ---- - */ - - gfx::Point start(bounds1.x() + bounds1.width() / 2, - bounds1.y() + bounds1.height() / 2); - gfx::Point end(start.x() + 2 * bounds1.width() / 3, start.y()); - ASSERT_TRUE(browser->SimulateDrag(start, end, - ui::EF_LEFT_MOUSE_BUTTON, - false)); - - // Now check for expected results. - tab1 = browser->GetTab(0); - ASSERT_TRUE(tab1.get()); - GURL tab1_new_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_new_url)); - - tab2 = browser->GetTab(1); - ASSERT_TRUE(tab2.get()); - GURL tab2_new_url; - ASSERT_TRUE(tab2->GetCurrentURL(&tab2_new_url)); - - EXPECT_EQ(tab1_url.spec(), tab2_new_url.spec()); - EXPECT_EQ(tab2_url.spec(), tab1_new_url.spec()); -} - -// Drag Tab_1 into the position of Tab_3. -TEST_F(TabDraggingTest, MAYBE_Tab1Tab3) { - scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); - ASSERT_TRUE(browser.get()); - scoped_refptr<WindowProxy> window(browser->GetWindow()); - ASSERT_TRUE(window.get()); - - // Get initial tab count. - int initial_tab_count = 0; - ASSERT_TRUE(browser->GetTabCount(&initial_tab_count)); - ASSERT_TRUE(1 == initial_tab_count); - - // Get Tab_1 which comes with the browser window. - scoped_refptr<TabProxy> tab1(browser->GetTab(0)); - ASSERT_TRUE(tab1.get()); - GURL tab1_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_url)); - - // Add Tab_2. - GURL tab2_url("about:"); - ASSERT_TRUE(browser->AppendTab(tab2_url)); - scoped_refptr<TabProxy> tab2(browser->GetTab(1)); - ASSERT_TRUE(tab2.get()); - - // Add Tab_3. - GURL tab3_url("about:plugins"); - ASSERT_TRUE(browser->AppendTab(tab3_url)); - scoped_refptr<TabProxy> tab3(browser->GetTab(2)); - ASSERT_TRUE(tab3.get()); - - // Make sure 3 tabs are open. - ASSERT_TRUE(browser->WaitForTabCountToBecome(initial_tab_count + 2)); - - // Get bounds for the tabs. - gfx::Rect bounds1; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_0, &bounds1, false)); - EXPECT_LT(0, bounds1.x()); - EXPECT_LT(0, bounds1.width()); - EXPECT_LT(0, bounds1.height()); - - gfx::Rect bounds2; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_1, &bounds2, false)); - EXPECT_LT(0, bounds2.width()); - EXPECT_LT(0, bounds2.height()); - EXPECT_LT(bounds1.x(), bounds2.x()); - EXPECT_EQ(bounds2.y(), bounds1.y()); - - gfx::Rect bounds3; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_2, &bounds3, false)); - EXPECT_LT(0, bounds3.width()); - EXPECT_LT(0, bounds3.height()); - EXPECT_LT(bounds2.x(), bounds3.x()); - EXPECT_EQ(bounds3.y(), bounds2.y()); - - // Get url Bar bounds. - gfx::Rect urlbar_bounds; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_LOCATION_BAR, &urlbar_bounds, - false)); - EXPECT_LT(0, urlbar_bounds.x()); - EXPECT_LT(0, urlbar_bounds.y()); - EXPECT_LT(0, urlbar_bounds.width()); - EXPECT_LT(0, urlbar_bounds.height()); - - /* - TEST: Move Tab_1 to the middle position of Tab_3 - ____________ ____________ ____________ - / \ / \ / \ - | Tab_1 | Tab_2 | Tab_3 | - ---- ---- ---- ---- ---- ---- ---- ---- ---- - x---- ---- ---- ---- ---- ----> - ____________ - / X \ - | Tab_1 | - ---- ---- ---- - */ - - gfx::Point start(bounds1.x() + bounds1.width() / 2, - bounds1.y() + bounds1.height() / 2); - gfx::Point end(start.x() + bounds1.width() / 2 + bounds2.width() + - bounds3.width() / 2, - start.y()); - ASSERT_TRUE(browser->SimulateDrag(start, end, - ui::EF_LEFT_MOUSE_BUTTON, - false)); - - // Now check for expected results. - tab1 = browser->GetTab(0); - ASSERT_TRUE(tab1.get()); - GURL tab1_new_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_new_url)); - - tab2 = browser->GetTab(1); - ASSERT_TRUE(tab2.get()); - GURL tab2_new_url; - ASSERT_TRUE(tab2->GetCurrentURL(&tab2_new_url)); - - tab3 = browser->GetTab(2); - ASSERT_TRUE(tab3.get()); - GURL tab3_new_url; - ASSERT_TRUE(tab3->GetCurrentURL(&tab3_new_url)); - - EXPECT_EQ(tab1_new_url.spec(), tab2_url.spec()); - EXPECT_EQ(tab2_new_url.spec(), tab3_url.spec()); - EXPECT_EQ(tab3_new_url.spec(), tab1_url.spec()); -} - -// Drag Tab_1 into the position of Tab_3, and press ESCAPE before releasing the -// left mouse button. -TEST_F(TabDraggingTest, MAYBE_Tab1Tab3Escape) { - scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); - ASSERT_TRUE(browser.get()); - scoped_refptr<WindowProxy> window(browser->GetWindow()); - ASSERT_TRUE(window.get()); - - // Get initial tab count. - int initial_tab_count = 0; - ASSERT_TRUE(browser->GetTabCount(&initial_tab_count)); - ASSERT_TRUE(1 == initial_tab_count); - - // Get Tab_1 which comes with the browser window. - scoped_refptr<TabProxy> tab1(browser->GetTab(0)); - ASSERT_TRUE(tab1.get()); - GURL tab1_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_url)); - - // Add Tab_2. - GURL tab2_url("about:blank"); - ASSERT_TRUE(browser->AppendTab(tab2_url)); - scoped_refptr<TabProxy> tab2(browser->GetTab(1)); - ASSERT_TRUE(tab2.get()); - - // Add Tab_3. - GURL tab3_url("about:plugins"); - ASSERT_TRUE(browser->AppendTab(tab3_url)); - scoped_refptr<TabProxy> tab3(browser->GetTab(2)); - ASSERT_TRUE(tab3.get()); - - // Make sure 3 tabs are open. - ASSERT_TRUE(browser->WaitForTabCountToBecome(initial_tab_count + 2)); - - // Get bounds for the tabs. - gfx::Rect bounds1; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_0, &bounds1, false)); - EXPECT_LT(0, bounds1.x()); - EXPECT_LT(0, bounds1.width()); - EXPECT_LT(0, bounds1.height()); - - gfx::Rect bounds2; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_1, &bounds2, false)); - EXPECT_LT(0, bounds2.width()); - EXPECT_LT(0, bounds2.height()); - EXPECT_LT(bounds1.x(), bounds2.x()); - EXPECT_EQ(bounds2.y(), bounds1.y()); - - gfx::Rect bounds3; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_2, &bounds3, false)); - EXPECT_LT(0, bounds3.width()); - EXPECT_LT(0, bounds3.height()); - EXPECT_LT(bounds2.x(), bounds3.x()); - EXPECT_EQ(bounds3.y(), bounds2.y()); - - // Get url Bar bounds. - gfx::Rect urlbar_bounds; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_LOCATION_BAR, &urlbar_bounds, - false)); - EXPECT_LT(0, urlbar_bounds.x()); - EXPECT_LT(0, urlbar_bounds.y()); - EXPECT_LT(0, urlbar_bounds.width()); - EXPECT_LT(0, urlbar_bounds.height()); - - /* - TEST: Move Tab_1 to the middle position of Tab_3 - ____________ ____________ ____________ - / \ / \ / \ - | Tab_1 | Tab_2 | Tab_3 | - ---- ---- ---- ---- ---- ---- ---- ---- ---- - x---- ---- ---- ---- ---- ----> + ESCAPE - ____________ - / X \ - | Tab_1 | - ---- ---- ---- - */ - - gfx::Point start(bounds1.x() + bounds1.width() / 2, - bounds1.y() + bounds1.height() / 2); - gfx::Point end(start.x() + bounds1.width() / 2 + bounds2.width() + - bounds3.width() / 2, - start.y()); - - // Simulate drag with 'true' as the last parameter. This will interrupt - // in-flight with Escape. - ASSERT_TRUE(browser->SimulateDrag(start, end, - ui::EF_LEFT_MOUSE_BUTTON, - true)); - - // Now check for expected results. - tab1 = browser->GetTab(0); - ASSERT_TRUE(tab1.get()); - GURL tab1_new_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_new_url)); - - tab2 = browser->GetTab(1); - ASSERT_TRUE(tab2.get()); - GURL tab2_new_url; - ASSERT_TRUE(tab2->GetCurrentURL(&tab2_new_url)); - - tab3 = browser->GetTab(2); - ASSERT_TRUE(tab3.get()); - GURL tab3_new_url; - ASSERT_TRUE(tab3->GetCurrentURL(&tab3_new_url)); - - // The tabs should be in their original positions. - EXPECT_EQ(tab1_new_url.spec(), tab1_url.spec()); - EXPECT_EQ(tab2_new_url.spec(), tab2_url.spec()); - EXPECT_EQ(tab3_new_url.spec(), tab3_url.spec()); -} - -// Drag Tab_2 out of the Tab strip. A new window should open with this tab. -TEST_F(TabDraggingTest, MAYBE_Tab2OutOfTabStrip) { - scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); - ASSERT_TRUE(browser.get()); - scoped_refptr<WindowProxy> window(browser->GetWindow()); - ASSERT_TRUE(window.get()); - - // Get initial tab count. - int initial_tab_count = 0; - ASSERT_TRUE(browser->GetTabCount(&initial_tab_count)); - ASSERT_TRUE(1 == initial_tab_count); - - // Get Tab_1 which comes with the browser window. - scoped_refptr<TabProxy> tab1(browser->GetTab(0)); - ASSERT_TRUE(tab1.get()); - GURL tab1_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_url)); - - // Add Tab_2. - GURL tab2_url("about:version"); - ASSERT_TRUE(browser->AppendTab(tab2_url)); - scoped_refptr<TabProxy> tab2(browser->GetTab(1)); - ASSERT_TRUE(tab2.get()); - - // Add Tab_3. - GURL tab3_url("about:plugins"); - ASSERT_TRUE(browser->AppendTab(tab3_url)); - scoped_refptr<TabProxy> tab3(browser->GetTab(2)); - ASSERT_TRUE(tab3.get()); - - // Make sure 3 tabs are opened. - ASSERT_TRUE(browser->WaitForTabCountToBecome(initial_tab_count + 2)); - - // Make sure all the tab URL specs are different. - ASSERT_TRUE(tab1_url != tab2_url); - ASSERT_TRUE(tab1_url != tab3_url); - ASSERT_TRUE(tab2_url != tab3_url); - - // Get bounds for the tabs. - gfx::Rect bounds1; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_0, &bounds1, false)); - EXPECT_LT(0, bounds1.x()); - EXPECT_LT(0, bounds1.width()); - EXPECT_LT(0, bounds1.height()); - - gfx::Rect bounds2; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_1, &bounds2, false)); - EXPECT_LT(0, bounds2.width()); - EXPECT_LT(0, bounds2.height()); - EXPECT_LT(bounds1.x(), bounds2.x()); - EXPECT_EQ(bounds2.y(), bounds1.y()); - - gfx::Rect bounds3; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_2, &bounds3, false)); - EXPECT_LT(0, bounds3.width()); - EXPECT_LT(0, bounds3.height()); - EXPECT_LT(bounds2.x(), bounds3.x()); - EXPECT_EQ(bounds3.y(), bounds2.y()); - - // Get url Bar bounds. - gfx::Rect urlbar_bounds; - ASSERT_TRUE(window->GetViewBounds(VIEW_ID_LOCATION_BAR, &urlbar_bounds, - false)); - EXPECT_LT(0, urlbar_bounds.x()); - EXPECT_LT(0, urlbar_bounds.y()); - EXPECT_LT(0, urlbar_bounds.width()); - EXPECT_LT(0, urlbar_bounds.height()); - - /* - TEST: Move Tab_2 down, out of the tab strip. - This should result in the following: - 1- Tab_3 shift left in place of Tab_2 in Window 1 - 2- Tab_1 to remain in its place - 3- Tab_2 openes in a new window - - ____________ ____________ ____________ - / \ / \ / \ - | Tab_1 | Tab_2 | Tab_3 | - ---- ---- ---- ---- ---- ---- ---- ---- ---- - x - | - | (Drag this below, out of tab strip) - V - ____________ - / X \ - | Tab_2 | (New Window) - ---- ---- ---- ---- ---- ---- ---- - */ - - gfx::Point start(bounds2.x() + bounds2.width() / 2, - bounds2.y() + bounds2.height() / 2); - gfx::Point end(start.x(), - start.y() + 3 * urlbar_bounds.height()); - - // Simulate tab drag. - ASSERT_TRUE(browser->SimulateDrag(start, end, - ui::EF_LEFT_MOUSE_BUTTON, - false)); - - // Now, first make sure that the old window has only two tabs remaining. - int new_tab_count = 0; - ASSERT_TRUE(browser->GetTabCount(&new_tab_count)); - ASSERT_EQ(2, new_tab_count); - - // Get the two tabs - they are called Tab_1 and Tab_2 in the old window. - tab1 = browser->GetTab(0); - ASSERT_TRUE(tab1.get()); - GURL tab1_new_url; - ASSERT_TRUE(tab1->GetCurrentURL(&tab1_new_url)); - - tab2 = browser->GetTab(1); - ASSERT_TRUE(tab2.get()); - GURL tab2_new_url; - ASSERT_TRUE(tab2->GetCurrentURL(&tab2_new_url)); - - // Now check for proper shifting of tabs; i.e., Tab_3 in window 1 should - // shift left to the position of Tab_2; Tab_1 should stay where it was. - EXPECT_EQ(tab1_new_url.spec(), tab1_url.spec()); - EXPECT_EQ(tab2_new_url.spec(), tab3_url.spec()); - - // Now check to make sure a new window has opened. - scoped_refptr<BrowserProxy> browser2(automation()->GetBrowserWindow(1)); - ASSERT_TRUE(browser2.get()); - scoped_refptr<WindowProxy> window2(browser2->GetWindow()); - ASSERT_TRUE(window2.get()); - - // Make sure that the new window has only one tab. - int tab_count_window_2 = 0; - ASSERT_TRUE(browser2->GetTabCount(&tab_count_window_2)); - ASSERT_EQ(1, tab_count_window_2); - - // Get Tab_1_2 which should be Tab_1 in Window 2. - scoped_refptr<TabProxy> tab1_2(browser2->GetTab(0)); - ASSERT_TRUE(tab1_2.get()); - GURL tab1_2_url; - ASSERT_TRUE(tab1_2->GetCurrentURL(&tab1_2_url)); - - // Tab_1_2 of Window 2 should essentially be Tab_2 of Window 1. - EXPECT_EQ(tab1_2_url.spec(), tab2_url.spec()); - EXPECT_NE(tab1_2_url.spec(), tab1_url.spec()); - EXPECT_NE(tab1_2_url.spec(), tab3_url.spec()); -} diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index b790eab..ebad0be 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc @@ -20,8 +20,8 @@ #include "chrome/browser/tabs/tab_strip_selection_model.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/ui/view_ids.h" +#include "chrome/browser/ui/views/tabs/default_tab_drag_controller.h" #include "chrome/browser/ui/views/tabs/tab.h" -#include "chrome/browser/ui/views/tabs/tab_drag_controller.h" #include "chrome/browser/ui/views/tabs/tab_strip_controller.h" #include "chrome/browser/ui/views/tabs/touch_tab_strip_layout.h" #include "chrome/common/chrome_switches.h" @@ -888,9 +888,10 @@ void TabStrip::MaybeStartDrag( (event.type() == ui::ET_TOUCH_PRESSED || (event.type() == ui::ET_MOUSE_PRESSED && event.flags() & ui::EF_CONTROL_DOWN)); - drag_controller_.reset(TabDragController::Create( + drag_controller_.reset(new TabDragController); + drag_controller_->Init( this, tab, tabs, gfx::Point(x, y), tab->GetMirroredXInView(event.x()), - selection_model, move_only)); + selection_model, move_only); } void TabStrip::ContinueDrag(const views::MouseEvent& event) { @@ -901,7 +902,7 @@ void TabStrip::ContinueDrag(const views::MouseEvent& event) { bool TabStrip::EndDrag(bool canceled) { if (!drag_controller_.get()) return false; - bool started_drag = drag_controller_->GetStartedDrag(); + bool started_drag = drag_controller_->started_drag(); drag_controller_->EndDrag(canceled); return started_drag; } diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h index 76e9a38..6ebe33f 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.h +++ b/chrome/browser/ui/views/tabs/tab_strip.h @@ -222,9 +222,8 @@ class TabStrip : public views::View, class RemoveTabDelegate; - friend class DefaultTabDragController; - friend class TabDragController2; - friend class TabDragController2Test; + friend class TabDragController; + friend class TabDragControllerTest; // Used during a drop session of a url. Tracks the position of the drop as // well as a window used to highlight where the drop occurs. diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 6ac2f68..ec9731e 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -3535,9 +3535,6 @@ 'browser/ui/views/tabs/tab.cc', 'browser/ui/views/tabs/tab.h', 'browser/ui/views/tabs/tab_controller.h', - 'browser/ui/views/tabs/tab_drag_controller.h', - 'browser/ui/views/tabs/tab_drag_controller2.h', - 'browser/ui/views/tabs/tab_drag_controller2.cc', 'browser/ui/views/tabs/tab_renderer_data.cc', 'browser/ui/views/tabs/tab_renderer_data.h', 'browser/ui/views/tabs/tab_strip.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 0be1ab5..e58af95 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -517,8 +517,9 @@ 'browser/ui/views/menu_item_view_test.cc', 'browser/ui/views/menu_model_adapter_test.cc', 'browser/ui/views/ssl_client_certificate_selector_browsertest.cc', - 'browser/ui/views/tabs/tab_dragging_test.cc', + 'browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h', 'browser/ui/views/tabs/tab_drag_controller2_interactive_uitest.cc', + 'browser/ui/views/tabs/tab_drag_controller_interactive_uitest_win.cc', 'browser/ui/webui/inspect_ui_browsertest.cc', 'test/base/chrome_test_launcher.cc', 'test/base/view_event_test_base.cc', @@ -551,7 +552,6 @@ 'browser/ui/views/find_bar_host_interactive_uitest.cc', 'browser/ui/views/menu_item_view_test.cc', 'browser/ui/views/menu_model_adapter_test.cc', - 'browser/ui/views/tabs/tab_dragging_test.cc', 'test/base/view_event_test_base.cc', 'test/base/view_event_test_base.h', ], @@ -570,7 +570,6 @@ 'browser/ui/views/find_bar_host_interactive_uitest.cc', 'browser/ui/views/menu_item_view_test.cc', 'browser/ui/views/menu_model_adapter_test.cc', - 'browser/ui/views/tabs/tab_dragging_test.cc', 'browser/ui/views/tabs/tab_drag_controller2_interactive_uitest.cc', 'test/base/view_event_test_base.cc', 'test/base/view_event_test_base.h', |