Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(108)

Side by Side Diff: chrome/browser/ui/cocoa/browser_window_controller.mm

Issue 157403004: [mac] Implement dragging of multiple tabs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixes for rsesek. Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | chrome/browser/ui/cocoa/tabs/tab_strip_controller.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "chrome/browser/ui/cocoa/browser_window_controller.h" 5 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
6 6
7 #include <cmath> 7 #include <cmath>
8 #include <numeric> 8 #include <numeric>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 1265 matching lines...) Expand 10 before | Expand all | Expand 10 after
1276 return YES; 1276 return YES;
1277 } 1277 }
1278 1278
1279 // Move a given tab view to the location of the current placeholder. If there is 1279 // Move a given tab view to the location of the current placeholder. If there is
1280 // no placeholder, it will go at the end. |controller| is the window controller 1280 // no placeholder, it will go at the end. |controller| is the window controller
1281 // of a tab being dropped from a different window. It will be nil if the drag is 1281 // of a tab being dropped from a different window. It will be nil if the drag is
1282 // within the window, otherwise the tab is removed from that window before being 1282 // within the window, otherwise the tab is removed from that window before being
1283 // placed into this one. The implementation will call |-removePlaceholder| since 1283 // placed into this one. The implementation will call |-removePlaceholder| since
1284 // the drag is now complete. This also calls |-layoutTabs| internally so 1284 // the drag is now complete. This also calls |-layoutTabs| internally so
1285 // clients do not need to call it again. 1285 // clients do not need to call it again.
1286 - (void)moveTabView:(NSView*)view 1286 - (void)moveTabViews:(NSArray*)views
1287 fromController:(TabWindowController*)dragController { 1287 fromController:(TabWindowController*)dragController {
1288 if (dragController) { 1288 if (dragController) {
1289 // Moving between windows. Figure out the WebContents to drop into our tab 1289 // Moving between windows.
1290 // model from the source window's model. 1290 NSView* activeTabView = [dragController activeTabView];
1291 BrowserWindowController* dragBWC = 1291 BrowserWindowController* dragBWC =
1292 base::mac::ObjCCastStrict<BrowserWindowController>(dragController); 1292 base::mac::ObjCCastStrict<BrowserWindowController>(dragController);
1293 int index = [dragBWC->tabStripController_ modelIndexForTabView:view];
1294 WebContents* contents =
1295 dragBWC->browser_->tab_strip_model()->GetWebContentsAt(index);
1296 // The tab contents may have gone away if given a window.close() while it
1297 // is being dragged. If so, bail, we've got nothing to drop.
1298 if (!contents)
1299 return;
1300 1293
1301 // Convert |view|'s frame (which starts in the source tab strip's coordinate 1294 // We will drop the tabs starting at indexOfPlaceholder, and increment from
1302 // system) to the coordinate system of the destination tab strip. This needs 1295 // there. We remove the placehoder before dropping the tabs, so that the
1303 // to be done before being detached so the window transforms can be 1296 // new tab animation's destination frame is correct.
1304 // performed. 1297 int tabIndex = [tabStripController_ indexOfPlaceholder];
1305 NSRect destinationFrame = [view frame]; 1298 [self removePlaceholder];
1306 NSPoint tabOrigin = destinationFrame.origin;
1307 tabOrigin = [[dragController tabStripView] convertPoint:tabOrigin
1308 toView:nil];
1309 tabOrigin = [[view window] convertBaseToScreen:tabOrigin];
1310 tabOrigin = [[self window] convertScreenToBase:tabOrigin];
1311 tabOrigin = [[self tabStripView] convertPoint:tabOrigin fromView:nil];
1312 destinationFrame.origin = tabOrigin;
1313 1299
1314 // Before the tab is detached from its originating tab strip, store the 1300 for (NSView* view in views) {
1315 // pinned state so that it can be maintained between the windows. 1301 // Figure out the WebContents to drop into our tab model from the source
1316 bool isPinned = dragBWC->browser_->tab_strip_model()->IsTabPinned(index); 1302 // window's model.
1303 int index = [dragBWC->tabStripController_ modelIndexForTabView:view];
1304 WebContents* contents =
1305 dragBWC->browser_->tab_strip_model()->GetWebContentsAt(index);
1306 // The tab contents may have gone away if given a window.close() while it
1307 // is being dragged. If so, bail, we've got nothing to drop.
1308 if (!contents)
1309 continue;
1317 1310
1318 // Now that we have enough information about the tab, we can remove it from 1311 // Convert |view|'s frame (which starts in the source tab strip's
1319 // the dragging window. We need to do this *before* we add it to the new 1312 // coordinate system) to the coordinate system of the destination tab
1320 // window as this will remove the WebContents' delegate. 1313 // strip. This needs to be done before being detached so the window
1321 [dragController detachTabView:view]; 1314 // transforms can be performed.
1315 NSRect destinationFrame = [view frame];
1316 NSPoint tabOrigin = destinationFrame.origin;
1317 tabOrigin = [[dragController tabStripView] convertPoint:tabOrigin
1318 toView:nil];
1319 tabOrigin = [[dragController window] convertBaseToScreen:tabOrigin];
1320 tabOrigin = [[self window] convertScreenToBase:tabOrigin];
1321 tabOrigin = [[self tabStripView] convertPoint:tabOrigin fromView:nil];
1322 destinationFrame.origin = tabOrigin;
1322 1323
1323 // Deposit it into our model at the appropriate location (it already knows 1324 // Before the tab is detached from its originating tab strip, store the
1324 // where it should go from tracking the drag). Doing this sets the tab's 1325 // pinned state so that it can be maintained between the windows.
1325 // delegate to be the Browser. 1326 bool isPinned = dragBWC->browser_->tab_strip_model()->IsTabPinned(index);
1326 [tabStripController_ dropWebContents:contents 1327
1327 withFrame:destinationFrame 1328 // Now that we have enough information about the tab, we can remove it
1328 asPinnedTab:isPinned]; 1329 // from the dragging window. We need to do this *before* we add it to the
1330 // new window as this will remove the WebContents' delegate.
1331 [dragController detachTabView:view];
1332
1333 // Deposit it into our model at the appropriate location (it already knows
1334 // where it should go from tracking the drag). Doing this sets the tab's
1335 // delegate to be the Browser.
1336 [tabStripController_ dropWebContents:contents
1337 atIndex:tabIndex++
1338 withFrame:destinationFrame
1339 asPinnedTab:isPinned
1340 activate:view == activeTabView];
1341 }
1329 } else { 1342 } else {
1330 // Moving within a window. 1343 // Moving within a window.
1331 int index = [tabStripController_ modelIndexForTabView:view]; 1344 for (NSView* view in views) {
1332 [tabStripController_ moveTabFromIndex:index]; 1345 int index = [tabStripController_ modelIndexForTabView:view];
1346 [tabStripController_ moveTabFromIndex:index];
1347 }
1348 [self removePlaceholder];
1333 } 1349 }
1334
1335 // Remove the placeholder since the drag is now complete.
1336 [self removePlaceholder];
1337 } 1350 }
1338 1351
1339 // Tells the tab strip to forget about this tab in preparation for it being 1352 // Tells the tab strip to forget about this tab in preparation for it being
1340 // put into a different tab strip, such as during a drop on another window. 1353 // put into a different tab strip, such as during a drop on another window.
1341 - (void)detachTabView:(NSView*)view { 1354 - (void)detachTabView:(NSView*)view {
1342 int index = [tabStripController_ modelIndexForTabView:view]; 1355 int index = [tabStripController_ modelIndexForTabView:view];
1343 browser_->tab_strip_model()->DetachWebContentsAt(index); 1356 browser_->tab_strip_model()->DetachWebContentsAt(index);
1344 } 1357 }
1345 1358
1359 - (NSArray*)tabViews {
1360 return [tabStripController_ tabViews];
1361 }
1362
1346 - (NSView*)activeTabView { 1363 - (NSView*)activeTabView {
1347 return [tabStripController_ activeTabView]; 1364 return [tabStripController_ activeTabView];
1348 } 1365 }
1349 1366
1350 - (void)setIsLoading:(BOOL)isLoading force:(BOOL)force { 1367 - (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
1351 [toolbarController_ setIsLoading:isLoading force:force]; 1368 [toolbarController_ setIsLoading:isLoading force:force];
1352 } 1369 }
1353 1370
1354 // Make the location bar the first responder, if possible. 1371 // Make the location bar the first responder, if possible.
1355 - (void)focusLocationBar:(BOOL)selectAll { 1372 - (void)focusLocationBar:(BOOL)selectAll {
1356 [toolbarController_ focusLocationBar:selectAll]; 1373 [toolbarController_ focusLocationBar:selectAll];
1357 } 1374 }
1358 1375
1359 - (void)focusTabContents { 1376 - (void)focusTabContents {
1360 [[self window] makeFirstResponder:[tabStripController_ activeTabView]]; 1377 [[self window] makeFirstResponder:[tabStripController_ activeTabView]];
1361 } 1378 }
1362 1379
1363 - (void)layoutTabs { 1380 - (void)layoutTabs {
1364 [tabStripController_ layoutTabs]; 1381 [tabStripController_ layoutTabs];
1365 } 1382 }
1366 1383
1367 - (TabWindowController*)detachTabToNewWindow:(TabView*)tabView { 1384 - (TabWindowController*)detachTabsToNewWindow:(NSArray*)tabViews
1385 draggedTab:(NSView*)draggedTab {
1386 DCHECK_GT([tabViews count], 0U);
1387
1368 // Disable screen updates so that this appears as a single visual change. 1388 // Disable screen updates so that this appears as a single visual change.
1369 gfx::ScopedNSDisableScreenUpdates disabler; 1389 gfx::ScopedNSDisableScreenUpdates disabler;
1370 1390
1371 // Fetch the tab contents for the tab being dragged.
1372 int index = [tabStripController_ modelIndexForTabView:tabView];
1373 WebContents* contents = browser_->tab_strip_model()->GetWebContentsAt(index);
1374
1375 // Set the window size. Need to do this before we detach the tab so it's 1391 // Set the window size. Need to do this before we detach the tab so it's
1376 // still in the window. We have to flip the coordinates as that's what 1392 // still in the window. We have to flip the coordinates as that's what
1377 // is expected by the Browser code. 1393 // is expected by the Browser code.
1378 NSWindow* sourceWindow = [tabView window]; 1394 NSWindow* sourceWindow = [draggedTab window];
1379 NSRect windowRect = [sourceWindow frame]; 1395 NSRect windowRect = [sourceWindow frame];
1380 NSScreen* screen = [sourceWindow screen]; 1396 NSScreen* screen = [sourceWindow screen];
1381 windowRect.origin.y = NSHeight([screen frame]) - NSMaxY(windowRect); 1397 windowRect.origin.y = NSHeight([screen frame]) - NSMaxY(windowRect);
1382 gfx::Rect browserRect(windowRect.origin.x, windowRect.origin.y, 1398 gfx::Rect browserRect(windowRect.origin.x, windowRect.origin.y,
1383 NSWidth(windowRect), NSHeight(windowRect)); 1399 NSWidth(windowRect), NSHeight(windowRect));
1384 1400
1385 NSRect sourceTabRect = [tabView frame]; 1401 std::vector<TabStripModelDelegate::NewStripContents> contentses;
1386 NSView* tabStrip = [self tabStripView]; 1402 TabStripModel* model = browser_->tab_strip_model();
1387 1403
1388 // Pushes tabView's frame back inside the tabstrip. 1404 for (TabView* tabView in tabViews) {
1389 NSSize tabOverflow = 1405 // Fetch the tab contents for the tab being dragged.
1390 [self overflowFrom:[tabStrip convertRect:sourceTabRect toView:nil] 1406 int index = [tabStripController_ modelIndexForTabView:tabView];
1391 to:[tabStrip frame]]; 1407 bool isPinned = model->IsTabPinned(index);
1392 NSRect tabRect = NSOffsetRect(sourceTabRect, 1408 bool isActive = (index == model->active_index());
1393 -tabOverflow.width, -tabOverflow.height);
1394 1409
1395 // Before detaching the tab, store the pinned state. 1410 TabStripModelDelegate::NewStripContents item;
1396 bool isPinned = browser_->tab_strip_model()->IsTabPinned(index); 1411 item.web_contents = model->GetWebContentsAt(index);
1412 item.add_types =
1413 (isActive ? TabStripModel::ADD_ACTIVE : TabStripModel::ADD_NONE) |
1414 (isPinned ? TabStripModel::ADD_PINNED : TabStripModel::ADD_NONE);
1415 contentses.push_back(item);
1416 }
1397 1417
1398 // Detach it from the source window, which just updates the model without 1418 for (TabView* tabView in tabViews) {
1399 // deleting the tab contents. This needs to come before creating the new 1419 int index = [tabStripController_ modelIndexForTabView:tabView];
1400 // Browser because it clears the WebContents' delegate, which gets hooked 1420 // Detach it from the source window, which just updates the model without
1401 // up during creation of the new window. 1421 // deleting the tab contents. This needs to come before creating the new
1402 browser_->tab_strip_model()->DetachWebContentsAt(index); 1422 // Browser because it clears the WebContents' delegate, which gets hooked
1423 // up during creation of the new window.
1424 model->DetachWebContentsAt(index);
1425 }
1403 1426
1404 // Create the new window with a single tab in its model, the one being 1427 // Create a new window with the dragged tabs in its model.
1405 // dragged.
1406 TabStripModelDelegate::NewStripContents item;
1407 item.web_contents = contents;
1408 item.add_types = TabStripModel::ADD_ACTIVE |
1409 (isPinned ? TabStripModel::ADD_PINNED
1410 : TabStripModel::ADD_NONE);
1411 std::vector<TabStripModelDelegate::NewStripContents> contentses;
1412 contentses.push_back(item);
1413 Browser* newBrowser = browser_->tab_strip_model()->delegate()-> 1428 Browser* newBrowser = browser_->tab_strip_model()->delegate()->
1414 CreateNewStripWithContents(contentses, browserRect, false); 1429 CreateNewStripWithContents(contentses, browserRect, false);
1415 1430
1416 // Get the new controller by asking the new window for its delegate. 1431 // Get the new controller by asking the new window for its delegate.
1417 BrowserWindowController* controller = 1432 BrowserWindowController* controller =
1418 reinterpret_cast<BrowserWindowController*>( 1433 reinterpret_cast<BrowserWindowController*>(
1419 [newBrowser->window()->GetNativeWindow() delegate]); 1434 [newBrowser->window()->GetNativeWindow() delegate]);
1420 DCHECK(controller && [controller isKindOfClass:[TabWindowController class]]); 1435 DCHECK(controller && [controller isKindOfClass:[TabWindowController class]]);
1421 1436
1422 // Force the added tab to the right size (remove stretching.) 1437 // And make sure we use the correct frame in the new view.
1423 tabRect.size.height = [TabStripController defaultTabHeight]; 1438 TabStripController* tabStripController = [controller tabStripController];
1439 NSView* tabStrip = [self tabStripView];
1440 NSEnumerator* tabEnumerator = [tabViews objectEnumerator];
1441 for (NSView* newView in [tabStripController tabViews]) {
1442 NSView* oldView = [tabEnumerator nextObject];
1443 if (oldView) {
1444 // Pushes tabView's frame back inside the tabstrip.
1445 NSRect sourceTabRect = [oldView frame];
1446 NSSize tabOverflow =
1447 [self overflowFrom:[tabStrip convertRect:sourceTabRect toView:nil]
1448 to:[tabStrip frame]];
1449 NSRect tabRect =
1450 NSOffsetRect(sourceTabRect, -tabOverflow.width, -tabOverflow.height);
1451 // Force the added tab to the right size (remove stretching.)
1452 tabRect.size.height = [TabStripController defaultTabHeight];
1424 1453
1425 // And make sure we use the correct frame in the new view. 1454 [tabStripController setFrame:tabRect ofTabView:newView];
1426 [[controller tabStripController] setFrameOfActiveTab:tabRect]; 1455 }
1456 }
1457
1427 return controller; 1458 return controller;
1428 } 1459 }
1429 1460
1430 - (void)insertPlaceholderForTab:(TabView*)tab 1461 - (void)insertPlaceholderForTab:(TabView*)tab
1431 frame:(NSRect)frame { 1462 frame:(NSRect)frame {
1432 [super insertPlaceholderForTab:tab frame:frame]; 1463 [super insertPlaceholderForTab:tab frame:frame];
1433 [tabStripController_ insertPlaceholderForTab:tab frame:frame]; 1464 [tabStripController_ insertPlaceholderForTab:tab frame:frame];
1434 } 1465 }
1435 1466
1436 - (void)removePlaceholder { 1467 - (void)removePlaceholder {
(...skipping 747 matching lines...) Expand 10 before | Expand all | Expand 10 after
2184 2215
2185 - (BOOL)supportsBookmarkBar { 2216 - (BOOL)supportsBookmarkBar {
2186 return [self supportsWindowFeature:Browser::FEATURE_BOOKMARKBAR]; 2217 return [self supportsWindowFeature:Browser::FEATURE_BOOKMARKBAR];
2187 } 2218 }
2188 2219
2189 - (BOOL)isTabbedWindow { 2220 - (BOOL)isTabbedWindow {
2190 return browser_->is_type_tabbed(); 2221 return browser_->is_type_tabbed();
2191 } 2222 }
2192 2223
2193 @end // @implementation BrowserWindowController(WindowType) 2224 @end // @implementation BrowserWindowController(WindowType)
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/ui/cocoa/tabs/tab_strip_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698