diff options
author | rowanbeentje <rowan@beent.je> | 2010-05-23 21:44:59 +0000 |
---|---|---|
committer | rowanbeentje <rowan@beent.je> | 2010-05-23 21:44:59 +0000 |
commit | c661b409eaa0e29d9e012b79e7a66574a554817a (patch) | |
tree | 49b310ded9a226a66aa53444c9ba112824854f68 /Source/TableDocument.m | |
parent | b66006f3755c6a57dfc60d4133bc4dc4da0fef56 (diff) | |
download | sequelpro-c661b409eaa0e29d9e012b79e7a66574a554817a.tar.gz sequelpro-c661b409eaa0e29d9e012b79e7a66574a554817a.tar.bz2 sequelpro-c661b409eaa0e29d9e012b79e7a66574a554817a.zip |
Initial implementation of tabs:
- Addition of PSMTabBar framework
- Rework away from a document-based TableDocument
- Support tabs throughout the application
- Add menu items for creating tabs, and add support for dragging tabs to different windows
Diffstat (limited to 'Source/TableDocument.m')
-rw-r--r-- | Source/TableDocument.m | 610 |
1 files changed, 370 insertions, 240 deletions
diff --git a/Source/TableDocument.m b/Source/TableDocument.m index 385e9781..5d3209e5 100644 --- a/Source/TableDocument.m +++ b/Source/TableDocument.m @@ -73,6 +73,9 @@ @implementation TableDocument +@synthesize parentWindowController; +@synthesize parentTabViewItem; + - (id)init { @@ -92,6 +95,9 @@ mySQLVersion = nil; allDatabases = nil; allSystemDatabases = nil; + mainToolbar = nil; + parentWindow = nil; + isProcessing = NO; printWebView = [[WebView alloc] init]; [printWebView setFrameLoadDelegate:self]; @@ -99,10 +105,12 @@ prefs = [NSUserDefaults standardUserDefaults]; queryEditorInitString = nil; + spfFileURL = nil; spfSession = nil; spfPreferences = [[NSMutableDictionary alloc] init]; spfDocData = [[NSMutableDictionary alloc] init]; + titleAccessoryView = nil; taskProgressWindow = nil; taskDisplayIsIndeterminate = YES; taskDisplayLastValue = 0; @@ -117,6 +125,15 @@ keyChainID = nil; statusValues = nil; printThread = nil; + nibObjectsToRelease = [[NSMutableArray alloc] init]; + + // As this object is not an NSWindowController subclass, top-level objects in loaded nibs aren't + // automatically released. Keep track of the top-level objects for release on dealloc. + NSArray *dbViewTopLevelObjects = nil; + NSNib *nibLoader = [[NSNib alloc] initWithNibNamed:@"DBView" bundle:[NSBundle mainBundle]]; + [nibLoader instantiateNibWithOwner:self topLevelObjects:&dbViewTopLevelObjects]; + [nibLoader release]; + [nibObjectsToRelease addObjectsFromArray:dbViewTopLevelObjects]; } return self; @@ -127,48 +144,6 @@ if (_mainNibLoaded) return; _mainNibLoaded = YES; - // The first window should use autosaving; subsequent windows should cascade - BOOL usedAutosave = [tableWindow setFrameAutosaveName:[self windowNibName]]; - if (!usedAutosave) { - [tableWindow setFrameUsingName:[self windowNibName]]; - NSArray *documents = [[NSDocumentController sharedDocumentController] documents]; - NSRect previousFrame = [[[documents objectAtIndex:(([documents count] > 1)?[documents count]-2:[documents count]-1)] valueForKey:@"tableWindow"] frame]; - NSPoint topLeftPoint = previousFrame.origin; - topLeftPoint.y += previousFrame.size.height; - [tableWindow setFrameTopLeftPoint:[tableWindow cascadeTopLeftFromPoint:topLeftPoint]]; - - // Try to check if new frame fits into the screen - NSRect screenFrame = [[NSScreen mainScreen] frame]; - NSScreen* candidate; - for(candidate in [NSScreen screens]) - if(NSMinX([candidate frame]) < topLeftPoint.x && NSMinX([candidate frame]) > NSMinX(screenFrame)) - screenFrame = [candidate visibleFrame]; - - previousFrame = [tableWindow frame]; - - // Determine if move/resize is required - if(previousFrame.origin.x - screenFrame.origin.x + previousFrame.size.width >= screenFrame.size.width - || previousFrame.origin.y - screenFrame.origin.y + previousFrame.size.height >= screenFrame.size.height) - { - - // First try to move the window back onto the screen if it will fit - if (previousFrame.size.width <= screenFrame.size.width && previousFrame.size.height <= screenFrame.size.height) { - previousFrame.origin.x -= (previousFrame.origin.x + previousFrame.size.width) - (screenFrame.origin.x + screenFrame.size.width); - previousFrame.origin.y -= (previousFrame.origin.y + previousFrame.size.height) - (screenFrame.origin.y + screenFrame.size.height); - [tableWindow setFrame:previousFrame display:YES]; - - // Otherwise, resize and de-cascade a little - } else { - previousFrame.size.width -= 50; - previousFrame.size.height -= 50; - previousFrame.origin.y += 50; - if(previousFrame.size.width >= [tableWindow minSize].width && previousFrame.size.height >= [tableWindow minSize].height) - [tableWindow setFrame:previousFrame display:YES]; - } - } - - } - // Set up the toolbar [self setupToolbar]; @@ -200,23 +175,21 @@ // Register a second observer for when the logging preference changes so we can tell the current connection about it [prefs addObserver:self forKeyPath:SPConsoleEnableLogging options:NSKeyValueObservingOptionNew context:NULL]; + // Register for notifications + //register for notifications + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willPerformQuery:) + name:@"SMySQLQueryWillBePerformed" object:self]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hasPerformedQuery:) + name:@"SMySQLQueryHasBeenPerformed" object:self]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) + name:@"NSApplicationWillTerminateNotification" object:nil]; + // Find the Database -> Database Encoding menu (it's not in our nib, so we can't use interface builder) - selectEncodingMenu = [[[[[NSApp mainMenu] itemWithTag:1] submenu] itemWithTag:1] submenu]; + selectEncodingMenu = [[[[[NSApp mainMenu] itemWithTag:SPMainMenuDatabase] submenu] itemWithTag:1] submenu]; // Hide the tabs in the tab view (we only show them to allow switching tabs in interface builder) [tableTabView setTabViewType:NSNoTabsNoBorder]; - // Add the icon accessory view to the title bar - NSView *windowFrame = [[tableWindow contentView] superview]; - NSRect av = [titleAccessoryView frame]; - NSRect initialAccessoryViewFrame = NSMakeRect( - [windowFrame frame].size.width - av.size.width - 30, - [windowFrame frame].size.height - av.size.height, - av.size.width, - av.size.height); - [titleAccessoryView setFrame:initialAccessoryViewFrame]; - [windowFrame addSubview:titleAccessoryView]; - // Bind the background color of the create syntax text view to the users preference [createTableSyntaxTextView setAllowsDocumentBackgroundColorChange:YES]; @@ -229,25 +202,35 @@ withKeyPath:@"values.CustomQueryEditorBackgroundColor" options:bindingOptions]; - // Load additional nibs - if (![NSBundle loadNibNamed:@"ConnectionErrorDialog" owner:self]) { + // Load additional nibs, keeping track of the top-level objects to allow correct release + NSArray *connectionDialogTopLevelObjects = nil; + NSNib *nibLoader = [[NSNib alloc] initWithNibNamed:@"ConnectionErrorDialog" bundle:[NSBundle mainBundle]]; + if (![nibLoader instantiateNibWithOwner:self topLevelObjects:&connectionDialogTopLevelObjects]) { NSLog(@"Connection error dialog could not be loaded; connection failure handling will not function correctly."); + } else { + [nibObjectsToRelease addObjectsFromArray:connectionDialogTopLevelObjects]; } - if (![NSBundle loadNibNamed:@"ProgressIndicatorLayer" owner:self]) { + [nibLoader release]; + NSArray *progressIndicatorLayerTopLevelObjects = nil; + nibLoader = [[NSNib alloc] initWithNibNamed:@"ProgressIndicatorLayer" bundle:[NSBundle mainBundle]]; + if (![nibLoader instantiateNibWithOwner:self topLevelObjects:&progressIndicatorLayerTopLevelObjects]) { NSLog(@"Progress indicator layer could not be loaded; progress display will not function correctly."); + } else { + [nibObjectsToRelease addObjectsFromArray:progressIndicatorLayerTopLevelObjects]; } + [nibLoader release]; - // Set up the progress indicator child window and layer - add to main window, change indicator color and size + // Retain the icon accessory view to allow it to be added and removed from windows + [titleAccessoryView retain]; + + // Set up the progress indicator child window and layer - change indicator color and size [taskProgressIndicator setForeColor:[NSColor whiteColor]]; taskProgressWindow = [[NSWindow alloc] initWithContentRect:[taskProgressLayer bounds] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; + [taskProgressWindow setReleasedWhenClosed:NO]; [taskProgressWindow setOpaque:NO]; [taskProgressWindow setBackgroundColor:[NSColor clearColor]]; [taskProgressWindow setAlphaValue:0.0]; - [taskProgressWindow orderFront:self]; - [tableWindow addChildWindow:taskProgressWindow ordered:NSWindowAbove]; - [taskProgressWindow setReleasedWhenClosed:YES]; [taskProgressWindow setContentView:taskProgressLayer]; - [self centerTaskWindow]; } /** @@ -266,8 +249,7 @@ NSInteger connectionType = -1; - // Inform about the data source in the window title bar - [tableWindow setTitle:[self displaySPName]]; + [self updateWindowTitle:self]; // Clean fields [connectionController setName:@""]; @@ -305,7 +287,7 @@ [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; if (spf) [spf release]; - [self close]; + [self closeAndDisconnect]; return; } @@ -313,7 +295,7 @@ if(![[spf objectForKey:@"format"] isEqualToString:@"connection"]) { NSLog(@"SPF file format is not 'connection'."); [spf release]; - [self close]; + [self closeAndDisconnect]; return; } @@ -327,7 +309,7 @@ [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; [spf release]; - [self close]; + [self closeAndDisconnect]; return; } @@ -339,7 +321,7 @@ [inputTextWindowSecureTextField setStringValue:@""]; [inputTextWindowSecureTextField selectText:nil]; - [NSApp beginSheet:inputTextWindow modalForWindow:tableWindow modalDelegate:self didEndSelector:nil contextInfo:nil]; + [NSApp beginSheet:inputTextWindow modalForWindow:parentWindow modalDelegate:self didEndSelector:nil contextInfo:nil]; // wait for encryption password NSModalSession session = [NSApp beginModalSessionForWindow:inputTextWindow]; @@ -366,7 +348,7 @@ if(passwordSheetReturnCode) encryptpw = [inputTextWindowSecureTextField stringValue]; else { - [self close]; + [self closeAndDisconnect]; [spf release]; return; } @@ -392,7 +374,7 @@ [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; - [self close]; + [self closeAndDisconnect]; [spf release]; return; } @@ -407,7 +389,7 @@ [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; - [self close]; + [self closeAndDisconnect]; [spf release]; return; } @@ -422,7 +404,7 @@ [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; - [self close]; + [self closeAndDisconnect]; [spf release]; return; } @@ -545,7 +527,7 @@ // Restore toolbar setting if([spfSession objectForKey:@"isToolbarVisible"]) - [[tableWindow toolbar] setVisible:[[spfSession objectForKey:@"isToolbarVisible"] boolValue]]; + [mainToolbar setVisible:[[spfSession objectForKey:@"isToolbarVisible"] boolValue]]; // TODO up to now it doesn't work if([spfSession objectForKey:@"contentSelectedIndexSet"]) { @@ -592,7 +574,7 @@ [[tablesListInstance valueForKeyPath:@"tablesListView"] scrollRowToVisible:[tables indexOfObject:[spfSession objectForKey:@"selectedTable"]]]; - [tableWindow setTitle:[self displaySPName]]; + [self updateWindowTitle:self]; // dealloc spfSession data [spfSession release]; @@ -650,7 +632,7 @@ [self setFileURL:[[SPQueryController sharedQueryController] registerDocumentWithFileURL:[self fileURL] andContextInfo:spfPreferences]]; // ...but hide the icon while the document is temporary - if ([self isUntitled]) [[tableWindow standardWindowButton:NSWindowDocumentIconButton] setImage:nil]; + if ([self isUntitled]) [[parentWindow standardWindowButton:NSWindowDocumentIconButton] setImage:nil]; // Set the connection encoding NSString *encodingName = [prefs objectForKey:SPDefaultEncoding]; @@ -672,6 +654,7 @@ // Update the database list [self setDatabases:self]; + [chooseDatabaseButton setEnabled:!_isWorkingLevel]; // For each of the main controllers, assign the current connection [tablesListInstance setConnection:mySQLConnection]; @@ -690,12 +673,12 @@ // Set the cutom query editor's MySQL version [customQueryInstance setMySQLversion:mySQLVersion]; - [tableWindow setTitle:[self displaySPName]]; + [self updateWindowTitle:self]; // Connected Growl notification [[SPGrowlController sharedGrowlController] notifyWithTitle:@"Connected" - description:[NSString stringWithFormat:NSLocalizedString(@"Connected to %@",@"description for connected growl notification"), [tableWindow title]] - window:tableWindow + description:[NSString stringWithFormat:NSLocalizedString(@"Connected to %@",@"description for connected growl notification"), [parentWindow title]] + document:self notificationName:@"Connected"]; // Init Custom Query editor with the stored queries in a spf file if given. @@ -722,9 +705,9 @@ // Set focus to table list filter field if visible // otherwise set focus to Table List view if ( [[tablesListInstance tables] count] > 20 ) - [tableWindow makeFirstResponder:listFilterField]; + [parentWindow makeFirstResponder:listFilterField]; else - [tableWindow makeFirstResponder:[tablesListInstance valueForKeyPath:@"tablesListView"]]; + [parentWindow makeFirstResponder:[tablesListInstance valueForKeyPath:@"tablesListView"]]; if(spfSession != nil) { @@ -764,25 +747,6 @@ return mySQLConnection; } - -/** - * Set whether the connection controller should automatically start - * connecting; called by maincontroller, but only for first window. - */ -- (void)setShouldAutomaticallyConnect:(BOOL)shouldAutomaticallyConnect -{ - _shouldOpenConnectionAutomatically = shouldAutomaticallyConnect; -} - -/** - * Allow the connection controller to determine whether connection should - * be automatically triggered. - */ -- (BOOL)shouldAutomaticallyConnect -{ - return _shouldOpenConnectionAutomatically; -} - /** * Sets this connection's Keychain ID. */ @@ -925,7 +889,7 @@ [databaseNameField setStringValue:@""]; [NSApp beginSheet:databaseSheet - modalForWindow:tableWindow + modalForWindow:parentWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"addDatabase"]; @@ -943,7 +907,7 @@ [copyDatabaseMessageField setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Duplicate database '%@' to:", @"duplicate database message"), selectedDatabase]]; [NSApp beginSheet:databaseCopySheet - modalForWindow:tableWindow + modalForWindow:parentWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"copyDatabase"]; @@ -960,7 +924,7 @@ [renameDatabaseMessageField setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Rename database '%@' to:", @"rename database message"), selectedDatabase]]; [NSApp beginSheet:databaseRenameSheet - modalForWindow:tableWindow + modalForWindow:parentWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"renameDatabase"]; @@ -991,7 +955,7 @@ [alert setAlertStyle:NSCriticalAlertStyle]; - [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"removeDatabase"]; + [alert beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"removeDatabase"]; } /** @@ -1008,7 +972,7 @@ [prefs addObserver:serverVariablesController forKeyPath:SPDisplayTableViewVerticalGridlines options:NSKeyValueObservingOptionNew context:NULL]; } - [serverVariablesController displayServerVariablesSheetAttachedToWindow:tableWindow]; + [serverVariablesController displayServerVariablesSheetAttachedToWindow:parentWindow]; } /** @@ -1108,7 +1072,7 @@ { // error := first object is the title , second the message, only one button OK SPBeginAlertSheet([error objectAtIndex:0], NSLocalizedString(@"OK", @"OK button"), - nil, nil, tableWindow, self, nil, nil, + nil, nil, parentWindow, self, nil, nil, [error objectAtIndex:1]); } @@ -1135,12 +1099,12 @@ if (selectedDatabase) [selectedDatabase release], selectedDatabase = nil; selectedDatabase = [[NSString alloc] initWithString:dbName]; [chooseDatabaseButton selectItemWithTitle:selectedDatabase]; - [tableWindow setTitle:[self displaySPName]]; + [self updateWindowTitle:self]; } } else { if (selectedDatabase) [selectedDatabase release], selectedDatabase = nil; [chooseDatabaseButton selectItemAtIndex:0]; - [tableWindow setTitle:[self displaySPName]]; + [self updateWindowTitle:self]; } } @@ -1284,6 +1248,7 @@ databaseListIsSelectable = NO; [[NSNotificationCenter defaultCenter] postNotificationName:SPDocumentTaskStartNotification object:self]; [mainToolbar validateVisibleItems]; + [chooseDatabaseButton setEnabled:NO]; // Schedule appearance of the task window in the near future taskDrawTimer = [[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(showTaskProgressWindow:) userInfo:nil repeats:NO] retain]; @@ -1399,6 +1364,7 @@ databaseListIsSelectable = YES; [[NSNotificationCenter defaultCenter] postNotificationName:SPDocumentTaskEndNotification object:self]; [mainToolbar validateVisibleItems]; + [chooseDatabaseButton setEnabled:_isConnected]; } } @@ -1476,7 +1442,7 @@ - (void) centerTaskWindow { NSPoint newBottomLeftPoint; - NSRect mainWindowRect = [tableWindow frame]; + NSRect mainWindowRect = [parentWindow frame]; NSRect taskWindowRect = [taskProgressWindow frame]; newBottomLeftPoint.x = round(mainWindowRect.origin.x + mainWindowRect.size.width/2 - taskWindowRect.size.width/2); @@ -1737,7 +1703,7 @@ defaultButton:NSLocalizedString(@"OK", @"OK button") alternateButton:nil otherButton:nil informativeTextWithFormat:NSLocalizedString(@"The creation syntax could not be retrieved due to a permissions error.\n\nPlease check your user permissions with an administrator.", @"Create syntax permission denied detail")] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; return; } @@ -1753,7 +1719,7 @@ // Show variables sheet [NSApp beginSheet:createTableSyntaxWindow - modalForWindow:tableWindow + modalForWindow:parentWindow modalDelegate:self didEndSelector:nil contextInfo:nil]; @@ -1806,7 +1772,7 @@ defaultButton:NSLocalizedString(@"OK", @"OK button") alternateButton:nil otherButton:nil informativeTextWithFormat:NSLocalizedString(@"The creation syntax could not be retrieved due to a permissions error.\n\nPlease check your user permissions with an administrator.", @"Create syntax permission denied detail")] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; return; } @@ -1822,7 +1788,7 @@ // Table syntax copied Growl notification [[SPGrowlController sharedGrowlController] notifyWithTitle:@"Syntax Copied" description:[NSString stringWithFormat:NSLocalizedString(@"Syntax for %@ table copied",@"description for table syntax copied growl notification"), [self table]] - window:tableWindow + document:self notificationName:@"Syntax Copied"]; } @@ -1851,7 +1817,7 @@ alternateButton:nil otherButton:nil informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to check the %@.\n\nMySQL said:%@",@"an error occurred while trying to check the %@.\n\nMySQL said:%@"), what, [mySQLConnection getLastErrorMessage]]] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; @@ -1886,7 +1852,7 @@ alternateButton:nil otherButton:nil informativeTextWithFormat:message] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; @@ -1898,7 +1864,7 @@ [alert setInformativeText:message]; [alert setMessageText:NSLocalizedString(@"Error while checking selected items", @"error while checking selected items message")]; [alert setAccessoryView:statusTableAccessoryView]; - [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"statusError"]; + [alert beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"statusError"]; } } @@ -1927,7 +1893,7 @@ alternateButton:nil otherButton:nil informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"An error occurred while analyzing the %@.\n\nMySQL said:%@",@"an error occurred while analyzing the %@.\n\nMySQL said:%@"), what, [mySQLConnection getLastErrorMessage]]] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; @@ -1962,7 +1928,7 @@ alternateButton:nil otherButton:nil informativeTextWithFormat:message] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; @@ -1974,7 +1940,7 @@ [alert setInformativeText:message]; [alert setMessageText:NSLocalizedString(@"Error while analyzing selected items", @"error while analyzing selected items message")]; [alert setAccessoryView:statusTableAccessoryView]; - [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"statusError"]; + [alert beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"statusError"]; } } @@ -2003,7 +1969,7 @@ alternateButton:nil otherButton:nil informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"An error occurred while optimzing the %@.\n\nMySQL said:%@",@"an error occurred while trying to optimze the %@.\n\nMySQL said:%@"), what, [mySQLConnection getLastErrorMessage]]] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; @@ -2038,7 +2004,7 @@ alternateButton:nil otherButton:nil informativeTextWithFormat:message] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; @@ -2050,7 +2016,7 @@ [alert setInformativeText:message]; [alert setMessageText:NSLocalizedString(@"Error while optimizing selected items", @"error while optimizing selected items message")]; [alert setAccessoryView:statusTableAccessoryView]; - [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"statusError"]; + [alert beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"statusError"]; } } @@ -2078,7 +2044,7 @@ alternateButton:nil otherButton:nil informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"An error occurred while repairing the %@.\n\nMySQL said:%@",@"an error occurred while trying to repair the %@.\n\nMySQL said:%@"), what, [mySQLConnection getLastErrorMessage]]] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; @@ -2113,7 +2079,7 @@ alternateButton:nil otherButton:nil informativeTextWithFormat:message] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; @@ -2125,7 +2091,7 @@ [alert setInformativeText:message]; [alert setMessageText:NSLocalizedString(@"Error while repairing selected items", @"error while repairing selected items message")]; [alert setAccessoryView:statusTableAccessoryView]; - [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"statusError"]; + [alert beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"statusError"]; } } @@ -2153,7 +2119,7 @@ alternateButton:nil otherButton:nil informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"An error occurred while flushing the %@.\n\nMySQL said:%@",@"an error occurred while trying to flush the %@.\n\nMySQL said:%@"), what, [mySQLConnection getLastErrorMessage]]] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; @@ -2188,7 +2154,7 @@ alternateButton:nil otherButton:nil informativeTextWithFormat:message] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; @@ -2200,7 +2166,7 @@ [alert setInformativeText:message]; [alert setMessageText:NSLocalizedString(@"Error while flushing selected items", @"error while flushing selected items message")]; [alert setAccessoryView:statusTableAccessoryView]; - [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"statusError"]; + [alert beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"statusError"]; } } @@ -2227,7 +2193,7 @@ alternateButton:nil otherButton:nil informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"An error occurred while performing the checksum on %@.\n\nMySQL said:%@",@"an error occurred while performing the checksum on the %@.\n\nMySQL said:%@"), what, [mySQLConnection getLastErrorMessage]]] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; @@ -2244,7 +2210,7 @@ alternateButton:nil otherButton:nil informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"Table checksum: %@",@"table checksum: %@"), message]] - beginSheetModalForWindow:tableWindow + beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:NULL contextInfo:NULL]; @@ -2256,7 +2222,7 @@ [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"Checksums of %@",@"Checksums of %@ message"), what]]; [alert setMessageText:NSLocalizedString(@"Table checksum",@"table checksum message")]; [alert setAccessoryView:statusTableAccessoryView]; - [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"statusError"]; + [alert beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"statusError"]; } } @@ -2293,7 +2259,7 @@ // Table syntax copied Growl notification [[SPGrowlController sharedGrowlController] notifyWithTitle:@"Syntax Copied" description:[NSString stringWithFormat:NSLocalizedString(@"Syntax for %@ table copied", @"description for table syntax copied growl notification"), [self table]] - window:tableWindow + document:self notificationName:@"Syntax Copied"]; } } @@ -2365,13 +2331,13 @@ [alert setAlertStyle:NSCriticalAlertStyle]; - [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"cannotremovefield"]; + [alert beginSheetModalForWindow:parentWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"cannotremovefield"]; return; } [NSApp beginSheet:[userManagerInstance window] - modalForWindow:tableWindow + modalForWindow:parentWindow modalDelegate:userManagerInstance didEndSelector:@selector(userManagerSheetDidEnd:returnCode:contextInfo:) contextInfo:nil]; @@ -2382,7 +2348,7 @@ */ - (void)doPerformQueryService:(NSString *)query { - [tableWindow makeKeyAndOrderFront:self]; + [parentWindow makeKeyAndOrderFront:self]; [tablesListInstance doPerformQueryService:query]; } @@ -2404,26 +2370,29 @@ if (![mySQLConnection queryErrored]) { //flushed privileges without errors - SPBeginAlertSheet(NSLocalizedString(@"Flushed Privileges", @"title of panel when successfully flushed privs"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, NSLocalizedString(@"Successfully flushed privileges.", @"message of panel when successfully flushed privs")); + SPBeginAlertSheet(NSLocalizedString(@"Flushed Privileges", @"title of panel when successfully flushed privs"), NSLocalizedString(@"OK", @"OK button"), nil, nil, parentWindow, self, nil, nil, NSLocalizedString(@"Successfully flushed privileges.", @"message of panel when successfully flushed privs")); } else { //error while flushing privileges - SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"Couldn't flush privileges.\nMySQL said: %@", @"message of panel when flushing privs failed"), + SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, parentWindow, self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"Couldn't flush privileges.\nMySQL said: %@", @"message of panel when flushing privs failed"), [mySQLConnection getLastErrorMessage]]); } } - (IBAction)openCurrentConnectionInNewWindow:(id)sender { - TableDocument *newTableDocument; + [[NSApp delegate] newWindow:self]; + TableDocument *newTableDocument = [[NSApp delegate] frontDocument]; + [newTableDocument initWithConnectionFile:[[self fileURL] path]]; +} - // Manually open a new document, setting SPAppController as sender to trigger autoconnection - if (newTableDocument = [[NSDocumentController sharedDocumentController] makeUntitledDocumentOfType:@"Sequel Pro connection" error:nil]) { - [newTableDocument setShouldAutomaticallyConnect:NO]; - [[NSDocumentController sharedDocumentController] addDocument:newTableDocument]; - [newTableDocument makeWindowControllers]; - [newTableDocument showWindows]; - [newTableDocument initWithConnectionFile:[[self fileURL] path]]; - } +/** + * Ask the connection controller to initiate connection, if it hasn't + * already. Used to support automatic connections on window open, + */ +- (void)connect +{ + if (mySQLVersion) return; + [connectionController initiateConnection:self]; } - (void)closeConnection @@ -2433,8 +2402,8 @@ // Disconnected Growl notification [[SPGrowlController sharedGrowlController] notifyWithTitle:@"Disconnected" - description:[NSString stringWithFormat:NSLocalizedString(@"Disconnected from %@",@"description for disconnected growl notification"), [tableWindow title]] - window:tableWindow + description:[NSString stringWithFormat:NSLocalizedString(@"Disconnected from %@",@"description for disconnected growl notification"), [parentTabViewItem label]] + document:self notificationName:@"Disconnected"]; } @@ -2453,7 +2422,7 @@ */ - (BOOL)isUntitled { - return ([[self fileURL] isFileURL]) ? NO : YES; + return ([self fileURL] && [[self fileURL] isFileURL]) ? NO : YES; } /** @@ -2463,7 +2432,7 @@ */ - (BOOL)couldCommitCurrentViewActions { - [tableWindow endEditingFor:nil]; + [parentWindow endEditingFor:nil]; switch ([tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]]) { // Table structure view @@ -2484,6 +2453,16 @@ #pragma mark - #pragma mark Accessor methods + +/** + * Returns the parent view, which in its turn contains the database view for this + * connection. + */ +- (NSView *)parentView +{ + return parentView; +} + /** * Returns the host */ @@ -2604,6 +2583,7 @@ */ - (void)willPerformQuery:(NSNotification *)notification { + isProcessing = YES; [queryProgressBar startAnimation:self]; } @@ -2612,6 +2592,7 @@ */ - (void)hasPerformedQuery:(NSNotification *)notification { + isProcessing = NO; [queryProgressBar stopAnimation:self]; } @@ -2686,7 +2667,8 @@ return; } - // Load accessory nib each time + // Load accessory nib each time. + // Note that the top-level objects aren't released automatically, but are released when the panel ends. if(![NSBundle loadNibNamed:@"SaveSPFAccessory" owner:self]) { NSLog(@"SaveSPFAccessory accessory dialog could not be loaded."); return; @@ -2734,7 +2716,7 @@ [panel beginSheetForDirectory:nil file:filename - modalForWindow:tableWindow + modalForWindow:parentWindow modalDelegate:self didEndSelector:@selector(saveConnectionPanelDidEnd:returnCode:contextInfo:) contextInfo:contextInfo]; @@ -2763,7 +2745,6 @@ - (void)saveConnectionPanelDidEnd:(NSSavePanel *)panel returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { - if ( returnCode ) { NSString *fileName = [panel filename]; @@ -2799,8 +2780,11 @@ [self saveDocumentWithFilePath:fileName inBackground:NO onlyPreferences:NO]; + // Manually loaded nibs don't have their top-level objects released automatically - do that here. + [saveConnectionAccessory release]; + if(contextInfo == @"saveSPFfileAndClose") - [self close]; + [self closeAndDisconnect]; } } } @@ -3010,7 +2994,7 @@ } [session setObject:aString forKey:@"view"]; - [session setObject:[NSNumber numberWithBool:[[tableWindow toolbar] isVisible]] forKey:@"isToolbarVisible"]; + [session setObject:[NSNumber numberWithBool:[[parentWindow toolbar] isVisible]] forKey:@"isToolbarVisible"]; [session setObject:[self connectionEncoding] forKey:@"connectionEncoding"]; [session setObject:[NSNumber numberWithBool:[tableContentInstance sortColumnIsAscending]] forKey:@"contentSortColIsAsc"]; @@ -3090,7 +3074,7 @@ [self setFileURL:[NSURL fileURLWithPath:fileName]]; [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:[NSURL fileURLWithPath:fileName]]; - [tableWindow setTitle:[self displaySPName]]; + [self updateWindowTitle:self]; // Store doc data permanently [spfDocData removeAllObjects]; @@ -3161,7 +3145,7 @@ } if (!_isConnected || _isWorkingLevel) { - return ([menuItem action] == @selector(newDocument:) || [menuItem action] == @selector(terminate:)); + return ([menuItem action] == @selector(newWindow:) || [menuItem action] == @selector(terminate:) || [menuItem action] == @selector(closeTab:) || [menuItem action] == @selector(newTab:)); } if ([menuItem action] == @selector(openCurrentConnectionInNewWindow:)) @@ -3291,7 +3275,8 @@ return NO; } - return [super validateMenuItem:menuItem]; + // Default to YES for unhandled menus + return YES; } - (IBAction)viewStructure:(id)sender @@ -3339,7 +3324,7 @@ [spHistoryControllerInstance updateHistoryEntries]; // Set the focus on the text field - [tableWindow makeFirstResponder:customQueryTextView]; + [parentWindow makeFirstResponder:customQueryTextView]; [prefs setInteger:SPQueryEditorViewMode forKey:SPLastViewMode]; } @@ -3363,7 +3348,7 @@ [extendedTableInfoInstance loadTable:[self table]]; } - [tableWindow makeFirstResponder:[extendedTableInfoInstance valueForKeyPath:@"tableCreateSyntaxTextView"]]; + [parentWindow makeFirstResponder:[extendedTableInfoInstance valueForKeyPath:@"tableCreateSyntaxTextView"]]; [prefs setInteger:SPTableInfoViewMode forKey:SPLastViewMode]; } @@ -3448,6 +3433,72 @@ #pragma mark Titlebar Methods /** + * Update the window title. + */ +- (void) updateWindowTitle:(id)sender +{ + NSMutableString *tabTitle; + NSMutableString *windowTitle; + TableDocument *frontTableDocument = [parentWindowController selectedTableDocument]; + + // Determine name details + NSString *pathName = @""; + if ([[[self fileURL] path] length] && ![self isUntitled]) { + pathName = [NSString stringWithFormat:@"%@ — ", [[[self fileURL] path] lastPathComponent]]; + } + if (!_isConnected) { + windowTitle = [NSString stringWithFormat:@"%@%@", pathName, @"Sequel Pro"]; + tabTitle = windowTitle; + } else { + windowTitle = [NSMutableString string]; + tabTitle = [NSMutableString string]; + + // Add the path to the window title + [windowTitle appendString:pathName]; + + // Add the MySQL version to the window title if enabled in prefs + if ([prefs boolForKey:SPDisplayServerVersionInWindowTitle]) [windowTitle appendFormat:@"(MySQL %@) ", mySQLVersion]; + + // Add the name to the window + [windowTitle appendString:[self name]]; + + // Also add to the frontmost tab, and other tabs if the host is different, not connected, or no db is selected + if (frontTableDocument == self || [[frontTableDocument name] isNotEqualTo:[self name]] || ![frontTableDocument getConnection] || ![self database]) { + [tabTitle appendString:[self name]]; + } + + // If a database is selected, add to the window - and other tabs if host is the same but table is set + if ([self database]) { + [windowTitle appendFormat:@"/%@", [self database]]; + if (frontTableDocument == self + || [[frontTableDocument name] isNotEqualTo:[self name]] + || ![[self table] length]) + { + if ([tabTitle length]) [tabTitle appendString:@"/"]; + [tabTitle appendString:[self database]]; + } + } + + // Add the table name if one is selected + if ([[self table] length]) { + [windowTitle appendFormat:@"/%@", [self table]]; + if ([tabTitle length]) [tabTitle appendString:@"/"]; + [tabTitle appendString:[self table]]; + } + } + + // Set the titles + [parentTabViewItem setLabel:tabTitle]; + if ([parentWindowController selectedTableDocument] == self) { + [parentWindow setTitle:windowTitle]; + } + + // If the sender wasn't the window controller, update other tabs in this window + // for shared pathname updates + if ([sender class] != [SPWindowController class]) [parentWindowController updateAllTabTitles:self]; +} + +/** * Set the connection status icon in the titlebar */ - (void)setStatusIconToImageWithName:(NSString *)imageName @@ -3482,7 +3533,7 @@ - (void)setupToolbar { // create a new toolbar instance, and attach it to our document window - mainToolbar = [[[NSToolbar alloc] initWithIdentifier:@"TableWindowToolbar"] autorelease]; + mainToolbar = [[NSToolbar alloc] initWithIdentifier:@"TableWindowToolbar"]; // set up toolbar properties [mainToolbar setAllowsUserCustomization:YES]; @@ -3492,9 +3543,6 @@ // set ourself as the delegate [mainToolbar setDelegate:self]; - // attach the toolbar to the document window - [tableWindow setToolbar:mainToolbar]; - // update the toolbar item size [self updateChooseDatabaseToolbarItemWidth]; @@ -3525,6 +3573,7 @@ [toolbarItem setMaxSize:NSMakeSize(200,32)]; [chooseDatabaseButton setTarget:self]; [chooseDatabaseButton setAction:@selector(chooseDatabase:)]; + [chooseDatabaseButton setEnabled:(_isConnected && !_isWorkingLevel)]; if (willBeInsertedIntoToolbar) { chooseDatabaseToolbarItem = toolbarItem; @@ -3698,7 +3747,7 @@ /** * Validates the toolbar items */ -- (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem; +- (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem { if (!_isConnected || _isWorkingLevel) return NO; @@ -3732,40 +3781,50 @@ } #pragma mark - -#pragma mark NSDocument methods +#pragma mark Tab methods /** - * Returns the name of the nib file + * Make this document's window frontmost in the application, + * and ensure this tab is selected. */ -- (NSString *)windowNibName +- (void)makeKeyDocument { - return @"DBView"; + [[[self parentWindow] onMainThread] makeKeyAndOrderFront:self]; + [[[[self parentTabViewItem] onMainThread] tabView] selectTabViewItemWithIdentifier:self]; } /** - * Code that need to be executed once the windowController has loaded the document's window - * sets upt the interface (small fonts). + * Invoked to determine whether the parent tab is allowed to close */ -- (void)windowControllerDidLoadNib:(NSWindowController *)aController +- (BOOL)parentTabShouldClose { - [aController setShouldCascadeWindows:YES]; - [super windowControllerDidLoadNib:aController]; - //register for notifications - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willPerformQuery:) - name:@"SMySQLQueryWillBePerformed" object:self]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hasPerformedQuery:) - name:@"SMySQLQueryHasBeenPerformed" object:self]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) - name:@"NSApplicationWillTerminateNotification" object:nil]; -} + // If no connection is available, always return YES. Covers initial setup and disconnections. + if(!_isConnected) return YES; -// NSWindow delegate methods + // If tasks are active, return NO to allow tasks to complete + if (_isWorkingLevel) return NO; + + // If the table list considers itself to be working, return NO. This catches open alerts, and + // edits in progress in various views. + if ( ![tablesListInstance selectionShouldChangeInTableView:nil] ) return NO; + + // Auto-save spf file based connection and return whether the save was successful + if([self fileURL] && [[[self fileURL] path] length] && ![self isUntitled]) { + BOOL isSaved = [self saveDocumentWithFilePath:nil inBackground:YES onlyPreferences:YES]; + if(isSaved) + [[SPQueryController sharedQueryController] removeRegisteredDocumentWithFileURL:[self fileURL]]; + return isSaved; + } + + // Return YES by default + return YES; +} /** - * Invoked when the document window is about to close + * Invoked when the parent tab is about to close */ -- (void)windowWillClose:(NSNotification *)aNotification +- (void)parentTabDidClose { // Cancel autocompletion trigger @@ -3787,37 +3846,64 @@ if ([[[SPQueryController sharedQueryController] window] isVisible]) [self toggleConsole:self]; [createTableSyntaxWindow orderOut:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self]; + [self setParentWindow:nil]; } /** - * Invoked when the document window should close + * Invoked when the parent tab is currently the active tab in the + * window, but is being switched away from, to allow cleaning up + * details in the window. */ -- (BOOL)windowShouldClose:(id)sender +- (void)willResignActiveTabInWindow { - // If no connection is available, always return YES. Covers initial setup and disconnections. - if(!_isConnected) return YES; + // Remove the icon accessory view from the title bar + [titleAccessoryView removeFromSuperview]; - // If tasks are active, return NO to allow tasks to complete - if (_isWorkingLevel) return NO; + // Remove the task progress window + [parentWindow removeChildWindow:taskProgressWindow]; + [taskProgressWindow orderOut:self]; +} - // If the table list considers itself to be working, return NO. This catches open alerts, and - // edits in progress in various views. - if ( ![tablesListInstance selectionShouldChangeInTableView:nil] ) return NO; +/** + * Invoked when the parent tab became the active tab in the window, + * to allow the window to reflect the contents of this view. + */ +- (void)didBecomeActiveTabInWindow +{ - // Auto-save spf file based connection and return whether the save was successful - if([self fileURL] && [[[self fileURL] path] length] && ![self isUntitled]) { - BOOL isSaved = [self saveDocumentWithFilePath:nil inBackground:YES onlyPreferences:YES]; - if(isSaved) - [[SPQueryController sharedQueryController] removeRegisteredDocumentWithFileURL:[self fileURL]]; - return isSaved; - } + // Update the toolbar + [parentWindow setToolbar:mainToolbar]; - // Return YES by default - return YES; + // Update the window's title and represented document + [self updateWindowTitle:self]; + if (spfFileURL && [spfFileURL isFileURL]) + [parentWindow setRepresentedURL:spfFileURL]; + else + [parentWindow setRepresentedURL:nil]; + + // Add the icon accessory view to the title bar + NSView *windowFrame = [[parentWindow contentView] superview]; + NSRect av = [titleAccessoryView frame]; + NSRect initialAccessoryViewFrame = NSMakeRect( + [windowFrame frame].size.width - av.size.width - 30, + [windowFrame frame].size.height - av.size.height, + av.size.width, + av.size.height); + [titleAccessoryView setFrame:initialAccessoryViewFrame]; + [windowFrame addSubview:titleAccessoryView]; + + // Add the progress window to this window + [self centerTaskWindow]; + [taskProgressWindow orderFront:self]; + [parentWindow addChildWindow:taskProgressWindow ordered:NSWindowAbove]; } -- (void)windowDidBecomeKey:(NSNotification *)notification +/** + * Invoked when the parent tab became the key tab in the application; + * the selected tab in the frontmost window. + */ +- (void)tabDidBecomeKey { // Synchronize Navigator with current active document if Navigator runs in syncMode if([[SPNavigatorController sharedNavigatorController] syncMode] && [self connectionID] && ![[self connectionID] isEqualToString:@"_"]) { @@ -3838,19 +3924,67 @@ /** * Invoked when the document window is resized */ -- (void)windowDidResize:(NSNotification *)notification +- (void)tabDidResize { - // If the task interface is visible, re-center the task child window - if (_isWorkingLevel) [self centerTaskWindow]; + // If the task interface is visible, and this tab is frontmost, re-center the task child window + if (_isWorkingLevel && [parentWindowController selectedTableDocument] == self) [self centerTaskWindow]; } /** - * Invoked when the user command-clicks on the window title to see the document path + * Support the tab's progress spinner */ -- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu +- (BOOL)isProcessing +{ + return (isProcessing || (_isWorkingLevel > 0)); +} +- (void)setIsProcessing:(BOOL)value { - return ![self isUntitled]; + isProcessing = value; +} + +/** + * Set the parent window + */ +- (void)setParentWindow:(NSWindow *)aWindow +{ + parentWindow = aWindow; + SPSSHTunnel *currentTunnel = [connectionController valueForKeyPath:@"sshTunnel"]; + if (currentTunnel) [currentTunnel setParentWindow:parentWindow]; +} + +/** + * Return the parent window + */ +- (NSWindow *)parentWindow +{ + return parentWindow; +} + +#pragma mark - +#pragma mark NSDocument compatibility + +/** + * Set the NSURL for a .spf file for this connection instance. + */ +- (void)setFileURL:(NSURL *)theURL +{ + if (spfFileURL) [spfFileURL release], spfFileURL = nil; + spfFileURL = [theURL retain]; + if ([parentWindowController selectedTableDocument] == self) { + if (spfFileURL && [spfFileURL isFileURL]) + [parentWindow setRepresentedURL:spfFileURL]; + else + [parentWindow setRepresentedURL:nil]; + } +} + +/** + * Retrieve the NSURL for the .spf file for this connection instance (if any) + */ +- (NSURL *)fileURL +{ + return [[spfFileURL copy] autorelease]; } /* @@ -3883,27 +4017,13 @@ /** * The window title for this document. */ -- (NSString *)displaySPName +- (NSString *)displayName { if (!_isConnected) { return [NSString stringWithFormat:@"%@%@", ([[[self fileURL] path] length] && ![self isUntitled]) ? [NSString stringWithFormat:@"%@ — ",[[[self fileURL] path] lastPathComponent]] : @"", @"Sequel Pro"]; } - - return [NSString stringWithFormat:@"%@%@ %@%@%@", - ([[[self fileURL] path] length] && ![self isUntitled]) ? [NSString stringWithFormat:@"%@ — ",[self displayName]] : @"", - ([prefs boolForKey:SPDisplayServerVersionInWindowTitle]) ? [NSString stringWithFormat:@"(MySQL %@)", mySQLVersion] : @"", - [self name], - ([self database]?[NSString stringWithFormat:@"/%@",[self database]]:@""), - ([[self table] length]?[NSString stringWithFormat:@"/%@",[self table]]:@"")]; -} -/** - * The window title for this document. - */ -- (NSString *)displayName -{ - if(!_isConnected) return [self displaySPName]; return [[[self fileURL] path] lastPathComponent]; } @@ -3916,7 +4036,10 @@ - (void)connectionControllerInitiatingConnection:(id)controller { // Update the window title to indicate that we are try to establish a connection - [tableWindow setTitle:NSLocalizedString(@"Connecting…", @"window title string indicating that sp is connecting")]; + [parentTabViewItem setLabel:NSLocalizedString(@"Connecting…", @"window title string indicating that sp is connecting")]; + if ([parentWindowController selectedTableDocument] == self) { + [parentWindow setTitle:NSLocalizedString(@"Connecting…", @"window title string indicating that sp is connecting")]; + } } /** @@ -3925,7 +4048,7 @@ - (void)connectionControllerConnectAttemptFailed:(id)controller { // Reset the window title - [tableWindow setTitle:[self displaySPName]]; + [self updateWindowTitle:self]; } #pragma mark - @@ -4105,6 +4228,7 @@ */ - (void)dealloc { +NSLog(@"is dealloc'd"); // Unregister observers [prefs removeObserver:self forKeyPath:SPDisplayTableViewVerticalGridlines]; @@ -4123,6 +4247,9 @@ [[NSNotificationCenter defaultCenter] removeObserver:self]; [NSObject cancelPreviousPerformRequestsWithTarget:self]; + for (id retainedObject in nibObjectsToRelease) [retainedObject release]; + [nibObjectsToRelease release]; + [_encoding release]; [allDatabases release]; [allSystemDatabases release]; @@ -4138,10 +4265,14 @@ if (taskDrawTimer) [taskDrawTimer release]; if (taskFadeAnimator) [taskFadeAnimator release]; if (queryEditorInitString) [queryEditorInitString release]; + if (spfFileURL) [spfFileURL release]; if (spfPreferences) [spfPreferences release]; if (spfSession) [spfSession release]; if (spfDocData) [spfDocData release]; if (keyChainID) [keyChainID release]; + if (mainToolbar) [mainToolbar release]; + if (titleAccessoryView) [titleAccessoryView release]; + if (taskProgressWindow) [taskProgressWindow release]; [super dealloc]; } @@ -4152,12 +4283,12 @@ - (void)_copyDatabase { if ([[databaseCopyNameField stringValue] isEqualToString:@""]) { - SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, NSLocalizedString(@"Database must have a name.", @"message of panel when no db name is given")); + SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, parentWindow, self, nil, nil, NSLocalizedString(@"Database must have a name.", @"message of panel when no db name is given")); return; } SPDatabaseCopy *dbActionCopy = [[SPDatabaseCopy alloc] init]; [dbActionCopy setConnection: [self getConnection]]; - [dbActionCopy setMessageWindow: tableWindow]; + [dbActionCopy setMessageWindow: parentWindow]; BOOL copyWithContent = [copyDatabaseDataButton state] == NSOnState; @@ -4172,12 +4303,12 @@ - (void)_renameDatabase { if ([[databaseRenameNameField stringValue] isEqualToString:@""]) { - SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, NSLocalizedString(@"Database must have a name.", @"message of panel when no db name is given")); + SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, parentWindow, self, nil, nil, NSLocalizedString(@"Database must have a name.", @"message of panel when no db name is given")); return; } SPDatabaseRename *dbActionRename = [[SPDatabaseRename alloc] init]; [dbActionRename setConnection: [self getConnection]]; - [dbActionRename setMessageWindow: tableWindow]; + [dbActionRename setMessageWindow: parentWindow]; if ([dbActionRename renameDatabaseFrom: [self database] to: [databaseRenameNameField stringValue]]) { @@ -4195,7 +4326,7 @@ // This check is not necessary anymore as the add database button is now only enabled if the name field // has a length greater than zero. We'll leave it in just in case. if ([[databaseNameField stringValue] isEqualToString:@""]) { - SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, NSLocalizedString(@"Database must have a name.", @"message of panel when no db name is given")); + SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, parentWindow, self, nil, nil, NSLocalizedString(@"Database must have a name.", @"message of panel when no db name is given")); return; } @@ -4211,14 +4342,14 @@ if ([mySQLConnection queryErrored]) { // An error occurred - SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"Couldn't create database.\nMySQL said: %@", @"message of panel when creation of db failed"), [mySQLConnection getLastErrorMessage]]); + SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, parentWindow, self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"Couldn't create database.\nMySQL said: %@", @"message of panel when creation of db failed"), [mySQLConnection getLastErrorMessage]]); return; } // Error while selecting the new database (is this even possible?) if (![mySQLConnection selectDB:[databaseNameField stringValue]] ) { - SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"Unable to connect to database %@.\nBe sure that you have the necessary privileges.", @"message of panel when connection to db failed after selecting from popupbutton"), [databaseNameField stringValue]]); + SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, parentWindow, self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"Unable to connect to database %@.\nBe sure that you have the necessary privileges.", @"message of panel when connection to db failed after selecting from popupbutton"), [databaseNameField stringValue]]); [self setDatabases:self]; @@ -4235,7 +4366,7 @@ [tablesListInstance setConnection:mySQLConnection]; [tableDumpInstance setConnection:mySQLConnection]; - [tableWindow setTitle:[self displaySPName]]; + [self updateWindowTitle:self]; } /** @@ -4274,8 +4405,7 @@ [tablesListInstance setConnection:mySQLConnection]; [tableDumpInstance setConnection:mySQLConnection]; - [tableWindow setTitle:[self displaySPName]]; - + [self updateWindowTitle:self]; } /** @@ -4301,7 +4431,7 @@ || ![mySQLConnection selectDB:targetDatabaseName]) { if ( [mySQLConnection isConnected] ) { - SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"Unable to connect to database %@.\nBe sure that you have the necessary privileges.", @"message of panel when connection to db failed after selecting from popupbutton"), targetDatabaseName]); + SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, parentWindow, self, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"Unable to connect to database %@.\nBe sure that you have the necessary privileges.", @"message of panel when connection to db failed after selecting from popupbutton"), targetDatabaseName]); // Update the database list [self setDatabases:self]; @@ -4328,7 +4458,7 @@ [tableDumpInstance setConnection:mySQLConnection]; // Update the window title - [[tableWindow onMainThread] setTitle:[self displaySPName]]; + [[self onMainThread] updateWindowTitle:self]; // Add a history entry if (!historyStateChanging) { @@ -4339,9 +4469,9 @@ // Set focus to table list filter field if visible // otherwise set focus to Table List view if ( [[tablesListInstance tables] count] > 20 ) - [[tableWindow onMainThread] makeFirstResponder:listFilterField]; + [[parentWindow onMainThread] makeFirstResponder:listFilterField]; else - [[tableWindow onMainThread] makeFirstResponder:[tablesListInstance valueForKeyPath:@"tablesListView"]]; + [[parentWindow onMainThread] makeFirstResponder:[tablesListInstance valueForKeyPath:@"tablesListView"]]; } // If a the table has changed, update the selection |