diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/SPWindowController.m | 376 | ||||
-rw-r--r-- | Source/SPWindowControllerDelegate.h | 37 | ||||
-rw-r--r-- | Source/SPWindowControllerDelegate.m | 432 |
3 files changed, 471 insertions, 374 deletions
diff --git a/Source/SPWindowController.m b/Source/SPWindowController.m index 7e461177..eeecca68 100644 --- a/Source/SPWindowController.m +++ b/Source/SPWindowController.m @@ -32,9 +32,9 @@ enum { #import "SPWindowController.h" #import "SPDatabaseDocument.h" -#import "PSMTabDragAssistant.h" #import "SPDatabaseViewController.h" #import "SPAppController.h" +#import "PSMTabDragAssistant.h" #import <PSMTabBar/PSMTabBarControl.h> #import <PSMTabBar/PSMTabStyle.h> @@ -115,7 +115,7 @@ enum { /** * Add a new database connection to the window, in a tab view. */ -- (IBAction) addNewConnection:(id)sender +- (IBAction)addNewConnection:(id)sender { // Create a new database connection view SPDatabaseDocument *newTableDocument = [[SPDatabaseDocument alloc] init]; @@ -359,378 +359,6 @@ enum { } #pragma mark - -#pragma mark Tab view delegate methods - -/** - * Called when a tab item is about to be selected. - */ -- (void)tabView:(NSTabView *)tabView willSelectTabViewItem:(NSTabViewItem *)tabViewItem -{ - [selectedTableDocument willResignActiveTabInWindow]; -} - -/** - * Called when a tab item was selected. - */ -- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem -{ - if ([[PSMTabDragAssistant sharedDragAssistant] isDragging]) return; - selectedTableDocument = [tabViewItem identifier]; - [selectedTableDocument didBecomeActiveTabInWindow]; - if ([[self window] isKeyWindow]) [selectedTableDocument tabDidBecomeKey]; - [self updateAllTabTitles:self]; -} - -/** - * Called to determine whether a tab view item can be closed - */ -- (BOOL)tabView:(NSTabView *)aTabView shouldCloseTabViewItem:(NSTabViewItem *)tabViewItem -{ - SPDatabaseDocument *theDocument = [tabViewItem identifier]; - if (![theDocument parentTabShouldClose]) return NO; - return YES; -} - -/** - * Called after a tab view item is closed. - */ -- (void)tabView:(NSTabView *)aTabView didCloseTabViewItem:(NSTabViewItem *)tabViewItem -{ - SPDatabaseDocument *theDocument = [tabViewItem identifier]; - [theDocument removeObserver:self forKeyPath:@"isProcessing"]; - [theDocument parentTabDidClose]; -} - -/** - * Called to allow dragging of tab view items - */ -- (BOOL)tabView:(NSTabView *)aTabView shouldDragTabViewItem:(NSTabViewItem *)tabViewItem fromTabBar:(PSMTabBarControl *)tabBarControl -{ - return YES; -} - -/** - * Called when a tab finishes a drop. This is called with the new tabView. - */ -- (void)tabView:(NSTabView*)aTabView didDropTabViewItem:(NSTabViewItem *)tabViewItem inTabBar:(PSMTabBarControl *)tabBarControl -{ - SPDatabaseDocument *draggedDocument = [tabViewItem identifier]; - - // Grab a reference to the old window - NSWindow *draggedFromWindow = [draggedDocument parentWindow]; - - // If the window changed, perform additional processing. - if (draggedFromWindow != [tabBarControl window]) { - - // Update the old window, ensuring the toolbar is cleared to prevent issues with toolbars in multiple windows - [draggedFromWindow setToolbar:nil]; - [[draggedFromWindow windowController] updateSelectedTableDocument]; - - // Update the item's document's window and controller - [draggedDocument willResignActiveTabInWindow]; - [draggedDocument setParentWindowController:[[tabBarControl window] windowController]]; - [draggedDocument setParentWindow:[tabBarControl window]]; - [draggedDocument didBecomeActiveTabInWindow]; - - // Update window controller's active tab, and update the document's isProcessing observation - [[[tabBarControl window] windowController] updateSelectedTableDocument]; - [draggedDocument removeObserver:[draggedFromWindow windowController] forKeyPath:@"isProcessing"]; - [[[tabBarControl window] windowController] _updateProgressIndicatorForItem:tabViewItem]; - } - - // Check the window and move it to front if it's key (eg for new window creation) - if ([[tabBarControl window] isKeyWindow]) [[tabBarControl window] orderFront:self]; -} - -/** - * Respond to dragging events entering the tab in the tab bar. - * Allows custom behaviours - for example, if dragging text, switch to the custom - * query view. - */ -- (void)draggingEvent:(id <NSDraggingInfo>)dragEvent enteredTabBar:(PSMTabBarControl *)tabBarControl tabView:(NSTabViewItem *)tabViewItem -{ - SPDatabaseDocument *theDocument = [tabViewItem identifier]; - - if (![theDocument isCustomQuerySelected] - && [[[dragEvent draggingPasteboard] types] indexOfObject:NSStringPboardType] != NSNotFound) - { - [theDocument viewQuery:self]; - } -} - -/** - * Show tooltip for a tab view item. - */ -- (NSString *)tabView:(NSTabView *)aTabView toolTipForTabViewItem:(NSTabViewItem *)tabViewItem -{ - - NSInteger tabIndex = [tabView indexOfTabViewItem:tabViewItem]; - - if([[tabBar cells] count] < (NSUInteger)tabIndex) return @""; - - PSMTabBarCell *theCell = [[tabBar cells] objectAtIndex:tabIndex]; - - // If cell is selected show tooltip if truncated only - if([theCell tabState] & PSMTab_SelectedMask) { - - CGFloat cellWidth = [theCell width]; - CGFloat titleWidth = [theCell stringSize].width; - CGFloat closeButtonWidth = 0; - - if([theCell hasCloseButton]) - closeButtonWidth = [theCell closeButtonRectForFrame:[theCell frame]].size.width; - - if(titleWidth > cellWidth - closeButtonWidth) - return [theCell title]; - - return @""; - - // if cell is not selected show full title plus MySQL version is enabled as tooltip - } else { - if([[tabViewItem identifier] respondsToSelector:@selector(tabTitleForTooltip)]) - return [[tabViewItem identifier] tabTitleForTooltip]; - - return @""; - - } - -} - -/** - * Allow window closing of the last tab item. - */ -- (void)tabView:(NSTabView *)aTabView closeWindowForLastTabViewItem:(NSTabViewItem *)tabViewItem -{ - [[aTabView window] close]; -} - -/** - * When dragging a tab off a tab bar, add a shadow to the drag window. - */ -- (void)tabViewDragWindowCreated:(NSWindow *)dragWindow -{ - [dragWindow setHasShadow:YES]; -} - -/** - * Allow dragging and dropping of tabs to any position, including out of a tab bar - * to create a new window. - */ -- (BOOL)tabView:(NSTabView*)aTabView shouldDropTabViewItem:(NSTabViewItem *)tabViewItem inTabBar:(PSMTabBarControl *)tabBarControl -{ - return YES; -} - -/** - * When a tab is dragged off a tab bar, create a new window containing a new - * (empty) tab bar to hold it. - */ -- (PSMTabBarControl *)tabView:(NSTabView *)aTabView newTabBarForDraggedTabViewItem:(NSTabViewItem *)tabViewItem atPoint:(NSPoint)point -{ - - // Create the new window controller, with no tabs - SPWindowController *newWindowController = [[SPWindowController alloc] initWithWindowNibName:@"MainWindow"]; - NSWindow *newWindow = [newWindowController window]; - - CGFloat toolbarHeight = 0; - if ([[[self window] toolbar] isVisible]) { - NSRect innerFrame = [NSWindow contentRectForFrameRect:[[self window] frame] styleMask:[[self window] styleMask]]; - toolbarHeight = innerFrame.size.height - [[[self window] contentView] frame].size.height; - } - - // Adjust the positioning as appropriate - point.y += toolbarHeight; - if ([[NSUserDefaults standardUserDefaults] boolForKey:SPAlwaysShowWindowTabBar]) point.y += kPSMTabBarControlHeight; - - // Set the new window position and size - NSRect targetWindowFrame = [[self window] frame]; - targetWindowFrame.size.height -= toolbarHeight; - [newWindow setFrame:targetWindowFrame display:NO]; - [newWindow setFrameTopLeftPoint:point]; - - // Set the window controller as the window's delegate - [newWindow setDelegate:newWindowController]; - - // Set window title - [newWindow setTitle:[[[tabViewItem identifier] parentWindow] title]]; - - // Return the window's tab bar - return [newWindowController valueForKey:@"tabBar"]; -} - -/** - * When dragging a tab off the tab bar, return an image so that a - * drag placeholder can be displayed. - */ -- (NSImage *)tabView:(NSTabView *)aTabView imageForTabViewItem:(NSTabViewItem *)tabViewItem offset:(NSSize *)offset styleMask:(unsigned int *)styleMask -{ - NSImage *viewImage = [[NSImage alloc] init]; - - // Capture an image of the entire window - CGImageRef windowImage = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, (unsigned int)[[self window] windowNumber], kCGWindowImageBoundsIgnoreFraming); - NSBitmapImageRep *viewRep = [[NSBitmapImageRep alloc] initWithCGImage:windowImage]; - [viewImage addRepresentation:viewRep]; - - // Calculate the titlebar+toolbar height - CGFloat contentViewOffsetY = [[self window] frame].size.height - [[[self window] contentView] frame].size.height; - offset->height = contentViewOffsetY + [tabBar frame].size.height; - - // Draw over the tab bar area - [viewImage lockFocus]; - [[NSColor windowBackgroundColor] set]; - NSRectFill([tabBar frame]); - [viewImage unlockFocus]; - - // Draw the tab bar background in the tab bar area - [viewImage lockFocus]; - NSRect tabFrame = [tabBar frame]; - [[NSColor windowBackgroundColor] set]; - NSRectFill(tabFrame); - - // Draw the background flipped, which is actually the right way up - NSAffineTransform *transform = [NSAffineTransform transform]; - [transform translateXBy:0.0f yBy:[[[self window] contentView] frame].size.height]; - [transform scaleXBy:1.0f yBy:-1.0f]; - [transform concat]; - [(id <PSMTabStyle>)[[aTabView delegate] style] drawBackgroundInRect:tabFrame]; - [viewImage unlockFocus]; - - return [viewImage autorelease]; -} - -/** - * Displays the current tab's context menu. - */ -- (NSMenu *)tabView:(NSTabView *)aTabView menuForTabViewItem:(NSTabViewItem *)tabViewItem -{ - NSMenu *menu = [[NSMenu alloc] init]; - - [menu addItemWithTitle:NSLocalizedString(@"Close Tab", @"close tab context menu item") action:@selector(closeTab:) keyEquivalent:@""]; - [menu insertItem:[NSMenuItem separatorItem] atIndex:1]; - [menu addItemWithTitle:NSLocalizedString(@"Open in New Tab", @"open connection in new tab context menu item") action:@selector(openDatabaseInNewTab:) keyEquivalent:@""]; - - return [menu autorelease]; -} - -/** - * When tab drags start, show all the tab bars. This allows adding tabs to windows - * containing only one tab - where the bar is normally hidden. - */ -- (void)tabDragStarted:(id)sender -{ - [tabBar setHideForSingleTab:NO]; -} - -/** - * When tab drags stop, set tab bars to automatically hide again for only one tab. - */ -- (void)tabDragStopped:(id)sender -{ - if (![[NSUserDefaults standardUserDefaults] boolForKey:SPAlwaysShowWindowTabBar]) { - [tabBar setHideForSingleTab:YES]; - } -} - -#pragma mark - -#pragma mark Window delegate methods - -/** - * Determine whether the window is permitted to close. - * Go through the tabs in this window, and ask the database connection view - * in each one if it can be closed, returning YES only if all can be closed. - */ -- (BOOL)windowShouldClose:(id)sender -{ - - // Iterate through all tabs if more than one tab is opened only otherwise - // [... parentTabShouldClose] will be called twice [see self closeTab:(id)sender] - if([[tabView tabViewItems] count] > 1) - for (NSTabViewItem *eachItem in [tabView tabViewItems]) { - SPDatabaseDocument *eachDocument = [eachItem identifier]; - if (![eachDocument parentTabShouldClose]) return NO; - } - - // Remove global session data if the last window of a session will be closed - if([[NSApp delegate] sessionURL] && [[[NSApp delegate] orderedDatabaseConnectionWindows] count] == 1) { - [[NSApp delegate] setSessionURL:nil]; - [[NSApp delegate] setSpfSessionDocData:nil]; - } - - return YES; -} - -/** - * When the window does close, close all tabs. - */ -- (void)windowWillClose:(NSNotification *)notification - -{ - for (NSTabViewItem *eachItem in [tabView tabViewItems]) { - [tabView removeTabViewItem:eachItem]; - } - [self autorelease]; -} - -/** - * When the window becomes key, inform the selected tab and - * update menu items. - */ -- (void)windowDidBecomeKey:(NSNotification *)notification -{ - [selectedTableDocument tabDidBecomeKey]; - - // Update the "Close window" item - [closeWindowMenuItem setTitle:NSLocalizedString(@"Close Window", @"Close Window menu item")]; - [closeWindowMenuItem setKeyEquivalentModifierMask:(NSCommandKeyMask | NSShiftKeyMask)]; - - // Ensure the "Close tab" item is enabled and has the standard shortcut - [closeTabMenuItem setEnabled:YES]; - [closeTabMenuItem setKeyEquivalent:@"w"]; - [closeTabMenuItem setKeyEquivalentModifierMask:NSCommandKeyMask]; -} - -/** - * When the window resigns key, update menu items. - */ -- (void)windowDidResignKey:(NSNotification *)notification -{ - // Disable the "Close tab" menu item - [closeTabMenuItem setEnabled:NO]; - [closeTabMenuItem setKeyEquivalent:@""]; - - // Update the "Close window" item to show only "Close" - [closeWindowMenuItem setTitle:NSLocalizedString(@"Close", @"Close menu item")]; - [closeWindowMenuItem setKeyEquivalentModifierMask:NSCommandKeyMask]; -} - -/** - * If the window is resized, notify all the tabs. - */ -- (void)windowDidResize:(NSNotification *)notification -{ - for (NSTabViewItem *eachItem in [tabView tabViewItems]) { - SPDatabaseDocument *eachDocument = [eachItem identifier]; - [eachDocument tabDidResize]; - } -} - -/** - * If the window is entering fullscreen, update the front tab's titlebar status view visibility. - */ -- (void)windowWillEnterFullScreen:(NSNotification *)notification -{ - [selectedTableDocument updateTitlebarStatusVisibilityForcingHide:YES]; -} - -/** - * If the window exits fullscreen, update the front tab's titlebar status view visibility. - */ -- (void)windowDidExitFullScreen:(NSNotification *)notification -{ - [selectedTableDocument updateTitlebarStatusVisibilityForcingHide:NO]; -} - -#pragma mark - #pragma mark First responder forwarding to active tab /** diff --git a/Source/SPWindowControllerDelegate.h b/Source/SPWindowControllerDelegate.h new file mode 100644 index 00000000..5e940948 --- /dev/null +++ b/Source/SPWindowControllerDelegate.h @@ -0,0 +1,37 @@ +// +// $Id$ +// +// SPWindowControllerDelegate.h +// Sequel Pro +// +// Created by Stuart Connolly (stuconnolly.com) on April 9, 2012 +// Copyright (c) 2012 Stuart Connolly. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// More info at <http://code.google.com/p/sequel-pro/> + +#import "SPWindowController.h" + +@interface SPWindowController (SPWindowControllerDelegate) + +@end diff --git a/Source/SPWindowControllerDelegate.m b/Source/SPWindowControllerDelegate.m new file mode 100644 index 00000000..220930de --- /dev/null +++ b/Source/SPWindowControllerDelegate.m @@ -0,0 +1,432 @@ +// +// $Id$ +// +// SPWindowControllerDelegate.h +// Sequel Pro +// +// Created by Stuart Connolly (stuconnolly.com) on April 9, 2012 +// Copyright (c) 2012 Stuart Connolly. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// More info at <http://code.google.com/p/sequel-pro/> + +#import "SPWindowControllerDelegate.h" +#import "PSMTabDragAssistant.h" +#import "SPDatabaseDocument.h" +#import "SPDatabaseViewController.h" +#import "SPAppController.h" + +#import <PSMTabBar/PSMTabBarControl.h> +#import <PSMTabBar/PSMTabStyle.h> + +@interface SPWindowController (SPDeclaredAPI) + +- (void)_updateProgressIndicatorForItem:(NSTabViewItem *)theItem; + +@end + +@implementation SPWindowController (SPWindowControllerDelegate) + +#pragma mark - +#pragma mark Window delegate methods + +/** + * Determine whether the window is permitted to close. + * Go through the tabs in this window, and ask the database connection view + * in each one if it can be closed, returning YES only if all can be closed. + */ +- (BOOL)windowShouldClose:(id)sender +{ + // Iterate through all tabs if more than one tab is opened only otherwise + // [... parentTabShouldClose] will be called twice [see self closeTab:(id)sender] + if ([[tabView tabViewItems] count] > 1) { + for (NSTabViewItem *eachItem in [tabView tabViewItems]) + { + SPDatabaseDocument *eachDocument = [eachItem identifier]; + + if (![eachDocument parentTabShouldClose]) return NO; + } + } + + // Remove global session data if the last window of a session will be closed + if ([[NSApp delegate] sessionURL] && [[[NSApp delegate] orderedDatabaseConnectionWindows] count] == 1) { + [[NSApp delegate] setSessionURL:nil]; + [[NSApp delegate] setSpfSessionDocData:nil]; + } + + return YES; +} + +/** + * When the window does close, close all tabs. + */ +- (void)windowWillClose:(NSNotification *)notification +{ + for (NSTabViewItem *eachItem in [tabView tabViewItems]) + { + [tabView removeTabViewItem:eachItem]; + } + + [self autorelease]; +} + +/** + * When the window becomes key, inform the selected tab and + * update menu items. + */ +- (void)windowDidBecomeKey:(NSNotification *)notification +{ + [selectedTableDocument tabDidBecomeKey]; + + // Update the "Close window" item + [closeWindowMenuItem setTitle:NSLocalizedString(@"Close Window", @"Close Window menu item")]; + [closeWindowMenuItem setKeyEquivalentModifierMask:(NSCommandKeyMask | NSShiftKeyMask)]; + + // Ensure the "Close tab" item is enabled and has the standard shortcut + [closeTabMenuItem setEnabled:YES]; + [closeTabMenuItem setKeyEquivalent:@"w"]; + [closeTabMenuItem setKeyEquivalentModifierMask:NSCommandKeyMask]; +} + +/** + * When the window resigns key, update menu items. + */ +- (void)windowDidResignKey:(NSNotification *)notification +{ + // Disable the "Close tab" menu item + [closeTabMenuItem setEnabled:NO]; + [closeTabMenuItem setKeyEquivalent:@""]; + + // Update the "Close window" item to show only "Close" + [closeWindowMenuItem setTitle:NSLocalizedString(@"Close", @"Close menu item")]; + [closeWindowMenuItem setKeyEquivalentModifierMask:NSCommandKeyMask]; +} + +/** + * If the window is resized, notify all the tabs. + */ +- (void)windowDidResize:(NSNotification *)notification +{ + for (NSTabViewItem *eachItem in [tabView tabViewItems]) + { + SPDatabaseDocument *eachDocument = [eachItem identifier]; + + [eachDocument tabDidResize]; + } +} + +/** + * If the window is entering fullscreen, update the front tab's titlebar status view visibility. + */ +- (void)windowWillEnterFullScreen:(NSNotification *)notification +{ + [selectedTableDocument updateTitlebarStatusVisibilityForcingHide:YES]; +} + +/** + * If the window exits fullscreen, update the front tab's titlebar status view visibility. + */ +- (void)windowDidExitFullScreen:(NSNotification *)notification +{ + [selectedTableDocument updateTitlebarStatusVisibilityForcingHide:NO]; +} + +#pragma mark - +#pragma mark Tab view delegate methods + +/** + * Called when a tab item is about to be selected. + */ +- (void)tabView:(NSTabView *)tabView willSelectTabViewItem:(NSTabViewItem *)tabViewItem +{ + [selectedTableDocument willResignActiveTabInWindow]; +} + +/** + * Called when a tab item was selected. + */ +- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem +{ + if ([[PSMTabDragAssistant sharedDragAssistant] isDragging]) return; + + selectedTableDocument = [tabViewItem identifier]; + [selectedTableDocument didBecomeActiveTabInWindow]; + + if ([[self window] isKeyWindow]) [selectedTableDocument tabDidBecomeKey]; + + [self updateAllTabTitles:self]; +} + +/** + * Called to determine whether a tab view item can be closed + */ +- (BOOL)tabView:(NSTabView *)aTabView shouldCloseTabViewItem:(NSTabViewItem *)tabViewItem +{ + SPDatabaseDocument *theDocument = [tabViewItem identifier]; + + if (![theDocument parentTabShouldClose]) return NO; + + return YES; +} + +/** + * Called after a tab view item is closed. + */ +- (void)tabView:(NSTabView *)aTabView didCloseTabViewItem:(NSTabViewItem *)tabViewItem +{ + SPDatabaseDocument *theDocument = [tabViewItem identifier]; + + [theDocument removeObserver:self forKeyPath:@"isProcessing"]; + [theDocument parentTabDidClose]; +} + +/** + * Called to allow dragging of tab view items + */ +- (BOOL)tabView:(NSTabView *)aTabView shouldDragTabViewItem:(NSTabViewItem *)tabViewItem fromTabBar:(PSMTabBarControl *)tabBarControl +{ + return YES; +} + +/** + * Called when a tab finishes a drop. This is called with the new tabView. + */ +- (void)tabView:(NSTabView*)aTabView didDropTabViewItem:(NSTabViewItem *)tabViewItem inTabBar:(PSMTabBarControl *)tabBarControl +{ + SPDatabaseDocument *draggedDocument = [tabViewItem identifier]; + + // Grab a reference to the old window + NSWindow *draggedFromWindow = [draggedDocument parentWindow]; + + // If the window changed, perform additional processing. + if (draggedFromWindow != [tabBarControl window]) { + + // Update the old window, ensuring the toolbar is cleared to prevent issues with toolbars in multiple windows + [draggedFromWindow setToolbar:nil]; + [[draggedFromWindow windowController] updateSelectedTableDocument]; + + // Update the item's document's window and controller + [draggedDocument willResignActiveTabInWindow]; + [draggedDocument setParentWindowController:[[tabBarControl window] windowController]]; + [draggedDocument setParentWindow:[tabBarControl window]]; + [draggedDocument didBecomeActiveTabInWindow]; + + // Update window controller's active tab, and update the document's isProcessing observation + [[[tabBarControl window] windowController] updateSelectedTableDocument]; + [draggedDocument removeObserver:[draggedFromWindow windowController] forKeyPath:@"isProcessing"]; + [[[tabBarControl window] windowController] _updateProgressIndicatorForItem:tabViewItem]; + } + + // Check the window and move it to front if it's key (eg for new window creation) + if ([[tabBarControl window] isKeyWindow]) [[tabBarControl window] orderFront:self]; +} + +/** + * Respond to dragging events entering the tab in the tab bar. + * Allows custom behaviours - for example, if dragging text, switch to the custom + * query view. + */ +- (void)draggingEvent:(id <NSDraggingInfo>)dragEvent enteredTabBar:(PSMTabBarControl *)tabBarControl tabView:(NSTabViewItem *)tabViewItem +{ + SPDatabaseDocument *theDocument = [tabViewItem identifier]; + + if (![theDocument isCustomQuerySelected] && [[[dragEvent draggingPasteboard] types] indexOfObject:NSStringPboardType] != NSNotFound) + { + [theDocument viewQuery:self]; + } +} + +/** + * Show tooltip for a tab view item. + */ +- (NSString *)tabView:(NSTabView *)aTabView toolTipForTabViewItem:(NSTabViewItem *)tabViewItem +{ + NSInteger tabIndex = [tabView indexOfTabViewItem:tabViewItem]; + + if ([[tabBar cells] count] < (NSUInteger)tabIndex) return @""; + + PSMTabBarCell *theCell = [[tabBar cells] objectAtIndex:tabIndex]; + + // If cell is selected show tooltip if truncated only + if ([theCell tabState] & PSMTab_SelectedMask) { + + CGFloat cellWidth = [theCell width]; + CGFloat titleWidth = [theCell stringSize].width; + CGFloat closeButtonWidth = 0; + + if ([theCell hasCloseButton]) + closeButtonWidth = [theCell closeButtonRectForFrame:[theCell frame]].size.width; + + if (titleWidth > cellWidth - closeButtonWidth) { + return [theCell title]; + } + + return @""; + } + // if cell is not selected show full title plus MySQL version is enabled as tooltip + else { + if ([[tabViewItem identifier] respondsToSelector:@selector(tabTitleForTooltip)]) { + return [[tabViewItem identifier] tabTitleForTooltip]; + } + + return @""; + } +} + +/** + * Allow window closing of the last tab item. + */ +- (void)tabView:(NSTabView *)aTabView closeWindowForLastTabViewItem:(NSTabViewItem *)tabViewItem +{ + [[aTabView window] close]; +} + +/** + * When dragging a tab off a tab bar, add a shadow to the drag window. + */ +- (void)tabViewDragWindowCreated:(NSWindow *)dragWindow +{ + [dragWindow setHasShadow:YES]; +} + +/** + * Allow dragging and dropping of tabs to any position, including out of a tab bar + * to create a new window. + */ +- (BOOL)tabView:(NSTabView*)aTabView shouldDropTabViewItem:(NSTabViewItem *)tabViewItem inTabBar:(PSMTabBarControl *)tabBarControl +{ + return YES; +} + +/** + * When a tab is dragged off a tab bar, create a new window containing a new + * (empty) tab bar to hold it. + */ +- (PSMTabBarControl *)tabView:(NSTabView *)aTabView newTabBarForDraggedTabViewItem:(NSTabViewItem *)tabViewItem atPoint:(NSPoint)point +{ + // Create the new window controller, with no tabs + SPWindowController *newWindowController = [[SPWindowController alloc] initWithWindowNibName:@"MainWindow"]; + NSWindow *newWindow = [newWindowController window]; + + CGFloat toolbarHeight = 0; + + if ([[[self window] toolbar] isVisible]) { + NSRect innerFrame = [NSWindow contentRectForFrameRect:[[self window] frame] styleMask:[[self window] styleMask]]; + toolbarHeight = innerFrame.size.height - [[[self window] contentView] frame].size.height; + } + + // Adjust the positioning as appropriate + point.y += toolbarHeight; + + if ([[NSUserDefaults standardUserDefaults] boolForKey:SPAlwaysShowWindowTabBar]) point.y += kPSMTabBarControlHeight; + + // Set the new window position and size + NSRect targetWindowFrame = [[self window] frame]; + targetWindowFrame.size.height -= toolbarHeight; + [newWindow setFrame:targetWindowFrame display:NO]; + [newWindow setFrameTopLeftPoint:point]; + + // Set the window controller as the window's delegate + [newWindow setDelegate:newWindowController]; + + // Set window title + [newWindow setTitle:[[[tabViewItem identifier] parentWindow] title]]; + + // Return the window's tab bar + return [newWindowController valueForKey:@"tabBar"]; +} + +/** + * When dragging a tab off the tab bar, return an image so that a + * drag placeholder can be displayed. + */ +- (NSImage *)tabView:(NSTabView *)aTabView imageForTabViewItem:(NSTabViewItem *)tabViewItem offset:(NSSize *)offset styleMask:(unsigned int *)styleMask +{ + NSImage *viewImage = [[NSImage alloc] init]; + + // Capture an image of the entire window + CGImageRef windowImage = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, (unsigned int)[[self window] windowNumber], kCGWindowImageBoundsIgnoreFraming); + NSBitmapImageRep *viewRep = [[NSBitmapImageRep alloc] initWithCGImage:windowImage]; + [viewImage addRepresentation:viewRep]; + + // Calculate the titlebar+toolbar height + CGFloat contentViewOffsetY = [[self window] frame].size.height - [[[self window] contentView] frame].size.height; + offset->height = contentViewOffsetY + [tabBar frame].size.height; + + // Draw over the tab bar area + [viewImage lockFocus]; + [[NSColor windowBackgroundColor] set]; + NSRectFill([tabBar frame]); + [viewImage unlockFocus]; + + // Draw the tab bar background in the tab bar area + [viewImage lockFocus]; + NSRect tabFrame = [tabBar frame]; + [[NSColor windowBackgroundColor] set]; + NSRectFill(tabFrame); + + // Draw the background flipped, which is actually the right way up + NSAffineTransform *transform = [NSAffineTransform transform]; + [transform translateXBy:0.0f yBy:[[[self window] contentView] frame].size.height]; + [transform scaleXBy:1.0f yBy:-1.0f]; + [transform concat]; + [(id <PSMTabStyle>)[[aTabView delegate] style] drawBackgroundInRect:tabFrame]; + [viewImage unlockFocus]; + + return [viewImage autorelease]; +} + +/** + * Displays the current tab's context menu. + */ +- (NSMenu *)tabView:(NSTabView *)aTabView menuForTabViewItem:(NSTabViewItem *)tabViewItem +{ + NSMenu *menu = [[NSMenu alloc] init]; + + [menu addItemWithTitle:NSLocalizedString(@"Close Tab", @"close tab context menu item") action:@selector(closeTab:) keyEquivalent:@""]; + [menu insertItem:[NSMenuItem separatorItem] atIndex:1]; + [menu addItemWithTitle:NSLocalizedString(@"Open in New Tab", @"open connection in new tab context menu item") action:@selector(openDatabaseInNewTab:) keyEquivalent:@""]; + + return [menu autorelease]; +} + +/** + * When tab drags start, show all the tab bars. This allows adding tabs to windows + * containing only one tab - where the bar is normally hidden. + */ +- (void)tabDragStarted:(id)sender +{ + [tabBar setHideForSingleTab:NO]; +} + +/** + * When tab drags stop, set tab bars to automatically hide again for only one tab. + */ +- (void)tabDragStopped:(id)sender +{ + if (![[NSUserDefaults standardUserDefaults] boolForKey:SPAlwaysShowWindowTabBar]) { + [tabBar setHideForSingleTab:YES]; + } +} + +@end |