Index: chrome/browser/ui/cocoa/browser_window_controller.mm |
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm |
index f883a94e96d67cb53228d9d6c6bf5ba20cb9a1f3..9c51c27db2d40648db9db94ed8653ecbaa2823e1 100644 |
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm |
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm |
@@ -1283,57 +1283,70 @@ enum { |
// placed into this one. The implementation will call |-removePlaceholder| since |
// the drag is now complete. This also calls |-layoutTabs| internally so |
// clients do not need to call it again. |
-- (void)moveTabView:(NSView*)view |
- fromController:(TabWindowController*)dragController { |
+- (void)moveTabViews:(NSArray*)views |
+ fromController:(TabWindowController*)dragController { |
if (dragController) { |
- // Moving between windows. Figure out the WebContents to drop into our tab |
- // model from the source window's model. |
+ // Moving between windows. |
+ NSView* activeTabView = [dragController activeTabView]; |
BrowserWindowController* dragBWC = |
base::mac::ObjCCastStrict<BrowserWindowController>(dragController); |
- int index = [dragBWC->tabStripController_ modelIndexForTabView:view]; |
- WebContents* contents = |
- dragBWC->browser_->tab_strip_model()->GetWebContentsAt(index); |
- // The tab contents may have gone away if given a window.close() while it |
- // is being dragged. If so, bail, we've got nothing to drop. |
- if (!contents) |
- return; |
- // Convert |view|'s frame (which starts in the source tab strip's coordinate |
- // system) to the coordinate system of the destination tab strip. This needs |
- // to be done before being detached so the window transforms can be |
- // performed. |
- NSRect destinationFrame = [view frame]; |
- NSPoint tabOrigin = destinationFrame.origin; |
- tabOrigin = [[dragController tabStripView] convertPoint:tabOrigin |
- toView:nil]; |
- tabOrigin = [[view window] convertBaseToScreen:tabOrigin]; |
- tabOrigin = [[self window] convertScreenToBase:tabOrigin]; |
- tabOrigin = [[self tabStripView] convertPoint:tabOrigin fromView:nil]; |
- destinationFrame.origin = tabOrigin; |
- |
- // Before the tab is detached from its originating tab strip, store the |
- // pinned state so that it can be maintained between the windows. |
- bool isPinned = dragBWC->browser_->tab_strip_model()->IsTabPinned(index); |
- |
- // Now that we have enough information about the tab, we can remove it from |
- // the dragging window. We need to do this *before* we add it to the new |
- // window as this will remove the WebContents' delegate. |
- [dragController detachTabView:view]; |
- |
- // Deposit it into our model at the appropriate location (it already knows |
- // where it should go from tracking the drag). Doing this sets the tab's |
- // delegate to be the Browser. |
- [tabStripController_ dropWebContents:contents |
- withFrame:destinationFrame |
- asPinnedTab:isPinned]; |
+ // We will drop the tabs starting at indexOfPlaceholder, and increment from |
+ // there. We remove the placehoder before dropping the tabs, so that the |
+ // new tab animation's destination frame is correct. |
+ int tabIndex = [tabStripController_ indexOfPlaceholder]; |
+ [self removePlaceholder]; |
+ |
+ for (NSView* view in views) { |
+ // Figure out the WebContents to drop into our tab model from the source |
+ // window's model. |
+ int index = [dragBWC->tabStripController_ modelIndexForTabView:view]; |
+ WebContents* contents = |
+ dragBWC->browser_->tab_strip_model()->GetWebContentsAt(index); |
+ // The tab contents may have gone away if given a window.close() while it |
+ // is being dragged. If so, bail, we've got nothing to drop. |
+ if (!contents) |
+ continue; |
+ |
+ // Convert |view|'s frame (which starts in the source tab strip's |
+ // coordinate system) to the coordinate system of the destination tab |
+ // strip. This needs to be done before being detached so the window |
+ // transforms can be performed. |
+ NSRect destinationFrame = [view frame]; |
+ NSPoint tabOrigin = destinationFrame.origin; |
+ tabOrigin = [[dragController tabStripView] convertPoint:tabOrigin |
+ toView:nil]; |
+ tabOrigin = [[dragController window] convertBaseToScreen:tabOrigin]; |
+ tabOrigin = [[self window] convertScreenToBase:tabOrigin]; |
+ tabOrigin = [[self tabStripView] convertPoint:tabOrigin fromView:nil]; |
+ destinationFrame.origin = tabOrigin; |
+ |
+ // Before the tab is detached from its originating tab strip, store the |
+ // pinned state so that it can be maintained between the windows. |
+ bool isPinned = dragBWC->browser_->tab_strip_model()->IsTabPinned(index); |
+ |
+ // Now that we have enough information about the tab, we can remove it |
+ // from the dragging window. We need to do this *before* we add it to the |
+ // new window as this will remove the WebContents' delegate. |
+ [dragController detachTabView:view]; |
+ |
+ // Deposit it into our model at the appropriate location (it already knows |
+ // where it should go from tracking the drag). Doing this sets the tab's |
+ // delegate to be the Browser. |
+ [tabStripController_ dropWebContents:contents |
+ atIndex:tabIndex++ |
+ withFrame:destinationFrame |
+ asPinnedTab:isPinned |
+ activate:view == activeTabView]; |
+ } |
} else { |
// Moving within a window. |
- int index = [tabStripController_ modelIndexForTabView:view]; |
- [tabStripController_ moveTabFromIndex:index]; |
+ for (NSView* view in views) { |
+ int index = [tabStripController_ modelIndexForTabView:view]; |
+ [tabStripController_ moveTabFromIndex:index]; |
+ } |
+ [self removePlaceholder]; |
} |
- |
- // Remove the placeholder since the drag is now complete. |
- [self removePlaceholder]; |
} |
// Tells the tab strip to forget about this tab in preparation for it being |
@@ -1343,6 +1356,10 @@ enum { |
browser_->tab_strip_model()->DetachWebContentsAt(index); |
} |
+- (NSArray*)tabViews { |
+ return [tabStripController_ tabViews]; |
+} |
+ |
- (NSView*)activeTabView { |
return [tabStripController_ activeTabView]; |
} |
@@ -1364,52 +1381,50 @@ enum { |
[tabStripController_ layoutTabs]; |
} |
-- (TabWindowController*)detachTabToNewWindow:(TabView*)tabView { |
+- (TabWindowController*)detachTabsToNewWindow:(NSArray*)tabViews |
+ draggedTab:(NSView*)draggedTab { |
+ DCHECK_GT([tabViews count], 0U); |
+ |
// Disable screen updates so that this appears as a single visual change. |
gfx::ScopedNSDisableScreenUpdates disabler; |
- // Fetch the tab contents for the tab being dragged. |
- int index = [tabStripController_ modelIndexForTabView:tabView]; |
- WebContents* contents = browser_->tab_strip_model()->GetWebContentsAt(index); |
- |
// Set the window size. Need to do this before we detach the tab so it's |
// still in the window. We have to flip the coordinates as that's what |
// is expected by the Browser code. |
- NSWindow* sourceWindow = [tabView window]; |
+ NSWindow* sourceWindow = [draggedTab window]; |
NSRect windowRect = [sourceWindow frame]; |
NSScreen* screen = [sourceWindow screen]; |
windowRect.origin.y = NSHeight([screen frame]) - NSMaxY(windowRect); |
gfx::Rect browserRect(windowRect.origin.x, windowRect.origin.y, |
NSWidth(windowRect), NSHeight(windowRect)); |
- NSRect sourceTabRect = [tabView frame]; |
- NSView* tabStrip = [self tabStripView]; |
- |
- // Pushes tabView's frame back inside the tabstrip. |
- NSSize tabOverflow = |
- [self overflowFrom:[tabStrip convertRect:sourceTabRect toView:nil] |
- to:[tabStrip frame]]; |
- NSRect tabRect = NSOffsetRect(sourceTabRect, |
- -tabOverflow.width, -tabOverflow.height); |
- |
- // Before detaching the tab, store the pinned state. |
- bool isPinned = browser_->tab_strip_model()->IsTabPinned(index); |
+ std::vector<TabStripModelDelegate::NewStripContents> contentses; |
+ TabStripModel* model = browser_->tab_strip_model(); |
+ |
+ for (TabView* tabView in tabViews) { |
+ // Fetch the tab contents for the tab being dragged. |
+ int index = [tabStripController_ modelIndexForTabView:tabView]; |
+ bool isPinned = model->IsTabPinned(index); |
+ bool isActive = (index == model->active_index()); |
+ |
+ TabStripModelDelegate::NewStripContents item; |
+ item.web_contents = model->GetWebContentsAt(index); |
+ item.add_types = |
+ (isActive ? TabStripModel::ADD_ACTIVE : TabStripModel::ADD_NONE) | |
+ (isPinned ? TabStripModel::ADD_PINNED : TabStripModel::ADD_NONE); |
+ contentses.push_back(item); |
+ } |
- // Detach it from the source window, which just updates the model without |
- // deleting the tab contents. This needs to come before creating the new |
- // Browser because it clears the WebContents' delegate, which gets hooked |
- // up during creation of the new window. |
- browser_->tab_strip_model()->DetachWebContentsAt(index); |
+ for (TabView* tabView in tabViews) { |
+ int index = [tabStripController_ modelIndexForTabView:tabView]; |
+ // Detach it from the source window, which just updates the model without |
+ // deleting the tab contents. This needs to come before creating the new |
+ // Browser because it clears the WebContents' delegate, which gets hooked |
+ // up during creation of the new window. |
+ model->DetachWebContentsAt(index); |
+ } |
- // Create the new window with a single tab in its model, the one being |
- // dragged. |
- TabStripModelDelegate::NewStripContents item; |
- item.web_contents = contents; |
- item.add_types = TabStripModel::ADD_ACTIVE | |
- (isPinned ? TabStripModel::ADD_PINNED |
- : TabStripModel::ADD_NONE); |
- std::vector<TabStripModelDelegate::NewStripContents> contentses; |
- contentses.push_back(item); |
+ // Create a new window with the dragged tabs in its model. |
Browser* newBrowser = browser_->tab_strip_model()->delegate()-> |
CreateNewStripWithContents(contentses, browserRect, false); |
@@ -1419,11 +1434,27 @@ enum { |
[newBrowser->window()->GetNativeWindow() delegate]); |
DCHECK(controller && [controller isKindOfClass:[TabWindowController class]]); |
- // Force the added tab to the right size (remove stretching.) |
- tabRect.size.height = [TabStripController defaultTabHeight]; |
- |
// And make sure we use the correct frame in the new view. |
- [[controller tabStripController] setFrameOfActiveTab:tabRect]; |
+ TabStripController* tabStripController = [controller tabStripController]; |
+ NSView* tabStrip = [self tabStripView]; |
+ NSEnumerator* tabEnumerator = [tabViews objectEnumerator]; |
+ for (NSView* newView in [tabStripController tabViews]) { |
+ NSView* oldView = [tabEnumerator nextObject]; |
+ if (oldView) { |
+ // Pushes tabView's frame back inside the tabstrip. |
+ NSRect sourceTabRect = [oldView frame]; |
+ NSSize tabOverflow = |
+ [self overflowFrom:[tabStrip convertRect:sourceTabRect toView:nil] |
+ to:[tabStrip frame]]; |
+ NSRect tabRect = |
+ NSOffsetRect(sourceTabRect, -tabOverflow.width, -tabOverflow.height); |
+ // Force the added tab to the right size (remove stretching.) |
+ tabRect.size.height = [TabStripController defaultTabHeight]; |
+ |
+ [tabStripController setFrame:tabRect ofTabView:newView]; |
+ } |
+ } |
+ |
return controller; |
} |