diff options
author | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-26 15:30:28 +0000 |
---|---|---|
committer | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-26 15:30:28 +0000 |
commit | 3d1104f27426048f4a951a614507b047fc7fd416 (patch) | |
tree | 559ee421338ba8fd85ea072bcde1003602086f30 /chrome/browser/cocoa | |
parent | 10f2e7c37e44d513524f816a230d47b503362460 (diff) | |
download | chromium_src-3d1104f27426048f4a951a614507b047fc7fd416.zip chromium_src-3d1104f27426048f4a951a614507b047fc7fd416.tar.gz chromium_src-3d1104f27426048f4a951a614507b047fc7fd416.tar.bz2 |
Allow live tabs to be dragged out of a window. Change TabStripModel such that
the caller must now explicitly show the newly created browser rather than it
happening automatically.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12550 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa')
-rw-r--r-- | chrome/browser/cocoa/browser_window_controller.mm | 35 | ||||
-rw-r--r-- | chrome/browser/cocoa/tab_strip_controller.h | 3 | ||||
-rw-r--r-- | chrome/browser/cocoa/tab_view.mm | 22 | ||||
-rw-r--r-- | chrome/browser/cocoa/tab_window_controller.h | 14 | ||||
-rw-r--r-- | chrome/browser/cocoa/tab_window_controller.mm | 34 |
5 files changed, 87 insertions, 21 deletions
diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm index 95452b2..06c629a 100644 --- a/chrome/browser/cocoa/browser_window_controller.mm +++ b/chrome/browser/cocoa/browser_window_controller.mm @@ -5,10 +5,12 @@ #import "chrome/app/chrome_dll_resource.h" // IDC_* #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" +#include "chrome/browser/tabs/tab_strip_model.h" #import "chrome/browser/cocoa/browser_window_cocoa.h" #import "chrome/browser/cocoa/browser_window_controller.h" #import "chrome/browser/cocoa/tab_strip_view.h" #import "chrome/browser/cocoa/tab_strip_controller.h" +#import "chrome/browser/cocoa/tab_view.h" @implementation BrowserWindowController @@ -205,8 +207,34 @@ } - (TabWindowController*)detachTabToNewWindow:(TabView*)tabView { - NOTIMPLEMENTED(); - return NULL; + // Fetch the tab contents for the tab being dragged + int index = [tabStripController_ indexForTabView:tabView]; + TabContents* contents = browser_->tabstrip_model()->GetTabContentsAt(index); + + // Set the window size. Need to do this before we detach the tab so it's + // still in the window. + NSRect windowRect = [[tabView window] frame]; + gfx::Rect browserRect(windowRect.origin.x, windowRect.origin.y, + windowRect.size.width, windowRect.size.height); + + // Create the new window with a single tab in its model, the one being + // dragged. + DockInfo dockInfo; + Browser* newBrowser = + browser_->tabstrip_model()->TearOffTabContents(contents, + browserRect, + dockInfo); + + // Get the new controller by asking the new window for its delegate. + TabWindowController* controller = + [newBrowser->window()->GetNativeHandle() delegate]; + DCHECK(controller && [controller isKindOfClass:[TabWindowController class]]); + + // Detach it from the source window, which just updates the model without + // deleting the tab contents. + browser_->tabstrip_model()->DetachTabContentsAt(index); + + return controller; } - (void)insertPlaceholderForTab:(TabView*)tab atLocation:(NSInteger)xLocation { @@ -226,5 +254,8 @@ [tabStripController_ toggleBookmarkBar]; } +- (NSInteger)numberOfTabs { + return browser_->tabstrip_model()->count(); +} @end diff --git a/chrome/browser/cocoa/tab_strip_controller.h b/chrome/browser/cocoa/tab_strip_controller.h index 0bd7df4..1d6686a 100644 --- a/chrome/browser/cocoa/tab_strip_controller.h +++ b/chrome/browser/cocoa/tab_strip_controller.h @@ -88,6 +88,9 @@ class ToolbarModel; // Turn on or off the bookmark bar for *ALL* tabs. - (void)toggleBookmarkBar; +// Given a tab view in the strip, return its index. Returns -1 if not present. +- (NSInteger)indexForTabView:(NSView*)view; + @end #endif // CHROME_BROWSER_COCOA_TAB_STRIP_CONTROLLER_H_ diff --git a/chrome/browser/cocoa/tab_view.mm b/chrome/browser/cocoa/tab_view.mm index 5fee1d5..16446ac 100644 --- a/chrome/browser/cocoa/tab_view.mm +++ b/chrome/browser/cocoa/tab_view.mm @@ -64,7 +64,9 @@ TabWindowController* draggedController = nil; TabWindowController* targetController = nil; - BOOL isLastTab = NO; // TODO(alcor) + // We don't want to "tear off" a tab if there's only one in the window. Treat + // it like we're dragging around a tab we've already detached. + BOOL isLastRemainingTab = [sourceController numberOfTabs] == 1; NSWindow* dragWindow = nil; NSWindow* dragOverlay = nil; @@ -88,7 +90,7 @@ // appropriate class, and visible (obviously). if (![targets count]) { for (NSWindow* window in [NSApp windows]) { - if (window == sourceWindow && isLastTab) continue; + if (window == sourceWindow && isLastRemainingTab) continue; if (window == dragWindow) continue; if (![window isVisible]) continue; NSWindowController *controller = [window windowController]; @@ -121,11 +123,9 @@ NSEventType type = [theEvent type]; if (type == NSLeftMouseDragged) { -#if 0 - // TODO(alcor): get this working... moved = YES; if (!draggedController) { - if (isLastTab) { + if (isLastRemainingTab) { draggedController = sourceController; dragWindow = [draggedController window]; } else { @@ -144,7 +144,7 @@ } // Bring the target window to the front and make sure it has a border. - [[draggedController window] setLevel:NSFloatingWindowLevel]; + [dragWindow setLevel:NSFloatingWindowLevel]; [dragWindow orderFront:nil]; [dragWindow makeMainWindow]; [draggedController showOverlay]; @@ -162,7 +162,7 @@ // If we're not hovering over any window, make the window is fully // opaque. Otherwise, find where the tab might be dropped and insert // a placeholder so it appears like it's part of that window. - if (!targetContoller) { + if (!targetController) { [[dragWindow animator] setAlphaValue:1.0]; } else { if (![[targetController window] isKeyWindow]) { @@ -179,7 +179,7 @@ [sourceWindow convertBaseToScreen: [self convertPointToBase:NSZeroPoint]]; int x = NSWidth([self bounds]) / 2 + point.x - dropTabFrame.origin.x; - [targetController insertPlaceholderForTab:tab_ atLocation:x]; + [targetController insertPlaceholderForTab:self atLocation:x]; [targetController arrangeTabs]; if (!targetController) @@ -190,7 +190,6 @@ setAlphaValue:targetController ? 0.85 : 1.0]; // [setAlphaValue:targetController ? 0.0 : 0.6]; } -#endif } else if (type == NSLeftMouseUp) { // Mouse up, break out of the drag event tracking loop dragging = NO; @@ -203,6 +202,8 @@ if (moved) { TabWindowController *dropController = targetController; if (dropController) { +#if 0 +// TODO(alcor/pinkerton): hookup drops on existing windows NSRect adjustedFrame = [self bounds]; NSRect dropTabFrame = [[dropController tabStripView] frame]; adjustedFrame.origin = [self convertPointToBase:NSZeroPoint]; @@ -220,11 +221,12 @@ [dropController arrangeTabs]; [draggedController close]; [dropController showWindow:nil]; +#endif } else { [[dragWindow animator] setAlphaValue:1.0]; [dragOverlay setHasShadow:NO]; [draggedController removeOverlayAfterDelay: - [[NSAnimationContext currentContext] duration]]; + [[NSAnimationContext currentContext] duration]]; [dragWindow makeKeyAndOrderFront:nil]; [[draggedController window] setLevel:NSNormalWindowLevel]; diff --git a/chrome/browser/cocoa/tab_window_controller.h b/chrome/browser/cocoa/tab_window_controller.h index fee790a..f0fcb524 100644 --- a/chrome/browser/cocoa/tab_window_controller.h +++ b/chrome/browser/cocoa/tab_window_controller.h @@ -19,9 +19,14 @@ @interface TabWindowController : NSWindowController { @private - IBOutlet NSBox* contentBox_; + IBOutlet NSBox* contentBox_; // Only valid at window creation time, used + // to position the tab strip. nil afterwards. + // TODO(pinkerton): get rid of this. IBOutlet TabStripView* tabStripView_; - NSWindow* overlayWindow_; // used during dragging + NSWindow* overlayWindow_; // Used during dragging for window opacity tricks + NSView* cachedContentView_; // Used during dragging for identifying which + // view is the proper content area in the overlay + // (weak) } @property(readonly, nonatomic) TabStripView* tabStripView; @@ -30,6 +35,7 @@ - (void)showOverlay; - (void)removeOverlay; - (void)removeOverlayAfterDelay:(NSTimeInterval)delay; +- (NSWindow*)overlayWindow; // A collection of methods, stubbed out in this base class, that provide // the implementation of tab dragging based on whatever model is most @@ -50,6 +56,10 @@ // Removes the placeholder installed by |-insertPlaceholderForTab:atLocation:|. - (void)removePlaceholder; +// Number of tabs in the tab strip. Useful, for example, to know if we're +// dragging the only tab in the window. +- (NSInteger)numberOfTabs; + @end #endif // CHROME_BROWSER_TAB_WINDOW_CONTROLLER_H_ diff --git a/chrome/browser/cocoa/tab_window_controller.mm b/chrome/browser/cocoa/tab_window_controller.mm index 0729c37..691095f 100644 --- a/chrome/browser/cocoa/tab_window_controller.mm +++ b/chrome/browser/cocoa/tab_window_controller.mm @@ -22,6 +22,10 @@ tabFrame.size.height = NSHeight([tabStripView_ frame]); [tabStripView_ setFrame:tabFrame]; [[[[self window] contentView] superview] addSubview:tabStripView_]; + + // tab switching will destroy the content area, so nil this out to ensure + // that nobody tries to use it. + contentBox_ = nil; } - (void)removeOverlay { @@ -41,11 +45,17 @@ [self setUseOverlay:YES]; } +// If |useOverlay| is YES, creates a new overlay window and puts the tab strip +// and the content area inside of it. This allows it to have a different opacity +// from the title bar. If NO, returns everything to the previous state and +// destroys the overlay window until it's needed again. The tab strip and window +// contents are returned to the original window. - (void)setUseOverlay:(BOOL)useOverlay { [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(removeOverlay) object:nil]; if (useOverlay && !overlayWindow_) { + DCHECK(!cachedContentView_); overlayWindow_ = [[NSPanel alloc] initWithContentRect:[[self window] frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered @@ -55,27 +65,31 @@ [overlayWindow_ setOpaque:NO]; NSView *contentView = [overlayWindow_ contentView]; [contentView addSubview:[self tabStripView]]; - [contentView addSubview:contentBox_]; + cachedContentView_ = [[self window] contentView]; + [contentView addSubview:cachedContentView_]; [overlayWindow_ setHasShadow:YES]; [[self window] addChildWindow:overlayWindow_ ordered:NSWindowAbove]; [overlayWindow_ orderFront:nil]; - [[self window] setHasShadow:NO]; } else if (!useOverlay && overlayWindow_) { - NSResponder *responder = [overlayWindow_ firstResponder]; + DCHECK(cachedContentView_); [[self window] setHasShadow:YES]; - NSView *contentView = [[self window] contentView]; - [contentView addSubview:contentBox_]; - [[contentView superview] addSubview:[self tabStripView]]; - [[self window] makeFirstResponder:responder]; + [[self window] setContentView:cachedContentView_]; + [[cachedContentView_ superview] addSubview:[self tabStripView]]; + [[self window] makeFirstResponder:cachedContentView_]; [[self window] display]; [[self window] removeChildWindow:overlayWindow_]; [overlayWindow_ orderOut:nil]; [overlayWindow_ release]; overlayWindow_ = nil; + cachedContentView_ = nil; } } +- (NSWindow*)overlayWindow { + return overlayWindow_; +} + - (void)arrangeTabs { // subclass must implement NOTIMPLEMENTED(); @@ -97,4 +111,10 @@ NOTIMPLEMENTED(); } +- (NSInteger)numberOfTabs { + // subclass must implement + NOTIMPLEMENTED(); + return 0; +} + @end |