summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-08 19:31:25 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-08 19:31:25 +0000
commit6dba9b3f1164f24271916ab1bd3bdc1b50727744 (patch)
tree9d932c93137ea00cc2b3b0b8a76669f6fd9b2baa
parent1a5b2c24261882d1daeae97ffb3b5c9242c880d7 (diff)
downloadchromium_src-6dba9b3f1164f24271916ab1bd3bdc1b50727744.zip
chromium_src-6dba9b3f1164f24271916ab1bd3bdc1b50727744.tar.gz
chromium_src-6dba9b3f1164f24271916ab1bd3bdc1b50727744.tar.bz2
Converts dragged tab controller to only create the drag window when
detached. Otherwise the dragged tab remains in the tab strip, it's just moved around. I also made it so the tab that originated the drag can be deleted. I'm doing this for a couple of reasons: . make it easier to use dragged tab controller with side tabs. . chromeos doesn't allow detaching, and only created the window when we really need it makes for a better experience there. . no flicker! BUG=none TEST=thoroughly test tab dragging to make sure I haven't broken anything. Review URL: http://codereview.chromium.org/1998009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46791 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/views/tabs/dragged_tab_controller.cc335
-rw-r--r--chrome/browser/views/tabs/dragged_tab_controller.h68
-rw-r--r--chrome/browser/views/tabs/dragged_tab_view.cc48
-rw-r--r--chrome/browser/views/tabs/dragged_tab_view.h24
-rw-r--r--chrome/browser/views/tabs/tab.cc3
-rw-r--r--chrome/browser/views/tabs/tab.h7
-rw-r--r--chrome/browser/views/tabs/tab_dragging_test.cc5
-rw-r--r--chrome/browser/views/tabs/tab_strip.cc193
-rw-r--r--chrome/browser/views/tabs/tab_strip.h16
9 files changed, 302 insertions, 397 deletions
diff --git a/chrome/browser/views/tabs/dragged_tab_controller.cc b/chrome/browser/views/tabs/dragged_tab_controller.cc
index de11308..61b6686 100644
--- a/chrome/browser/views/tabs/dragged_tab_controller.cc
+++ b/chrome/browser/views/tabs/dragged_tab_controller.cc
@@ -17,6 +17,7 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/tabs/dragged_tab_view.h"
@@ -313,15 +314,17 @@ DraggedTabController::DraggedTabController(Tab* source_tab,
TabStrip* source_tabstrip)
: dragged_contents_(NULL),
original_delegate_(NULL),
- source_tab_(source_tab),
source_tabstrip_(source_tabstrip),
source_model_index_(source_tabstrip->GetModelIndexOfTab(source_tab)),
- attached_tabstrip_(source_tabstrip),
+ attached_tabstrip_(NULL),
+ attached_tab_(NULL),
+ offset_to_width_ratio_(0),
old_focused_view_(NULL),
in_destructor_(false),
last_move_screen_x_(0),
mini_(source_tabstrip->model()->IsMiniTab(source_model_index_)),
- pinned_(source_tabstrip->model()->IsTabPinned(source_model_index_)) {
+ pinned_(source_tabstrip->model()->IsTabPinned(source_model_index_)),
+ started_drag_(false) {
SetDraggedContents(
source_tabstrip_->model()->GetTabContentsAt(source_model_index_));
// Listen for Esc key presses.
@@ -330,7 +333,6 @@ DraggedTabController::DraggedTabController(Tab* source_tab,
DraggedTabController::~DraggedTabController() {
in_destructor_ = true;
- CleanUpSourceTab();
MessageLoopForUI::current()->RemoveObserver(this);
// Need to delete the view here manually _before_ we reset the dragged
// contents to NULL, otherwise if the view is animating to its destination
@@ -340,7 +342,12 @@ DraggedTabController::~DraggedTabController() {
SetDraggedContents(NULL); // This removes our observer.
}
-void DraggedTabController::CaptureDragInfo(const gfx::Point& mouse_offset) {
+void DraggedTabController::CaptureDragInfo(Tab* tab,
+ const gfx::Point& mouse_offset) {
+ if (tab->width() > 0) {
+ offset_to_width_ratio_ = static_cast<float>(mouse_offset.x()) /
+ static_cast<float>(tab->width());
+ }
start_screen_point_ = GetCursorScreenPoint();
mouse_offset_ = mouse_offset;
InitWindowCreatePoint();
@@ -351,28 +358,18 @@ void DraggedTabController::Drag() {
// Before we get to dragging anywhere, ensure that we consider ourselves
// attached to the source tabstrip.
- if (source_tab_->IsVisible() && CanStartDrag())
- Attach(source_tabstrip_, gfx::Point());
-
- if (!source_tab_->IsVisible()) {
+ if (!started_drag_ && CanStartDrag()) {
+ started_drag_ = true;
SaveFocus();
- ContinueDragging();
+ Attach(source_tabstrip_, gfx::Point());
}
-}
-
-bool DraggedTabController::EndDrag(bool canceled) {
- return EndDragImpl(canceled ? CANCELED : NORMAL);
-}
-Tab* DraggedTabController::GetDragSourceTabForContents(
- TabContents* contents) const {
- if (attached_tabstrip_ == source_tabstrip_)
- return contents == dragged_contents_ ? source_tab_ : NULL;
- return NULL;
+ if (started_drag_)
+ ContinueDragging();
}
-bool DraggedTabController::IsDragSourceTab(Tab* tab) const {
- return source_tab_ == tab;
+void DraggedTabController::EndDrag(bool canceled) {
+ EndDragImpl(canceled ? CANCELED : NORMAL);
}
///////////////////////////////////////////////////////////////////////////////
@@ -584,8 +581,8 @@ void DraggedTabController::SetDraggedContents(TabContents* new_contents) {
void DraggedTabController::SaveFocus() {
if (!old_focused_view_) {
- old_focused_view_ = source_tab_->GetRootView()->GetFocusedView();
- source_tab_->GetRootView()->FocusView(source_tab_);
+ old_focused_view_ = source_tabstrip_->GetRootView()->GetFocusedView();
+ source_tabstrip_->GetRootView()->FocusView(source_tabstrip_);
}
}
@@ -607,8 +604,6 @@ bool DraggedTabController::CanStartDrag() const {
}
void DraggedTabController::ContinueDragging() {
- EnsureDraggedView();
-
// 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
@@ -621,7 +616,6 @@ void DraggedTabController::ContinueDragging() {
// guaranteed to be correct regardless of monitor config.
gfx::Point screen_point = GetCursorScreenPoint();
- // TODO(sky): make this define OS_CHROMEOS when we merge views and chromeos.
#if defined(OS_CHROMEOS)
// We don't allow detaching in chrome os.
TabStrip* target_tabstrip = source_tabstrip_;
@@ -647,39 +641,59 @@ void DraggedTabController::ContinueDragging() {
UpdateDockInfo(screen_point);
- MoveTab(screen_point);
+ if (attached_tabstrip_)
+ MoveAttachedTab(screen_point);
+ else
+ MoveDetachedTab(screen_point);
}
-void DraggedTabController::MoveTab(const gfx::Point& screen_point) {
- gfx::Point dragged_view_point = GetDraggedViewPoint(screen_point);
+void DraggedTabController::MoveAttachedTab(const gfx::Point& screen_point) {
+ DCHECK(attached_tabstrip_);
+ DCHECK(!view_.get());
- if (attached_tabstrip_) {
- TabStripModel* attached_model = attached_tabstrip_->model();
- int from_index = attached_model->GetIndexOfTabContents(dragged_contents_);
-
- // 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;
- attached_tabstrip_->GetCurrentTabWidths(&unselected, &selected);
- double ratio = unselected / Tab::GetStandardSize().width();
- int threshold = static_cast<int>(ratio * kHorizontalMoveThreshold);
-
- // Update the model, moving the TabContents from one index to another. Do
- // this only if we have moved a minimum distance since the last reorder (to
- // prevent jitter).
- if (abs(screen_point.x() - last_move_screen_x_) > threshold) {
- gfx::Rect bounds = GetDraggedViewTabStripBounds(dragged_view_point);
- int to_index = GetInsertionIndexForDraggedBounds(bounds, true);
- to_index = NormalizeIndexToAttachedTabStrip(to_index);
- if (from_index != to_index) {
- last_move_screen_x_ = screen_point.x();
- attached_model->MoveTabContentsAt(from_index, to_index, true);
- }
+ gfx::Point dragged_view_point = GetAttachedTabDragPoint(screen_point);
+
+ TabStripModel* attached_model = attached_tabstrip_->model();
+ int from_index = attached_model->GetIndexOfTabContents(dragged_contents_);
+
+ // 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;
+ attached_tabstrip_->GetCurrentTabWidths(&unselected, &selected);
+ double ratio = unselected / Tab::GetStandardSize().width();
+ int threshold = static_cast<int>(ratio * kHorizontalMoveThreshold);
+
+ // Update the model, moving the TabContents from one index to another. Do this
+ // only if we have moved a minimum distance since the last reorder (to prevent
+ // jitter).
+ if (abs(screen_point.x() - last_move_screen_x_) > threshold) {
+ gfx::Point dragged_view_screen_point(dragged_view_point);
+ views::View::ConvertPointToScreen(attached_tabstrip_,
+ &dragged_view_screen_point);
+ gfx::Rect bounds = GetDraggedViewTabStripBounds(dragged_view_screen_point);
+ int to_index = GetInsertionIndexForDraggedBounds(bounds, true);
+ to_index = NormalizeIndexToAttachedTabStrip(to_index);
+ if (from_index != to_index) {
+ last_move_screen_x_ = screen_point.x();
+ attached_model->MoveTabContentsAt(from_index, to_index, true);
}
}
+ attached_tab_->SchedulePaint();
+ attached_tab_->SetX(dragged_view_point.x());
+ attached_tab_->SetY(dragged_view_point.y());
+ attached_tab_->SchedulePaint();
+}
+
+void DraggedTabController::MoveDetachedTab(const gfx::Point& screen_point) {
+ DCHECK(!attached_tabstrip_);
+ DCHECK(view_.get());
+
+ int x = screen_point.x() - mouse_offset_.x();
+ int y = screen_point.y() - mouse_offset_.y();
+
// Move the View. There are no changes to the model if we're detached.
- view_->MoveTo(dragged_view_point);
+ view_->MoveTo(gfx::Point(x, y));
}
DockInfo DraggedTabController::GetDockInfoAtPoint(
@@ -705,11 +719,15 @@ DockInfo DraggedTabController::GetDockInfoAtPoint(
TabStrip* DraggedTabController::GetTabStripForPoint(
const gfx::Point& screen_point) {
- gfx::NativeView dragged_view = view_->GetWidget()->GetNativeView();
- dock_windows_.insert(dragged_view);
+ gfx::NativeView dragged_view = NULL;
+ if (view_.get()) {
+ dragged_view = view_->GetWidget()->GetNativeView();
+ dock_windows_.insert(dragged_view);
+ }
gfx::NativeWindow local_window =
DockInfo::GetLocalProcessWindowAtPoint(screen_point, dock_windows_);
- dock_windows_.erase(dragged_view);
+ if (dragged_view)
+ dock_windows_.erase(dragged_view);
if (!local_window)
return NULL;
BrowserView* browser =
@@ -747,35 +765,19 @@ TabStrip* DraggedTabController::GetTabStripIfItContains(
void DraggedTabController::Attach(TabStrip* attached_tabstrip,
const gfx::Point& screen_point) {
+ DCHECK(!attached_tabstrip_); // We should already have detached by the time
+ // we get here.
+ DCHECK(!attached_tab_); // Similarly there should be no attached tab.
+
attached_tabstrip_ = attached_tabstrip;
- attached_tabstrip_->GenerateIdealBounds();
// We don't need the photo-booth while we're attached.
photobooth_.reset(NULL);
- Tab* tab = GetTabMatchingDraggedContents(attached_tabstrip_);
+ // And we don't need the dragged view.
+ view_.reset();
- // Update the View first, so we can ask it for its bounds and determine
- // where to insert the hidden Tab.
-
- // If this is the first time Attach is called for this drag, we're attaching
- // to the source TabStrip, and we should assume the tab count already
- // includes this Tab since we haven't been detached yet. If we don't do this,
- // the dragged representation will be a different size to others in the
- // TabStrip.
- int tab_count = attached_tabstrip_->GetTabCount();
- int mini_tab_count = attached_tabstrip_->GetMiniTabCount();
- int nano_tab_count = attached_tabstrip_->GetNanoTabCount();
- if (!tab)
- ++tab_count;
- double unselected_width, selected_width = 0;
- attached_tabstrip_->GetDesiredTabWidths(tab_count, mini_tab_count,
- nano_tab_count, &unselected_width,
- &selected_width);
- EnsureDraggedView();
- int dragged_tab_width =
- mini_ ? Tab::GetMiniWidth() : static_cast<int>(selected_width);
- view_->Attach(dragged_tab_width);
+ Tab* tab = GetTabMatchingDraggedContents(attached_tabstrip_);
if (!tab) {
// There is no Tab in |attached_tabstrip| that corresponds to the dragged
@@ -789,12 +791,6 @@ void DraggedTabController::Attach(TabStrip* attached_tabstrip,
// Return the TabContents' to normalcy.
dragged_contents_->set_capturing_contents(false);
- // We need to ask the TabStrip we're attached to to ensure that the ideal
- // bounds for all its tabs are correctly generated, because the calculation
- // in GetInsertionIndexForDraggedBounds needs them to be to figure out the
- // appropriate insertion index.
- attached_tabstrip_->GenerateIdealBounds();
-
// 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_x_ = screen_point.x();
@@ -805,13 +801,22 @@ void DraggedTabController::Attach(TabStrip* attached_tabstrip,
// changing due to animation).
gfx::Rect bounds = GetDraggedViewTabStripBounds(screen_point);
int index = GetInsertionIndexForDraggedBounds(bounds, false);
+ attached_tabstrip_->set_attaching_dragged_tab(true);
attached_tabstrip_->model()->InsertTabContentsAt(index, dragged_contents_,
true, false, pinned_);
+ attached_tabstrip_->set_attaching_dragged_tab(false);
tab = GetTabMatchingDraggedContents(attached_tabstrip_);
}
DCHECK(tab); // We should now have a tab.
- tab->SetVisible(false);
+ attached_tab_ = tab;
+ attached_tabstrip_->StartedDraggingTab(tab);
+
+ // TODO(sky): this needs to adjust based on orientation of the tab strip.
+ // The size of the dragged tab may have changed. Adjust the x offset so that
+ // ratio of mouse_offset_ to original width is maintained.
+ mouse_offset_.set_x(static_cast<int>(offset_to_width_ratio_ *
+ static_cast<int>(tab->width())));
// Move the corresponding window to the front.
attached_tabstrip_->GetWindow()->Activate();
@@ -825,13 +830,8 @@ void DraggedTabController::Detach() {
// Update the Model.
TabStripModel* attached_model = attached_tabstrip_->model();
int index = attached_model->GetIndexOfTabContents(dragged_contents_);
- if (index >= 0 && index < attached_model->count()) {
- // Sometimes, DetachTabContentsAt has consequences that result in
- // attached_tabstrip_ being set to NULL, so we need to save it first.
- TabStrip* attached_tabstrip = attached_tabstrip_;
- attached_model->DetachTabContentsAt(index);
- attached_tabstrip->SchedulePaint();
- }
+ DCHECK(index != -1);
+ attached_model->DetachTabContentsAt(index);
// If we've removed the last Tab from the TabStrip, hide the frame now.
if (!attached_model->HasNonPhantomTabs())
@@ -844,21 +844,22 @@ void DraggedTabController::Detach() {
NativeViewPhotobooth::Create(dragged_contents_->GetNativeView()));
}
- // Update the View. This NULL check is necessary apparently in some
- // conditions during automation where the view_ is destroyed inside a
- // function call preceding this point but after it is created.
- if (view_.get())
- view_->Detach(photobooth_.get());
+ // Create the dragged view.
+ EnsureDraggedView();
+ view_->Attach(attached_tab_->width());
+ view_->Detach(photobooth_.get());
// Detaching resets the delegate, but we still want to be the delegate.
dragged_contents_->set_delegate(this);
attached_tabstrip_ = NULL;
+ attached_tab_ = NULL;
}
int DraggedTabController::GetInsertionIndexForDraggedBounds(
const gfx::Rect& dragged_bounds,
bool is_tab_attached) const {
+ // TODO(sky): this needs to adjust based on orientation of the tab strip.
int right_tab_x = 0;
// If the UI layout of the tab strip is right-to-left, we need to mirror the
@@ -912,57 +913,41 @@ gfx::Rect DraggedTabController::GetDraggedViewTabStripBounds(
const gfx::Point& screen_point) {
gfx::Point client_point =
ConvertScreenPointToTabStripPoint(attached_tabstrip_, screen_point);
- gfx::Size view_size = view_->attached_tab_size();
+ if (attached_tab_) {
+ return gfx::Rect(client_point.x(), client_point.y(),
+ attached_tab_->width(), attached_tab_->height());
+ }
+ // attached_tab_ is NULL when inserting into a new tabstrip.
+ double sel_width, unselected_width;
+ attached_tabstrip_->GetCurrentTabWidths(&sel_width, &unselected_width);
+ // TODO(sky): this needs to adjust based on orientation of the tab strip.
return gfx::Rect(client_point.x(), client_point.y(),
- view_size.width(), view_size.height());
+ static_cast<int>(sel_width),
+ Tab::GetStandardSize().height());
}
-gfx::Point DraggedTabController::GetDraggedViewPoint(
+gfx::Point DraggedTabController::GetAttachedTabDragPoint(
const gfx::Point& screen_point) {
+ DCHECK(attached_tabstrip_); // The tab must be attached.
+
int x = screen_point.x() - mouse_offset_.x();
int y = screen_point.y() - mouse_offset_.y();
- // If we're not attached, we just use x and y from above.
- if (attached_tabstrip_) {
- gfx::Rect tabstrip_bounds = GetViewScreenBounds(attached_tabstrip_);
-
- // Snap the dragged Tab to the TabStrip if we are attached, detaching
- // only when the mouse position (screen_point) exceeds the screen bounds
- // of the TabStrip.
- if (x < tabstrip_bounds.x() && screen_point.x() >= tabstrip_bounds.x())
- x = tabstrip_bounds.x();
-
- gfx::Size tab_size = view_->attached_tab_size();
- int vertical_drag_magnetism = tab_size.height() * 2;
- int vertical_detach_point = tabstrip_bounds.y() - vertical_drag_magnetism;
- if (y < tabstrip_bounds.y() && screen_point.y() >= vertical_detach_point)
- y = tabstrip_bounds.y();
-
- // Make sure the Tab can't be dragged off the right side of the TabStrip
- // unless the mouse pointer passes outside the bounds of the strip by
- // clamping the position of the dragged window to the tabstrip width less
- // the width of one tab until the mouse pointer (screen_point) exceeds the
- // screen bounds of the TabStrip.
- int max_x = tabstrip_bounds.right() - tab_size.width();
- int max_y = tabstrip_bounds.bottom() - tab_size.height();
- if (x > max_x && screen_point.x() <= tabstrip_bounds.right())
- x = max_x;
- if (y > max_y && screen_point.y() <=
- (tabstrip_bounds.bottom() + vertical_drag_magnetism)) {
- y = max_y;
- }
+ gfx::Point tab_loc(x, y);
+ views::View::ConvertPointToView(NULL, attached_tabstrip_, &tab_loc);
-#if defined(OS_LINUX)
- // We currently don't allow detaching on chromeos. This restricts dragging
- // to the main window.
- x = std::min(std::max(x, tabstrip_bounds.x()), max_x);
- y = tabstrip_bounds.y();
-#endif
- }
+ x = tab_loc.x();
+ y = tab_loc.y();
+
+ const gfx::Size& tab_size = attached_tab_->bounds().size();
+
+ int max_x = attached_tabstrip_->bounds().right() - tab_size.width();
+ // TODO(sky): this needs to adjust based on orientation of the tab strip.
+ x = std::min(std::max(x, 0), max_x);
+ y = 0;
return gfx::Point(x, y);
}
-
Tab* DraggedTabController::GetTabMatchingDraggedContents(
TabStrip* tabstrip) const {
int model_index = tabstrip->model()->GetIndexOfTabContents(dragged_contents_);
@@ -970,7 +955,7 @@ Tab* DraggedTabController::GetTabMatchingDraggedContents(
NULL : tabstrip->GetTabAtModelIndex(model_index);
}
-bool DraggedTabController::EndDragImpl(EndDragType type) {
+void DraggedTabController::EndDragImpl(EndDragType type) {
// WARNING: this may be invoked multiple times. In particular, if deletion
// occurs after a delay (as it does when the tab is released in the original
// tab strip) and the navigation controller/tab contents is deleted before
@@ -989,18 +974,16 @@ bool DraggedTabController::EndDragImpl(EndDragType type) {
dock_controllers_.clear();
dock_windows_.clear();
- bool destroy_now = true;
if (type != TAB_DESTROYED) {
- // We only finish up the drag if we were actually dragging. If we never
- // constructed a view, the user just clicked and released and didn't move
- // the mouse enough to trigger a drag.
- if (view_.get()) {
+ // 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) {
+ if (type == CANCELED)
RevertDrag();
- } else {
- destroy_now = CompleteDrag();
- }
+ else
+ CompleteDrag();
}
if (dragged_contents_ && dragged_contents_->delegate() == this)
dragged_contents_->set_delegate(original_delegate_);
@@ -1019,14 +1002,12 @@ bool DraggedTabController::EndDragImpl(EndDragType type) {
DCHECK(!dragged_contents_ || dragged_contents_->delegate() != this);
original_delegate_ = NULL;
- // If we're not destroyed now, we'll be destroyed asynchronously later.
- if (destroy_now)
- source_tabstrip_->DestroyDragController();
-
- return destroy_now;
+ source_tabstrip_->DestroyDragController();
}
void DraggedTabController::RevertDrag() {
+ DCHECK(started_drag_);
+
// We save this here because code below will modify |attached_tabstrip_|.
bool restore_frame = attached_tabstrip_ != source_tabstrip_;
if (attached_tabstrip_) {
@@ -1044,6 +1025,7 @@ void DraggedTabController::RevertDrag() {
} else {
// The Tab was moved within the TabStrip where the drag was initiated.
// Move it back to the starting location.
+ source_tabstrip_->StoppedDraggingTab(attached_tab_);
source_tabstrip_->model()->MoveTabContentsAt(index, source_model_index_,
true);
}
@@ -1072,19 +1054,13 @@ void DraggedTabController::RevertDrag() {
#endif
}
}
- source_tab_->SetVisible(true);
}
-bool DraggedTabController::CompleteDrag() {
- bool destroy_immediately = true;
+void DraggedTabController::CompleteDrag() {
+ DCHECK(started_drag_);
+
if (attached_tabstrip_) {
- // We don't need to do anything other than make the Tab visible again,
- // since the dragged View is going away.
- Tab* tab = GetTabMatchingDraggedContents(attached_tabstrip_);
- view_->AnimateToBounds(
- GetViewScreenBounds(tab),
- NewCallback(this, &DraggedTabController::OnAnimateToBoundsComplete));
- destroy_immediately = false;
+ attached_tabstrip_->StoppedDraggingTab(attached_tab_);
} else {
if (dock_info_.type() != DockInfo::NONE) {
switch (dock_info_.type()) {
@@ -1156,10 +1132,9 @@ bool DraggedTabController::CompleteDrag() {
new_model->SetTabPinned(new_model->GetIndexOfTabContents(dragged_contents_),
pinned_);
new_browser->window()->Show();
- CleanUpHiddenFrame();
}
- return destroy_immediately;
+ CleanUpHiddenFrame();
}
void DraggedTabController::EnsureDraggedView() {
@@ -1230,34 +1205,6 @@ void DraggedTabController::CleanUpHiddenFrame() {
source_tabstrip_->model()->delegate()->CloseFrameAfterDragSession();
}
-void DraggedTabController::CleanUpSourceTab() {
- // If we were attached to the source TabStrip, source Tab will be in use
- // as the Tab. If we were detached or attached to another TabStrip, we can
- // safely remove this item and delete it now.
- if (attached_tabstrip_ != source_tabstrip_) {
- source_tabstrip_->DestroyDraggedSourceTab(source_tab_);
- source_tab_ = NULL;
- }
-}
-
-void DraggedTabController::OnAnimateToBoundsComplete() {
- // Sometimes, for some reason, in automation we can be called back on a
- // detach even though we aren't attached to a TabStrip. Guard against that.
- if (attached_tabstrip_) {
- Tab* tab = GetTabMatchingDraggedContents(attached_tabstrip_);
- if (tab) {
- tab->SetVisible(true);
- // Paint the tab now, otherwise there may be slight flicker between the
- // time the dragged tab window is destroyed and we paint.
- tab->PaintNow();
- }
- }
- CleanUpHiddenFrame();
-
- if (!in_destructor_)
- source_tabstrip_->DestroyDragController();
-}
-
void DraggedTabController::DockDisplayerDestroyed(
DockDisplayer* controller) {
DockWindows::iterator dock_i =
diff --git a/chrome/browser/views/tabs/dragged_tab_controller.h b/chrome/browser/views/tabs/dragged_tab_controller.h
index 758b076..4e68605 100644
--- a/chrome/browser/views/tabs/dragged_tab_controller.h
+++ b/chrome/browser/views/tabs/dragged_tab_controller.h
@@ -9,22 +9,16 @@
#include "base/timer.h"
#include "chrome/browser/dock_info.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
-#include "chrome/browser/views/tabs/tab_renderer.h"
#include "chrome/common/notification_registrar.h"
#include "gfx/rect.h"
namespace views {
-class MouseEvent;
class View;
}
-class BrowserWindow;
class DraggedTabView;
class NativeViewPhotobooth;
-class SkBitmap;
class Tab;
class TabStrip;
-class TabStripModel;
///////////////////////////////////////////////////////////////////////////////
//
@@ -47,7 +41,7 @@ class DraggedTabController : public TabContentsDelegate,
// Capture information needed to be used during a drag session for this
// controller's associated source Tab and TabStrip. |mouse_offset| is the
// distance of the mouse pointer from the Tab's origin.
- void CaptureDragInfo(const gfx::Point& mouse_offset);
+ void CaptureDragInfo(Tab* tab, const gfx::Point& mouse_offset);
// Responds to drag events subsequent to StartDrag. If the mouse moves a
// sufficient distance before the mouse is released, a drag session is
@@ -57,23 +51,20 @@ class DraggedTabController : public TabContentsDelegate,
// 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. Returns whether the tab has been destroyed.
- bool EndDrag(bool canceled);
-
- // Retrieve the source Tab if the TabContents specified matches the one being
- // dragged by this controller, or NULL if the specified TabContents is not
- // the same as the one being dragged.
- Tab* GetDragSourceTabForContents(TabContents* contents) const;
-
- // Returns true if the specified Tab matches the Tab being dragged.
- bool IsDragSourceTab(Tab* tab) const;
+ // begun.
+ void EndDrag(bool canceled);
TabContents* dragged_contents() { return dragged_contents_; }
+ // Returns true if a drag started.
+ bool started_drag() const { return started_drag_; }
+
private:
class DockDisplayer;
friend class DockDisplayer;
+ typedef std::set<gfx::NativeView> DockWindows;
+
// Enumeration of the ways a drag session can end.
enum EndDragType {
// Drag session exited normally: the user released the mouse.
@@ -155,8 +146,11 @@ class DraggedTabController : public TabContentsDelegate,
// potentially updating the source and other TabStrips.
void ContinueDragging();
- // Handles moving the Tab within a TabStrip as well as updating the View.
- void MoveTab(const gfx::Point& screen_point);
+ // Handles dragging a tab while the tab is attached.
+ void MoveAttachedTab(const gfx::Point& screen_point);
+
+ // Handles dragging while the tab is detached.
+ void MoveDetachedTab(const gfx::Point& screen_point);
// Returns the compatible TabStrip that is under the specified point (screen
// coordinates), or NULL if there is none.
@@ -188,22 +182,21 @@ class DraggedTabController : public TabContentsDelegate,
// Get the position of the dragged tab view relative to the attached tab
// strip.
- gfx::Point GetDraggedViewPoint(const gfx::Point& screen_point);
+ gfx::Point GetAttachedTabDragPoint(const gfx::Point& screen_point);
// Finds the Tab within the specified TabStrip that corresponds to the
// dragged TabContents.
Tab* GetTabMatchingDraggedContents(TabStrip* tabstrip) const;
- // Does the work for EndDrag. Returns whether the tab has been destroyed.
- bool EndDragImpl(EndDragType how_end);
+ // 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);
- // If the drag was aborted for some reason, this function is called to un-do
- // the changes made during the drag operation.
+ // Reverts a cancelled drag operation.
void RevertDrag();
- // Finishes the drag operation. Returns true if the drag controller should
- // be destroyed immediately, false otherwise.
- bool CompleteDrag();
+ // Finishes a succesful drag operation.
+ void CompleteDrag();
// Create the DraggedTabView, if it does not yet exist.
void EnsureDraggedView();
@@ -225,13 +218,6 @@ class DraggedTabController : public TabContentsDelegate,
// Closes a hidden frame at the end of a drag session.
void CleanUpHiddenFrame();
- // Cleans up a source tab that is no longer used.
- void CleanUpSourceTab();
-
- // Completes the drag session after the view has animated to its final
- // position.
- void OnAnimateToBoundsComplete();
-
void DockDisplayerDestroyed(DockDisplayer* controller);
void BringWindowUnderMouseToFront();
@@ -247,9 +233,6 @@ class DraggedTabController : public TabContentsDelegate,
// certain delegate notifications back to it if we can't handle them locally.
TabContentsDelegate* original_delegate_;
- // The Tab that initiated the drag session.
- Tab* source_tab_;
-
// The TabStrip |source_tab_| originated from.
TabStrip* source_tabstrip_;
@@ -261,6 +244,9 @@ class DraggedTabController : public TabContentsDelegate,
// dragged Tab is detached.
TabStrip* attached_tabstrip_;
+ // If attached this is the tab we're dragging.
+ Tab* attached_tab_;
+
// The visual representation of the dragged Tab.
scoped_ptr<DraggedTabView> view_;
@@ -279,6 +265,9 @@ class DraggedTabController : public TabContentsDelegate,
// detached window is created at the right location.
gfx::Point mouse_offset_;
+ // Ratio of the x-coordinate of the mouse offset to the width of the tab.
+ float offset_to_width_ratio_;
+
// A hint to use when positioning new windows created by detaching Tabs. This
// is the distance of the mouse from the top left of the dragged tab as if it
// were the distance of the mouse from the top left of the first tab in the
@@ -309,8 +298,8 @@ class DraggedTabController : public TabContentsDelegate,
DockInfo dock_info_;
- typedef std::set<gfx::NativeView> DockWindows;
DockWindows dock_windows_;
+
std::vector<DockDisplayer*> dock_controllers_;
// Is the tab mini?
@@ -324,6 +313,9 @@ class DraggedTabController : public TabContentsDelegate,
// brought to front.
base::OneShotTimer<DraggedTabController> bring_to_front_timer_;
+ // Did the mouse move enough that we started a drag?
+ bool started_drag_;
+
DISALLOW_COPY_AND_ASSIGN(DraggedTabController);
};
diff --git a/chrome/browser/views/tabs/dragged_tab_view.cc b/chrome/browser/views/tabs/dragged_tab_view.cc
index b2da323..aab8a0f 100644
--- a/chrome/browser/views/tabs/dragged_tab_view.cc
+++ b/chrome/browser/views/tabs/dragged_tab_view.cc
@@ -20,7 +20,6 @@ static const int kOpaqueAlpha = 255;
static const int kDragFrameBorderSize = 2;
static const int kTwiceDragFrameBorderSize = 2 * kDragFrameBorderSize;
static const float kScalingFactor = 0.5;
-static const int kAnimateToBoundsDurationMs = 150;
static const SkColor kDraggedTabBorderColor = SkColorSetRGB(103, 129, 162);
////////////////////////////////////////////////////////////////////////////////
@@ -36,8 +35,7 @@ DraggedTabView::DraggedTabView(views::View* renderer,
mouse_tab_offset_(mouse_tab_offset),
attached_tab_size_(min_size),
photobooth_(NULL),
- contents_size_(contents_size),
- close_animation_(this) {
+ contents_size_(contents_size) {
set_parent_owned(false);
#if defined(OS_WIN)
@@ -65,8 +63,6 @@ DraggedTabView::DraggedTabView(views::View* renderer,
}
DraggedTabView::~DraggedTabView() {
- if (close_animation_.is_animating())
- close_animation_.Stop();
GetParent()->RemoveChildView(this);
container_->CloseNow();
}
@@ -138,48 +134,6 @@ void DraggedTabView::Update() {
#endif
}
-void DraggedTabView::AnimateToBounds(const gfx::Rect& bounds,
- Callback0::Type* callback) {
- animation_callback_.reset(callback);
-
- gfx::Rect initial_bounds;
- GetWidget()->GetBounds(&initial_bounds, true);
- animation_start_bounds_ = initial_bounds;
- animation_end_bounds_ = bounds;
-
- close_animation_.SetSlideDuration(kAnimateToBoundsDurationMs);
- close_animation_.SetTweenType(Tween::EASE_OUT);
- if (!close_animation_.IsShowing()) {
- close_animation_.Reset();
- close_animation_.Show();
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// DraggedTabView, AnimationDelegate implementation:
-
-void DraggedTabView::AnimationProgressed(const Animation* animation) {
- int delta_x = (animation_end_bounds_.x() - animation_start_bounds_.x());
- int x = animation_start_bounds_.x() +
- static_cast<int>(delta_x * animation->GetCurrentValue());
- int y = animation_end_bounds_.y();
-#if defined(OS_WIN)
- container_->SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
-#else
- gfx::Rect bounds;
- container_->GetBounds(&bounds, true);
- container_->SetBounds(gfx::Rect(x, y, bounds.width(), bounds.height()));
-#endif
-}
-
-void DraggedTabView::AnimationEnded(const Animation* animation) {
- animation_callback_->Run();
-}
-
-void DraggedTabView::AnimationCanceled(const Animation* animation) {
- AnimationEnded(animation);
-}
-
///////////////////////////////////////////////////////////////////////////////
// DraggedTabView, views::View overrides:
diff --git a/chrome/browser/views/tabs/dragged_tab_view.h b/chrome/browser/views/tabs/dragged_tab_view.h
index 02279d5..cda1daa 100644
--- a/chrome/browser/views/tabs/dragged_tab_view.h
+++ b/chrome/browser/views/tabs/dragged_tab_view.h
@@ -5,8 +5,6 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_DRAGGED_TAB_VIEW_H_
#define CHROME_BROWSER_VIEWS_TABS_DRAGGED_TAB_VIEW_H_
-#include "app/slide_animation.h"
-#include "base/callback.h"
#include "build/build_config.h"
#include "gfx/point.h"
#include "gfx/size.h"
@@ -26,8 +24,7 @@ class NativeViewPhotobooth;
class Tab;
class TabRenderer;
-class DraggedTabView : public views::View,
- public AnimationDelegate {
+class DraggedTabView : public views::View {
public:
// Creates a new DraggedTabView using |renderer| as the View. DraggedTabView
// takes ownership of |renderer|.
@@ -58,20 +55,11 @@ class DraggedTabView : public views::View,
// Notifies the DraggedTabView that it should update itself.
void Update();
- // Animates the DraggedTabView to the specified bounds, then calls back to
- // |callback|.
- void AnimateToBounds(const gfx::Rect& bounds, Callback0::Type* callback);
-
// Returns the size of the DraggedTabView. Used when attaching to a TabStrip
// to determine where to place the Tab in the attached TabStrip.
const gfx::Size& attached_tab_size() const { return attached_tab_size_; }
private:
- // Overridden from AnimationDelegate:
- virtual void AnimationProgressed(const Animation* animation);
- virtual void AnimationEnded(const Animation* animation);
- virtual void AnimationCanceled(const Animation* animation);
-
// Overridden from views::View:
virtual void Paint(gfx::Canvas* canvas);
virtual void Layout();
@@ -126,16 +114,6 @@ class DraggedTabView : public views::View,
// Size of the TabContents being dragged.
gfx::Size contents_size_;
- // The animation used to slide the attached view to its final location.
- SlideAnimation close_animation_;
-
- // A callback notified when the animation is complete.
- scoped_ptr<Callback0::Type> animation_callback_;
-
- // The start and end bounds of the animation sequence.
- gfx::Rect animation_start_bounds_;
- gfx::Rect animation_end_bounds_;
-
DISALLOW_COPY_AND_ASSIGN(DraggedTabView);
};
diff --git a/chrome/browser/views/tabs/tab.cc b/chrome/browser/views/tabs/tab.cc
index 4f3989c..03487a9 100644
--- a/chrome/browser/views/tabs/tab.cc
+++ b/chrome/browser/views/tabs/tab.cc
@@ -107,7 +107,8 @@ class Tab::TabContextMenuContents : public menus::SimpleMenuModel::Delegate {
Tab::Tab(TabDelegate* delegate)
: TabRenderer(),
delegate_(delegate),
- closing_(false) {
+ closing_(false),
+ dragging_(false) {
close_button()->SetTooltipText(l10n_util::GetString(IDS_TOOLTIP_CLOSE_TAB));
close_button()->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE));
close_button()->SetAnimationDuration(0);
diff --git a/chrome/browser/views/tabs/tab.h b/chrome/browser/views/tabs/tab.h
index 2276239..af7eb20 100644
--- a/chrome/browser/views/tabs/tab.h
+++ b/chrome/browser/views/tabs/tab.h
@@ -90,6 +90,10 @@ class Tab : public TabRenderer,
void set_closing(bool closing) { closing_ = closing; }
bool closing() const { return closing_; }
+ // See description above field.
+ void set_dragging(bool dragging) { dragging_ = dragging; }
+ bool dragging() const { return dragging_; }
+
// TabRenderer overrides:
virtual bool IsSelected() const;
@@ -125,6 +129,9 @@ class Tab : public TabRenderer,
// True if the tab is being animated closed.
bool closing_;
+ // True if the tab is being dragged.
+ bool dragging_;
+
// If non-null it means we're showing a menu for the tab.
class TabContextMenuContents;
scoped_ptr<TabContextMenuContents> context_menu_contents_;
diff --git a/chrome/browser/views/tabs/tab_dragging_test.cc b/chrome/browser/views/tabs/tab_dragging_test.cc
index aff4f16..4a57a53 100644
--- a/chrome/browser/views/tabs/tab_dragging_test.cc
+++ b/chrome/browser/views/tabs/tab_dragging_test.cc
@@ -19,7 +19,8 @@
#include "views/event.h"
#if defined(OS_CHROMEOS)
-// Disabled, see http://crbug.com/40043.
+// This test doesn't make sense on chromeos as chromeos doesn't allow dragging
+// tabs out.
#define MAYBE_Tab2OutOfTabStrip DISABLED_Tab2OutOfTabStrip
#else
#define MAYBE_Tab2OutOfTabStrip Tab2OutOfTabStrip
@@ -270,7 +271,7 @@ TEST_F(TabDraggingTest, MAYBE_Tab1Tab3Escape) {
ASSERT_TRUE(tab1->GetCurrentURL(&tab1_url));
// Add Tab_2.
- GURL tab2_url("about:");
+ GURL tab2_url("about:blank");
ASSERT_TRUE(browser->AppendTab(tab2_url));
scoped_refptr<TabProxy> tab2(browser->GetTab(1));
ASSERT_TRUE(tab2.get());
diff --git a/chrome/browser/views/tabs/tab_strip.cc b/chrome/browser/views/tabs/tab_strip.cc
index c58f15a..f88aaa4 100644
--- a/chrome/browser/views/tabs/tab_strip.cc
+++ b/chrome/browser/views/tabs/tab_strip.cc
@@ -36,6 +36,7 @@
#include "views/controls/image_view.h"
#include "views/painter.h"
#include "views/widget/default_theme_provider.h"
+#include "views/widget/root_view.h"
#include "views/window/non_client_view.h"
#include "views/window/window.h"
@@ -116,6 +117,28 @@ class NewTabAlphaDelegate
DISALLOW_COPY_AND_ASSIGN(NewTabAlphaDelegate);
};
+// Animation delegate used when a dragged tab is released. When done sets the
+// dragging state to false.
+class ResetDraggingStateDelegate
+ : public views::BoundsAnimator::OwnedAnimationDelegate {
+ public:
+ explicit ResetDraggingStateDelegate(Tab* tab) : tab_(tab) {
+ }
+
+ virtual void AnimationEnded(const Animation* animation) {
+ tab_->set_dragging(false);
+ }
+
+ virtual void AnimationCanceled(const Animation* animation) {
+ tab_->set_dragging(false);
+ }
+
+ private:
+ Tab* tab_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResetDraggingStateDelegate);
+};
+
///////////////////////////////////////////////////////////////////////////////
// NewTabButton
//
@@ -256,7 +279,8 @@ TabStrip::TabStrip(TabStripModel* model)
ALLOW_THIS_IN_INITIALIZER_LIST(bounds_animator_(this)),
animation_type_(ANIMATION_DEFAULT),
new_tab_button_enabled_(true),
- cancelling_animation_(false) {
+ cancelling_animation_(false),
+ attaching_dragged_tab_(false) {
Init();
}
@@ -289,28 +313,6 @@ void TabStrip::DestroyDragController() {
drag_controller_.reset(NULL);
}
-void TabStrip::DestroyDraggedSourceTab(Tab* tab) {
- // We could be running an animation that references this Tab.
- StopAnimating(true);
-
- // Make sure we leave the tab_data_ vector in a consistent state, otherwise
- // we'll be pointing to tabs that have been deleted and removed from the
- // child view list.
- int tab_data_index = TabDataIndexOfTab(tab);
- if (tab_data_index != -1) {
- if (!model_->closing_all())
- NOTREACHED() << "Leaving in an inconsistent state!";
- tab_data_.erase(tab_data_.begin() + tab_data_index);
- }
-
- delete tab;
-
- // Force a layout here, because if we've just quickly drag detached a Tab,
- // the stopping of the active animation above may have left the TabStrip in a
- // bad (visual) state.
- Layout();
-}
-
gfx::Rect TabStrip::GetIdealBounds(int tab_data_index) {
DCHECK_GE(tab_data_index, 0);
DCHECK_LT(tab_data_index, GetTabCount());
@@ -459,13 +461,17 @@ void TabStrip::PaintChildren(gfx::Canvas* canvas) {
Tab* selected_tab = NULL;
+ Tab* dragging_tab = NULL;
+
for (int i = tab_count - 1; i >= 0; --i) {
Tab* tab = GetTabAtTabDataIndex(i);
// We must ask the _Tab's_ model, not ourselves, because in some situations
// the model will be different to this object, e.g. when a Tab is being
// removed after its TabContents has been destroyed.
if (!tab->phantom()) {
- if (!tab->IsSelected()) {
+ if (tab->dragging()) {
+ dragging_tab = tab;
+ } else if (!tab->IsSelected()) {
if (tab->render_unselected() && model_->count() > 1) {
// See comment above kNetTabAnimationSelectedOffset as to why we do
// this.
@@ -511,6 +517,10 @@ void TabStrip::PaintChildren(gfx::Canvas* canvas) {
animation_type_ != ANIMATION_NEW_TAB_3) {
newtab_button_->ProcessPaint(canvas);
}
+
+ // And the dragged tab.
+ if (dragging_tab)
+ dragging_tab->ProcessPaint(canvas);
}
// Overridden to support automation. See automation_proxy_uitest.cc.
@@ -656,6 +666,16 @@ void TabStrip::ViewHierarchyChanged(bool is_add,
InitTabStripButtons();
}
+bool TabStrip::OnMouseDragged(const views::MouseEvent& event) {
+ if (drag_controller_.get())
+ drag_controller_->Drag();
+ return true;
+}
+
+void TabStrip::OnMouseReleased(const views::MouseEvent& event,
+ bool canceled) {
+ EndDrag(canceled);
+}
///////////////////////////////////////////////////////////////////////////////
// TabStrip, TabStripModelObserver implementation:
@@ -671,69 +691,23 @@ void TabStrip::TabInsertedAt(TabContents* contents,
contents->render_view_host()->UpdateBrowserWindowId(
contents->controller().window_id().id());
- bool contains_tab = false;
- Tab* tab = NULL;
- // First see if this Tab is one that was dragged out of this TabStrip and is
- // now being dragged back in. In this case, the DraggedTabController actually
- // has the Tab already constructed and we can just insert it into our list
- // again.
- if (IsDragSessionActive()) {
- tab = drag_controller_->GetDragSourceTabForContents(contents);
- if (tab) {
- // If the Tab was detached, it would have been animated closed but not
- // removed, so we need to reset this property.
- tab->set_closing(false);
- tab->ValidateLoadingAnimation(TabRenderer::ANIMATION_NONE);
- tab->SetVisible(true);
- }
-
- // See if we're already in the list. We don't want to add ourselves twice.
- int tab_data_index = TabDataIndexOfTab(tab);
+ Tab* tab = CreateTab();
- if (tab_data_index != -1) {
- contains_tab = true;
-
- // Make sure we stop animating the view. This is necessary otherwise when
- // the animation is done it'll try to remove the tab.
- bounds_animator_.StopAnimatingView(tab);
-
- // We have the tab, but it might not be at the right index. Reset the data
- // to ensure it's at the right index.
- TabData tab_data = tab_data_[tab_data_index];
- DCHECK(tab_data.tab == tab);
- tab_data_.erase(tab_data_.begin() + tab_data_index);
- tab_data_.insert(
- tab_data_.begin() + ModelIndexToTabDataIndex(model_index),
- tab_data);
- }
- }
-
- // Otherwise we need to make a new Tab.
- if (!tab)
- tab = CreateTab();
-
- // Only insert if we're not already in the list.
- if (!contains_tab) {
- TabData d = { tab, gfx::Rect() };
- tab_data_.insert(tab_data_.begin() +
- ModelIndexToTabDataIndex(model_index), d);
- tab->UpdateData(contents, model_->IsPhantomTab(model_index), false);
- }
+ TabData d = { tab, gfx::Rect() };
+ tab_data_.insert(tab_data_.begin() +
+ ModelIndexToTabDataIndex(model_index), d);
+ tab->UpdateData(contents, model_->IsPhantomTab(model_index), false);
tab->set_mini(model_->IsMiniTab(model_index));
tab->set_app(model_->IsAppTab(model_index));
tab->SetBlocked(model_->IsTabBlocked(model_index));
+ tab->SetAnimationContainer(animation_container_.get());
- // We only add the tab to the child list if it's not already - an invisible
- // tab maintained by the DraggedTabController will already be parented.
- if (!tab->GetParent()) {
- AddChildView(tab);
- tab->SetAnimationContainer(animation_container_.get());
- }
+ AddChildView(tab);
// Don't animate the first tab, it looks weird, and don't animate anything
// if the containing window isn't visible yet.
if (GetTabCount() > 1 && GetWindow() && GetWindow()->IsVisible()) {
- if (!IsDragSessionActive() &&
+ if (!IsDragSessionActive() && !attaching_dragged_tab_ &&
ShouldStartIntertTabAnimationAtEnd(model_index, foreground)) {
StartInsertTabAnimationAtEnd();
} else {
@@ -943,19 +917,30 @@ void TabStrip::MaybeStartDrag(Tab* tab, const views::MouseEvent& event) {
return;
}
drag_controller_.reset(new DraggedTabController(tab, this));
- drag_controller_->CaptureDragInfo(event.location());
+ drag_controller_->CaptureDragInfo(tab, event.location());
}
void TabStrip::ContinueDrag(const views::MouseEvent& event) {
// We can get called even if |MaybeStartDrag| wasn't called in the event of
// a TabStrip animation when the mouse button is down. In this case we should
// _not_ continue the drag because it can lead to weird bugs.
- if (drag_controller_.get())
+ if (drag_controller_.get()) {
+ bool started_drag = drag_controller_->started_drag();
drag_controller_->Drag();
+ if (drag_controller_->started_drag() && !started_drag) {
+ // The drag just started. Redirect mouse events to us to that the tab that
+ // originated the drag can be safely deleted.
+ GetRootView()->SetMouseHandler(this);
+ }
+ }
}
bool TabStrip::EndDrag(bool canceled) {
- return drag_controller_.get() ? drag_controller_->EndDrag(canceled) : false;
+ if (!drag_controller_.get())
+ return false;
+ bool started_drag = drag_controller_->started_drag();
+ drag_controller_->EndDrag(canceled);
+ return started_drag;
}
bool TabStrip::HasAvailableDragActions() const {
@@ -1537,7 +1522,7 @@ void TabStrip::NewTabAnimation2Done() {
void TabStrip::AnimateToIdealBounds() {
for (size_t i = 0; i < tab_data_.size(); ++i) {
- if (!tab_data_[i].tab->closing()) {
+ if (!tab_data_[i].tab->closing() && !tab_data_[i].tab->dragging()) {
bounds_animator_.AnimateViewTo(tab_data_[i].tab,
tab_data_[i].ideal_bounds);
}
@@ -1743,13 +1728,7 @@ void TabStrip::RemoveTab(Tab* tab) {
// Remove the Tab from the TabStrip's list...
tab_data_.erase(tab_data_.begin() + tab_data_index);
- // If the TabContents being detached was removed as a result of a drag
- // gesture from its corresponding Tab, we don't want to remove the Tab from
- // the child list, because if we do so it'll stop receiving events and the
- // drag will stall. So we only remove if a drag isn't active, or the Tab
- // was for some other TabContents.
- if (!IsDragSessionActive() || !drag_controller_->IsDragSourceTab(tab))
- delete tab;
+ delete tab;
}
void TabStrip::HandleGlobalMouseMoveEvent() {
@@ -1809,3 +1788,39 @@ int TabStrip::TabDataIndexOfTab(Tab* tab) const {
}
return -1;
}
+
+void TabStrip::StartedDraggingTab(Tab* tab) {
+ tab->set_dragging(true);
+
+ // Stop any animations on the tab.
+ bounds_animator_.StopAnimatingView(tab);
+
+ // Move the tab to its ideal bounds.
+ GenerateIdealBounds();
+ int tab_data_index = TabDataIndexOfTab(tab);
+ DCHECK(tab_data_index != -1);
+ tab->SetBounds(tab_data_[tab_data_index].ideal_bounds);
+ SchedulePaint();
+}
+
+void TabStrip::StoppedDraggingTab(Tab* tab) {
+ int tab_data_index = TabDataIndexOfTab(tab);
+ if (tab_data_index == -1) {
+ // The tab was removed before the drag completed. Don't do anything.
+ return;
+ }
+
+ // Animate the view back to its correct position.
+ ResetAnimationState(true);
+ GenerateIdealBounds();
+ AnimateToIdealBounds();
+ bounds_animator_.AnimateViewTo(
+ tab,
+ tab_data_[TabDataIndexOfTab(tab)].ideal_bounds);
+
+ // Install a delegate to reset the dragging state when done. We have to leave
+ // dragging true for the tab otherwise it'll draw beneath the new tab button.
+ bounds_animator_.SetAnimationDelegate(tab,
+ new ResetDraggingStateDelegate(tab),
+ true);
+}
diff --git a/chrome/browser/views/tabs/tab_strip.h b/chrome/browser/views/tabs/tab_strip.h
index 8752bf1..5279dd0 100644
--- a/chrome/browser/views/tabs/tab_strip.h
+++ b/chrome/browser/views/tabs/tab_strip.h
@@ -76,9 +76,6 @@ class TabStrip : public BaseTabStrip,
// Destroys the active drag controller.
void DestroyDragController();
- // Removes the drag source Tab from this TabStrip, and deletes it.
- void DestroyDraggedSourceTab(Tab* tab);
-
// Retrieves the ideal bounds for the Tab at the specified index.
gfx::Rect GetIdealBounds(int tab_data_index);
@@ -137,6 +134,9 @@ class TabStrip : public BaseTabStrip,
virtual void ViewHierarchyChanged(bool is_add,
views::View* parent,
views::View* child);
+ virtual bool OnMouseDragged(const views::MouseEvent& event);
+ virtual void OnMouseReleased(const views::MouseEvent& event,
+ bool canceled);
// TabStripModelObserver implementation:
virtual void TabInsertedAt(TabContents* contents,
@@ -419,6 +419,13 @@ class TabStrip : public BaseTabStrip,
// -1 if the tab isn't in |tab_data_|.
int TabDataIndexOfTab(Tab* tab) const;
+ // See description above field for details.
+ void set_attaching_dragged_tab(bool value) { attaching_dragged_tab_ = value; }
+
+ // Used by DraggedTabController when the user starts or stops dragging a tab.
+ void StartedDraggingTab(Tab* tab);
+ void StoppedDraggingTab(Tab* tab);
+
// -- Member Variables ------------------------------------------------------
// Our model.
@@ -491,6 +498,9 @@ class TabStrip : public BaseTabStrip,
// If true, we're cancelling the animation.
bool cancelling_animation_;
+ // Used by DraggedTabController when inserting a tab into our model.
+ bool attaching_dragged_tab_;
+
DISALLOW_COPY_AND_ASSIGN(TabStrip);
};