aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2010-05-23 21:44:59 +0000
committerrowanbeentje <rowan@beent.je>2010-05-23 21:44:59 +0000
commitc661b409eaa0e29d9e012b79e7a66574a554817a (patch)
tree49b310ded9a226a66aa53444c9ba112824854f68 /Source
parentb66006f3755c6a57dfc60d4133bc4dc4da0fef56 (diff)
downloadsequelpro-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')
-rw-r--r--Source/CMTextView.h6
-rw-r--r--Source/CMTextView.m84
-rw-r--r--Source/CustomQuery.h1
-rw-r--r--Source/CustomQuery.m36
-rw-r--r--Source/SPAppController.h9
-rw-r--r--Source/SPAppController.m244
-rw-r--r--Source/SPConnectionController.h6
-rw-r--r--Source/SPConnectionController.m66
-rw-r--r--Source/SPConnectionDelegate.m36
-rw-r--r--Source/SPConstants.h13
-rw-r--r--Source/SPContentFilterManager.h3
-rw-r--r--Source/SPContentFilterManager.m7
-rw-r--r--Source/SPDocumentController.h32
-rw-r--r--Source/SPDocumentController.m36
-rw-r--r--Source/SPExportController.h5
-rw-r--r--Source/SPExportController.m18
-rw-r--r--Source/SPFieldEditorController.h2
-rw-r--r--Source/SPFieldEditorController.m4
-rw-r--r--Source/SPGrowlController.h6
-rw-r--r--Source/SPGrowlController.m41
-rw-r--r--Source/SPHistoryController.m1
-rw-r--r--Source/SPNavigatorController.m15
-rw-r--r--Source/SPPrintController.m8
-rw-r--r--Source/SPProcessListController.m4
-rw-r--r--Source/SPQueryController.m4
-rw-r--r--Source/SPQueryFavoriteManager.h3
-rw-r--r--Source/SPQueryFavoriteManager.m7
-rw-r--r--Source/SPSSHTunnel.m11
-rw-r--r--Source/SPServerVariablesController.m2
-rw-r--r--Source/SPTableData.m7
-rw-r--r--Source/SPTableRelations.h1
-rw-r--r--Source/SPTableRelations.m4
-rw-r--r--Source/SPTableTriggers.h1
-rw-r--r--Source/SPTableTriggers.m4
-rw-r--r--Source/SPTableView.m12
-rw-r--r--Source/SPWindowController.h46
-rw-r--r--Source/SPWindowController.m372
-rw-r--r--Source/TableContent.h2
-rw-r--r--Source/TableContent.m68
-rw-r--r--Source/TableDocument.h38
-rw-r--r--Source/TableDocument.m610
-rw-r--r--Source/TableDump.h4
-rw-r--r--Source/TableDump.m92
-rw-r--r--Source/TableSource.h1
-rw-r--r--Source/TableSource.m28
-rw-r--r--Source/TablesList.h1
-rw-r--r--Source/TablesList.m56
47 files changed, 1433 insertions, 624 deletions
diff --git a/Source/CMTextView.h b/Source/CMTextView.h
index 7c09d827..51f2153d 100644
--- a/Source/CMTextView.h
+++ b/Source/CMTextView.h
@@ -31,10 +31,14 @@
#define SP_TEXT_SIZE_TRIGGER_FOR_PARTLY_PARSING 10000
-@class SPNarrowDownCompletion;
+@class SPNarrowDownCompletion, TableDocument, TablesList, CustomQuery;
@interface CMTextView : NSTextView
{
+ IBOutlet TableDocument *tableDocumentInstance;
+ IBOutlet TablesList *tablesListInstance;
+ IBOutlet CustomQuery *customQueryInstance;
+
BOOL autoindentEnabled;
BOOL autopairEnabled;
BOOL autoindentIgnoresEnter;
diff --git a/Source/CMTextView.m b/Source/CMTextView.m
index 94e5a2bb..55c759a0 100644
--- a/Source/CMTextView.m
+++ b/Source/CMTextView.m
@@ -306,8 +306,8 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
// Add structural db/table/field data to completions list or fallback to gathering TablesList data
NSString* connectionID;
- if([[[self window] delegate] respondsToSelector:@selector(connectionID)])
- connectionID = [[[self window] delegate] connectionID];
+ if(tableDocumentInstance)
+ connectionID = [tableDocumentInstance connectionID];
else
connectionID = @"_";
@@ -325,14 +325,14 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
NSString *currentDb = nil;
NSString *currentTable = nil;
- if ([[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"selectedDatabase"] != nil)
- currentDb = [NSString stringWithFormat:@"%@%@%@", connectionID, SPUniqueSchemaDelimiter, [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"selectedDatabase"]];
- if ([[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"tableName"] != nil)
- currentTable = [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"tableName"];
+ if (tablesListInstance && [tablesListInstance selectedDatabase])
+ currentDb = [NSString stringWithFormat:@"%@%@%@", connectionID, SPUniqueSchemaDelimiter, [tablesListInstance selectedDatabase]];
+ if (tablesListInstance && [tablesListInstance tableName])
+ currentTable = [tablesListInstance tableName];
// Put current selected db at the top
- if(aTableName == nil && aDbName == nil && [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"selectedDatabase"]) {
- currentDb = [NSString stringWithFormat:@"%@%@%@", connectionID, SPUniqueSchemaDelimiter, [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"selectedDatabase"]];
+ if(aTableName == nil && aDbName == nil && [tablesListInstance selectedDatabase]) {
+ currentDb = [NSString stringWithFormat:@"%@%@%@", connectionID, SPUniqueSchemaDelimiter, [tablesListInstance selectedDatabase]];
[sortedDbs removeObject:currentDb];
[sortedDbs insertObject:currentDb atIndex:0];
}
@@ -481,34 +481,34 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
// [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"fetching table data…", @"fetching table data for completion in progress message"), @"path", @"", @"noCompletion", nil]];
// Add all database names to completions list
- for (id obj in [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"allDatabaseNames"])
+ for (id obj in [tablesListInstance allDatabaseNames])
[possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:obj, @"display", @"database-small", @"image", @"", @"isRef", nil]];
// Add all system database names to completions list
- for (id obj in [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"allSystemDatabaseNames"])
+ for (id obj in [tablesListInstance allSystemDatabaseNames])
[possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:obj, @"display", @"database-small", @"image", @"", @"isRef", nil]];
// Add table names to completions list
- for (id obj in [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"allTableNames"])
+ for (id obj in [tablesListInstance allTableNames])
[possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:obj, @"display", @"table-small-square", @"image", @"", @"isRef", nil]];
// Add view names to completions list
- for (id obj in [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"allViewNames"])
+ for (id obj in [tablesListInstance allViewNames])
[possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:obj, @"display", @"table-view-small-square", @"image", @"", @"isRef", nil]];
// Add field names to completions list for currently selected table
- if ([[[self window] delegate] table] != nil)
- for (id obj in [[[[self window] delegate] valueForKeyPath:@"tableDataInstance"] valueForKey:@"columnNames"])
+ if ([tableDocumentInstance table] != nil)
+ for (id obj in [[tableDocumentInstance valueForKeyPath:@"tableDataInstance"] valueForKey:@"columnNames"])
[possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:obj, @"display", @"field-small-square", @"image", @"", @"isRef", nil]];
// Add proc/func only for MySQL version 5 or higher
if(mySQLmajorVersion > 4) {
// Add all procedures to completions list for currently selected table
- for (id obj in [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"allProcedureNames"])
+ for (id obj in [tablesListInstance allProcedureNames])
[possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:obj, @"display", @"proc-small", @"image", @"", @"isRef", nil]];
// Add all function to completions list for currently selected table
- for (id obj in [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"allFunctionNames"])
+ for (id obj in [tablesListInstance allFunctionNames])
[possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:obj, @"display", @"func-small", @"image", @"", @"isRef", nil]];
}
}
@@ -620,8 +620,8 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
// Parse for leading db.table.field infos
- if([[[self window] delegate] isKindOfClass:[TableDocument class]] && [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"selectedDatabase"])
- currentDb = [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"selectedDatabase"];
+ if(tablesListInstance && [tablesListInstance selectedDatabase])
+ currentDb = [tablesListInstance selectedDatabase];
else
currentDb = @"";
@@ -947,7 +947,7 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
*/
- (IBAction) showMySQLHelpForCurrentWord:(id)sender
{
- [[[[self window] delegate] valueForKeyPath:@"customQueryInstance"] showHelpForCurrentWord:self];
+ [customQueryInstance showHelpForCurrentWord:self];
}
/*
@@ -1000,7 +1000,7 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
- (void) selectCurrentQuery
{
if([self isEditable])
- [[[[self window] delegate] valueForKeyPath:@"customQueryInstance"] selectCurrentQuery];
+ [customQueryInstance selectCurrentQuery];
}
/*
@@ -1191,8 +1191,8 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
NSMutableArray *possibleCompletions = [[[NSMutableArray alloc] initWithCapacity:0] autorelease];
NSString *connectionID;
- if([[[self window] delegate] respondsToSelector:@selector(connectionID)])
- connectionID = [[[self window] delegate] connectionID];
+ if(tableDocumentInstance)
+ connectionID = [tableDocumentInstance connectionID];
else
connectionID = @"_";
@@ -1200,8 +1200,8 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
if([kind isEqualToString:@"$SP_ASLIST_ALL_TABLES"]) {
NSString *currentDb = nil;
- if ([[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"selectedDatabase"] != nil)
- currentDb = [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"selectedDatabase"];
+ if (tablesListInstance && [tablesListInstance selectedDatabase])
+ currentDb = [tablesListInstance selectedDatabase];
NSDictionary *dbs = [NSDictionary dictionaryWithDictionary:[[mySQLConnection getDbStructure] objectForKey:connectionID]];
@@ -1250,10 +1250,10 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
NSString *currentDb = nil;
NSString *currentTable = nil;
- if ([[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"selectedDatabase"] != nil)
- currentDb = [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"selectedDatabase"];
- if ([[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"tableName"] != nil)
- currentTable = [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"tableName"];
+ if (tablesListInstance && [tablesListInstance selectedDatabase])
+ currentDb = [tablesListInstance selectedDatabase];
+ if (tablesListInstance && [tablesListInstance tableName])
+ currentTable = [tablesListInstance tableName];
NSDictionary *dbs = [NSDictionary dictionaryWithDictionary:[[mySQLConnection getDbStructure] objectForKey:connectionID]];
if(currentDb != nil && currentTable != nil && dbs != nil && [dbs count] && [dbs objectForKey:currentDb] && [[dbs objectForKey:currentDb] objectForKey:currentTable]) {
@@ -1291,7 +1291,7 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
}
}
} else {
- arr = [NSArray arrayWithArray:[[[[self window] delegate] valueForKeyPath:@"tableDataInstance"] valueForKey:@"columnNames"]];
+ arr = [NSArray arrayWithArray:[[tableDocumentInstance valueForKeyPath:@"tableDataInstance"] valueForKey:@"columnNames"]];
if(arr == nil) {
arr = [NSArray array];
}
@@ -1586,11 +1586,11 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
if([theHintString isMatchedByRegex:@"(?<!\\\\)\\$SP_"]) {
NSRange r;
NSString *currentTable = nil;
- if ([[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"tableName"] != nil)
- currentTable = [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"tableName"];
+ if (tablesListInstance && [tablesListInstance tableName])
+ currentTable = [tablesListInstance tableName];
NSString *currentDb = nil;
- if ([[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"selectedDatabase"] != nil)
- currentDb = [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"selectedDatabase"];
+ if (tablesListInstance && [tablesListInstance selectedDatabase])
+ currentDb = [tablesListInstance selectedDatabase];
while([theHintString isMatchedByRegex:@"(?<!\\\\)\\$SP_SELECTED_TABLES"]) {
r = [theHintString rangeOfRegex:@"(?<!\\\\)\\$SP_SELECTED_TABLES"];
@@ -2075,8 +2075,8 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
}
// Check if tab trigger is defined; if so insert it, otherwise pass through event
- if(snippetControlCounter < 0 && [[[self window] delegate] fileURL]) {
- NSArray *snippets = [[SPQueryController sharedQueryController] queryFavoritesForFileURL:[[[self window] delegate] fileURL] andTabTrigger:tabTrigger includeGlobals:YES];
+ if(snippetControlCounter < 0 && [tableDocumentInstance fileURL]) {
+ NSArray *snippets = [[SPQueryController sharedQueryController] queryFavoritesForFileURL:[tableDocumentInstance fileURL] andTabTrigger:tabTrigger includeGlobals:YES];
if([snippets count] > 0 && [(NSString*)[(NSDictionary*)[snippets objectAtIndex:0] objectForKey:@"query"] length]) {
[self insertAsSnippet:[(NSDictionary*)[snippets objectAtIndex:0] objectForKey:@"query"] atRange:targetRange];
return;
@@ -2427,14 +2427,14 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
// If selection show Help for it
if([self selectedRange].length)
{
- [[[[self window] delegate] valueForKeyPath:@"customQueryInstance"] performSelector:@selector(showAutoHelpForCurrentWord:) withObject:self afterDelay:0.1];
+ [customQueryInstance performSelector:@selector(showAutoHelpForCurrentWord:) withObject:self afterDelay:0.1];
return;
}
// Otherwise show Help if caret is not inside quotes
NSUInteger cursorPosition = [self selectedRange].location;
if (cursorPosition >= [[self string] length]) cursorPosition--;
if(cursorPosition > -1 && (![[self textStorage] attribute:kQuote atIndex:cursorPosition effectiveRange:nil]||[[self textStorage] attribute:kSQLkeyword atIndex:cursorPosition effectiveRange:nil]))
- [[[[self window] delegate] valueForKeyPath:@"customQueryInstance"] performSelector:@selector(showAutoHelpForCurrentWord:) withObject:self afterDelay:0.1];
+ [customQueryInstance performSelector:@selector(showAutoHelpForCurrentWord:) withObject:self afterDelay:0.1];
}
@@ -2856,7 +2856,7 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
// Hide "Select Active Query" if self is not editable
[[menu itemAtIndex:4] setHidden:![self isEditable]];
- if([[[self window] delegate] valueForKeyPath:@"customQueryInstance"]) {
+ if(customQueryInstance) {
[[menu itemAtIndex:5] setHidden:NO];
[[menu itemAtIndex:6] setHidden:NO];
} else {
@@ -3129,10 +3129,10 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
NSString *currentDb = nil;
NSString *currentTable = nil;
- if ([[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"selectedDatabase"] != nil)
- currentDb = [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"selectedDatabase"];
- if ([[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKey:@"tableName"] != nil)
- currentTable = [[[[self window] delegate] valueForKeyPath:@"tablesListInstance"] valueForKeyPath:@"tableName"];
+ if (tablesListInstance && [tablesListInstance selectedDatabase])
+ currentDb = [tablesListInstance selectedDatabase];
+ if (tablesListInstance && [tablesListInstance tableName])
+ currentTable = [tablesListInstance tableName];
if(!currentDb) currentDb = @"";
if(!currentTable) currentTable = @"";
diff --git a/Source/CustomQuery.h b/Source/CustomQuery.h
index 039f3a29..829083fe 100644
--- a/Source/CustomQuery.h
+++ b/Source/CustomQuery.h
@@ -53,7 +53,6 @@
{
IBOutlet id tableDocumentInstance;
IBOutlet id tablesListInstance;
- IBOutlet id tableWindow;
IBOutlet id queryFavoritesButton;
IBOutlet NSMenuItem *queryFavoritesSearchMenuItem;
diff --git a/Source/CustomQuery.m b/Source/CustomQuery.m
index 7df5615f..6020a255 100644
--- a/Source/CustomQuery.m
+++ b/Source/CustomQuery.m
@@ -172,14 +172,14 @@
// This should never evaluate to true as we are now performing menu validation, meaning the 'Save Query to Favorites' menu item will
// only be enabled if the query text view has at least one character present.
if ([[textView string] isEqualToString:@""]) {
- SPBeginAlertSheet(NSLocalizedString(@"Empty query", @"empty query message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Empty query", @"empty query message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
NSLocalizedString(@"Cannot save an empty query.", @"empty query informative message"));
return;
}
if ([tableDocumentInstance isUntitled]) [saveQueryFavoriteGlobal setState:NSOnState];
[NSApp beginSheet:queryFavoritesSheet
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:@"addSelectionToNewQueryFavorite"];
@@ -190,14 +190,14 @@
// This should never evaluate to true as we are now performing menu validation, meaning the 'Save Query to Favorites' menu item will
// only be enabled if the query text view has at least one character present.
if ([[textView string] isEqualToString:@""]) {
- SPBeginAlertSheet(NSLocalizedString(@"Empty query", @"empty query message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Empty query", @"empty query message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
NSLocalizedString(@"Cannot save an empty query.", @"empty query informative message"));
return;
}
if ([tableDocumentInstance isUntitled]) [saveQueryFavoriteGlobal setState:NSOnState];
[NSApp beginSheet:queryFavoritesSheet
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:@"addAllToNewQueryFavorite"];
@@ -211,7 +211,7 @@
// Open query favorite manager
[NSApp beginSheet:[favoritesManager window]
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:favoritesManager
didEndSelector:nil
contextInfo:nil];
@@ -396,7 +396,7 @@
[encodingPopUp setEnabled:YES];
- [panel beginSheetForDirectory:nil file:@"history" modalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:@"saveHistory"];
+ [panel beginSheetForDirectory:nil file:@"history" modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:@"saveHistory"];
}
- (IBAction)copyQueryHistory:(id)sender
@@ -435,7 +435,7 @@
[[buttons objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask];
[[buttons objectAtIndex:1] setKeyEquivalent:@"\r"];
- [alert beginSheetModalForWindow:tableWindow
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:@"clearHistory"];
@@ -652,14 +652,14 @@
// Reload table list if at least one query began with drop, alter, rename, or create
if(tableListNeedsReload || databaseWasChanged) {
// Build database pulldown menu
- [[tableWindow delegate] setDatabases:self];
+ [tableDocumentInstance setDatabases:self];
if (databaseWasChanged)
// Reset the current database
- [[tableWindow delegate] refreshCurrentDatabase];
+ [tableDocumentInstance refreshCurrentDatabase];
// Reload table list
- [[[tableWindow delegate] valueForKeyPath:@"tablesListInstance"] updateTables:self];
+ [tablesListInstance updateTables:self];
}
@@ -745,7 +745,7 @@
// Perform the Growl notification for query completion
[[SPGrowlController sharedGrowlController] notifyWithTitle:@"Query Finished"
description:[NSString stringWithFormat:NSLocalizedString(@"%@",@"description for query finished growl notification"), [errorText stringValue]]
- window:tableWindow
+ document:tableDocumentInstance
notificationName:@"Query Finished"];
// Set up the callback if present
@@ -799,7 +799,7 @@
// Query finished Growl notification
[[SPGrowlController sharedGrowlController] notifyWithTitle:@"Query Finished"
description:[NSString stringWithFormat:NSLocalizedString(@"%@",@"description for query finished growl notification"), [errorText stringValue]]
- window:tableWindow
+ document:tableDocumentInstance
notificationName:@"Query Finished"];
// Set up the callback if present
@@ -1677,7 +1677,7 @@
// Check for errors while UPDATE
if ([mySQLConnection queryErrored]) {
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), NSLocalizedString(@"Cancel", @"cancel button"), nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), NSLocalizedString(@"Cancel", @"cancel button"), nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"Couldn't write field.\nMySQL said: %@", @"message of panel when error while updating field to db"), [mySQLConnection getLastErrorMessage]]);
return;
@@ -1687,7 +1687,7 @@
// This shouldn't happen – for safety reasons
if ( ![mySQLConnection affectedRows] ) {
if ( [prefs boolForKey:SPShowNoAffectedRowsError] ) {
- SPBeginAlertSheet(NSLocalizedString(@"Warning", @"warning"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Warning", @"warning"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
NSLocalizedString(@"The row was not written to the MySQL database. You probably haven't changed anything.\nReload the table to be sure that the row exists and use a primary key for your table.\n(This error can be turned off in the preferences.)", @"message of panel when no rows have been affected after writing to the db"));
} else {
NSBeep();
@@ -1702,7 +1702,7 @@
[self performQueries:[NSArray arrayWithObject:lastExecutedQuery] withCallback:NULL];
} else {
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"Updating field content failed. Couldn't identify field origin unambiguously (%ld match%@). It's very likely that while editing this field the table `%@` was changed by an other user.", @"message of panel when error while updating field to db after enabling it"),
(long)numberOfPossibleUpdateRows, (numberOfPossibleUpdateRows>1)?@"es":@"", tableForColumn]);
@@ -2039,7 +2039,7 @@
usingEncoding:[mySQLConnection encoding]
isObjectBlob:isBlob
isEditable:isFieldEditable
- withWindow:tableWindow] retain];
+ withWindow:[tableDocumentInstance parentWindow]] retain];
if ( editData )
[self tableView:aTableView setObjectValue:[editData copy] forTableColumn:aTableColumn row:rowIndex];
@@ -3196,9 +3196,9 @@
// Send moveDown/Up to the popup menu
NSEvent *arrowEvent;
if(commandSelector == @selector(moveDown:))
- arrowEvent = [NSEvent keyEventWithType:NSKeyDown location:NSMakePoint(0,0) modifierFlags:0 timestamp:0 windowNumber:[tableWindow windowNumber] context:[NSGraphicsContext currentContext] characters:nil charactersIgnoringModifiers:nil isARepeat:NO keyCode:0x7D];
+ arrowEvent = [NSEvent keyEventWithType:NSKeyDown location:NSMakePoint(0,0) modifierFlags:0 timestamp:0 windowNumber:[[tableDocumentInstance parentWindow] windowNumber] context:[NSGraphicsContext currentContext] characters:nil charactersIgnoringModifiers:nil isARepeat:NO keyCode:0x7D];
else
- arrowEvent = [NSEvent keyEventWithType:NSKeyDown location:NSMakePoint(0,0) modifierFlags:0 timestamp:0 windowNumber:[tableWindow windowNumber] context:[NSGraphicsContext currentContext] characters:nil charactersIgnoringModifiers:nil isARepeat:NO keyCode:0x7E];
+ arrowEvent = [NSEvent keyEventWithType:NSKeyDown location:NSMakePoint(0,0) modifierFlags:0 timestamp:0 windowNumber:[[tableDocumentInstance parentWindow] windowNumber] context:[NSGraphicsContext currentContext] characters:nil charactersIgnoringModifiers:nil isARepeat:NO keyCode:0x7E];
[[NSApplication sharedApplication] postEvent:arrowEvent atStart:NO];
return YES;
diff --git a/Source/SPAppController.h b/Source/SPAppController.h
index 86b9db13..e1ed4291 100644
--- a/Source/SPAppController.h
+++ b/Source/SPAppController.h
@@ -26,7 +26,7 @@
#import <Cocoa/Cocoa.h>
#import <FeedbackReporter/FRFeedbackReporter.h>
-@class SPPreferenceController, SPAboutController;
+@class SPPreferenceController, SPAboutController, TableDocument;
@interface SPAppController : NSObject <FRFeedbackReporterDelegate>
{
@@ -38,6 +38,11 @@
id encodingPopUp;
}
+// Window management
+- (IBAction)newWindow:(id)sender;
+- (IBAction)newTab:(id)sender;
+- (NSWindow *) frontDocumentWindow;
+
// IBAction methods
- (IBAction)openAboutPanel:(id)sender;
- (IBAction)openPreferences:(id)sender;
@@ -56,6 +61,8 @@
// Getters
- (SPPreferenceController *)preferenceController;
+- (NSArray *) orderedDatabaseConnectionWindows;
+- (TableDocument *) frontDocument;
// Feedback controller delegate methods
- (NSMutableDictionary*) anonymizePreferencesForFeedbackReport:(NSMutableDictionary *)preferences;
diff --git a/Source/SPAppController.m b/Source/SPAppController.m
index b80e0680..5adacb8b 100644
--- a/Source/SPAppController.m
+++ b/Source/SPAppController.m
@@ -31,13 +31,14 @@
#import "TableDump.h"
#import "SPEncodingPopupAccessory.h"
#import "SPConstants.h"
+#import "SPWindowController.h"
#import <Sparkle/Sparkle.h>
@implementation SPAppController
/**
- * Inialise the application's main controller, setting itself as the app delegate.
+ * Initialise the application's main controller, setting itself as the app delegate.
*/
- (id)init
{
@@ -96,14 +97,6 @@
*/
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
{
- if ([menuItem action] == @selector(openConnectionSheet:) && [menuItem tag] == 0)
- {
- // Do not allow to open a sql/spf file if SP asks for connection details
- if ([[[NSDocumentController sharedDocumentController] documents] count]) {
- if(![[[[NSDocumentController sharedDocumentController] currentDocument] mySQLVersion] length])
- return NO;
- }
- }
if ([menuItem action] == @selector(openCurrentConnectionInNewWindow:))
{
[menuItem setTitle:NSLocalizedString(@"Open in New Window", @"menu item open in new window")];
@@ -160,13 +153,13 @@
// it will enabled if user selects a *.sql file
[encodingPopUp setEnabled:NO];
-
+
// Check if at least one document exists, if so show a sheet
- if ([[[NSDocumentController sharedDocumentController] documents] count]) {
+ if ([self frontDocumentWindow]) {
[panel beginSheetForDirectory:nil
file:@""
types:[NSArray arrayWithObjects:@"spf", @"sql", nil]
- modalForWindow:[[[NSDocumentController sharedDocumentController] currentDocument] valueForKey:@"tableWindow"]
+ modalForWindow:[self frontDocumentWindow]
modalDelegate:self
didEndSelector:@selector(openConnectionPanelDidEnd:returnCode:contextInfo:)
contextInfo:NULL];
@@ -220,7 +213,7 @@
[alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"cancel button")];
// Show 'Import' button only if there's a connection available
- if ([[[NSDocumentController sharedDocumentController] documents] count])
+ if ([self frontDocument])
[alert addButtonWithTitle:NSLocalizedString(@"Import", @"import button")];
@@ -237,49 +230,44 @@
if(returnCode == NSAlertSecondButtonReturn) return; // Cancel
else if(returnCode == NSAlertThirdButtonReturn) { // Import
// begin import process
- [[[[NSDocumentController sharedDocumentController] currentDocument] valueForKeyPath:@"tableDumpInstance"] startSQLImportProcessWithFile:filename];
+ [[[self frontDocument] valueForKeyPath:@"tableDumpInstance"] startSQLImportProcessWithFile:filename];
return;
}
}
}
}
+ // Attempt to open the file into a string.
+ NSString *sqlString = nil;
+
+ // If the user came from an openPanel use the chosen encoding
+ if (encodingPopUp) {
+ NSError *error = nil;
+ sqlString = [NSString stringWithContentsOfFile:filename encoding:[[encodingPopUp selectedItem] tag] error:&error];
+ if(error != nil) {
+ NSAlert *errorAlert = [NSAlert alertWithError:error];
+ [errorAlert runModal];
+ return;
+ }
+
+ // Otherwise, read while attempting to autodetect the encoding
+ } else {
+ sqlString = [self contentOfFile:filename];
+ }
+
// if encodingPopUp is defined the filename comes from an openPanel and
// the encodingPopUp contains the chosen encoding; otherwise autodetect encoding
if(encodingPopUp)
[[NSUserDefaults standardUserDefaults] setInteger:[[encodingPopUp selectedItem] tag] forKey:SPLastSQLFileEncoding];
- // Check if at least one document exists
- if (![[[NSDocumentController sharedDocumentController] documents] count]) {
-
- TableDocument *firstTableDocument;
-
- // Manually open a new document, setting SPAppController as sender to trigger autoconnection
- if (firstTableDocument = [[NSDocumentController sharedDocumentController] makeUntitledDocumentOfType:@"Sequel Pro connection" error:nil]) {
- [firstTableDocument setShouldAutomaticallyConnect:NO];
-
- // user comes from a openPanel? if so use the chosen encoding
- if(encodingPopUp) {
- NSError *error = nil;
- NSString *content = [NSString stringWithContentsOfFile:filename encoding:[[encodingPopUp selectedItem] tag] error:&error];
- if(error != nil) {
- NSAlert *errorAlert = [NSAlert alertWithError:error];
- [errorAlert runModal];
- return;
- }
- [firstTableDocument initQueryEditorWithString:content];
-
- }
- else
- [firstTableDocument initQueryEditorWithString:[self contentOfFile:filename]];
-
- [[NSDocumentController sharedDocumentController] addDocument:firstTableDocument];
- [firstTableDocument makeWindowControllers];
- [firstTableDocument showWindows];
- }
+ // Check if at least one document exists. If not, open one.
+ if (![self frontDocument]) {
+ [self newWindow:self];
+ [[self frontDocument] initQueryEditorWithString:sqlString];
} else {
+
// Pass query to the Query editor of the current document
- [[[NSDocumentController sharedDocumentController] currentDocument] doPerformLoadQueryService:[self contentOfFile:filename]];
+ [[self frontDocument] doPerformLoadQueryService:[self contentOfFile:filename]];
}
break; // open only the first SQL file
@@ -289,15 +277,12 @@
TableDocument *newTableDocument;
- // 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:filename];
+ // If the frontmost document isn't connected and hasn't been, open the connection file with it.
+ // Otherwise, manually open a new document, setting SPAppController as sender to trigger autoconnection
+ if ([[self frontDocument] mySQLVersion]) {
+ [self newWindow:self];
}
-
+ [[self frontDocument] initWithConnectionFile:filename];
}
else {
NSLog(@"Only files with the extensions ‘spf’ or ‘sql’ are allowed.");
@@ -306,6 +291,81 @@
}
#pragma mark -
+#pragma mark Window management
+
+/**
+ * Create a new window, containing a single tab.
+ */
+- (IBAction)newWindow:(id)sender
+{
+ static NSPoint cascadeLocation = {.x = 0, .y = 0};
+
+ // Create a new window controller, and set up a new connection view within it.
+ SPWindowController *newWindowController = [[SPWindowController alloc] initWithWindowNibName:@"MainWindow"];
+ NSWindow *newWindow = [newWindowController window];
+ [newWindow setReleasedWhenClosed:YES];
+
+ // Cascading defaults to on - retrieve the window origin automatically assigned by cascading,
+ // and convert to a top left point.
+ NSPoint topLeftPoint = [newWindow frame].origin;
+ topLeftPoint.y += [newWindow frame].size.height;
+
+ // The first window should use autosaving; subsequent windows should cascade.
+ // So attempt to set the frame autosave name; this will succeed for the very
+ // first window, and fail for others.
+ BOOL usedAutosave = [newWindow setFrameAutosaveName:@"DBView"];
+ if (!usedAutosave) {
+ [newWindow setFrameUsingName:@"DBView"];
+ }
+
+ // Cascade according to the statically stored cascade location.
+ cascadeLocation = [newWindow cascadeTopLeftFromPoint:cascadeLocation];
+
+ // Set the window controller as the window's delegate
+ [newWindow setDelegate:newWindowController];
+
+ // Show the window
+ [newWindowController showWindow:self];
+}
+
+/**
+ * Create a new tab in the frontmost window.
+ */
+- (IBAction)newTab:(id)sender
+{
+ SPWindowController *frontController = nil;
+
+ for (NSWindow *aWindow in [self orderedWindows]) {
+ if ([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) {
+ frontController = [aWindow windowController];
+ break;
+ }
+ }
+
+ // If no window was found, create a new one
+ if (!frontController) {
+ [self newWindow:self];
+ } else {
+ if ([[frontController window] isMiniaturized]) [[frontController window] deminiaturize:self];
+ [frontController addNewConnection:self];
+ }
+}
+
+/**
+ * Retrieve the frontmost document window; returns nil if not found.
+ */
+- (NSWindow *) frontDocumentWindow
+{
+ for (NSWindow *aWindow in [self orderedWindows]) {
+ if ([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) {
+ return aWindow;
+ }
+ }
+
+ return nil;
+}
+
+#pragma mark -
#pragma mark IBAction methods
/**
@@ -337,11 +397,38 @@
return prefsController;
}
+/**
+ * Provide a method to retrieve an ordered list of the database
+ * connection windows currently open in the application.
+ */
+- (NSArray *) orderedDatabaseConnectionWindows
+{
+ NSMutableArray *orderedDatabaseConnectionWindows = [NSMutableArray array];
+ for (NSWindow *aWindow in [NSApp orderedWindows]) {
+ if ([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) [orderedDatabaseConnectionWindows addObject:aWindow];
+ }
+ return orderedDatabaseConnectionWindows;
+}
+
+/**
+ * Retrieve the frontmost document; returns nil if not found.
+ */
+- (TableDocument *) frontDocument
+{
+ for (NSWindow *aWindow in [self orderedWindows]) {
+ if ([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) {
+ return [[aWindow windowController] selectedTableDocument];
+ }
+ }
+
+ return nil;
+}
+
#pragma mark -
#pragma mark Services menu methods
/**
- * Passes the query to the last created document
+ * Passes the query to the frontmost document
*/
- (void)doPerformQueryService:(NSPasteboard *)pboard userData:(NSString *)data error:(NSString **)error
{
@@ -356,14 +443,14 @@
}
// Check if at least one document exists
- if (![[[NSDocumentController sharedDocumentController] documents] count]) {
+ if (![self frontDocument]) {
*error = @"No Documents open!";
return;
}
- // Pass query to last created document
- [[[[NSDocumentController sharedDocumentController] documents] objectAtIndex:([[[NSDocumentController sharedDocumentController] documents] count] - 1)] doPerformQueryService:pboardString];
+ // Pass query to front document
+ [[self frontDocument] doPerformQueryService:pboardString];
return;
}
@@ -446,21 +533,18 @@
#pragma mark Other methods
/**
- * Override the default open-blank-document methods to automatically connect automatically opened windows.
+ * Override the default open-blank-document methods to automatically connect automatically opened windows
+ * if the preference is set
*/
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
{
- TableDocument *firstTableDocument;
- // Manually open a new document, setting SPAppController as sender to trigger autoconnection
- if (firstTableDocument = [[NSDocumentController sharedDocumentController] makeUntitledDocumentOfType:@"Sequel Pro connection" error:nil]) {
- if ([[NSUserDefaults standardUserDefaults] boolForKey:SPAutoConnectToDefault]) {
- [firstTableDocument setShouldAutomaticallyConnect:YES];
- }
-
- [[NSDocumentController sharedDocumentController] addDocument:firstTableDocument];
- [firstTableDocument makeWindowControllers];
- [firstTableDocument showWindows];
+ // Manually open a table document
+ [self newWindow:self];
+
+ // Set autoconnection if appropriate
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:SPAutoConnectToDefault]) {
+ [[self frontDocument] connect];
}
// Return NO to the automatic opening
@@ -474,16 +558,8 @@
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
{
// Only create a new document (without auto-connect) when there are already no documents open.
- if ([[[NSDocumentController sharedDocumentController] documents] count] == 0) {
- TableDocument *firstTableDocument;
-
- // Manually open a new document, setting SPAppController as sender to trigger autoconnection
- if (firstTableDocument = [[NSDocumentController sharedDocumentController] makeUntitledDocumentOfType:@"Sequel Pro connection" error:nil]) {
- [[NSDocumentController sharedDocumentController] addDocument:firstTableDocument];
- [firstTableDocument makeWindowControllers];
- [firstTableDocument showWindows];
- }
-
+ if (![self frontDocument]) {
+ [self newWindow:self];
return NO;
}
@@ -620,20 +696,30 @@
*/
- (NSArray *)orderedDocuments
{
- return [[NSDocumentController sharedDocumentController] documents];
+ NSMutableArray *orderedDocuments = [NSMutableArray array];
+
+ for (NSWindow *aWindow in [self orderedWindows]) {
+ if ([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) {
+ [orderedDocuments addObjectsFromArray:[[aWindow windowController] documents]];
+ }
+ }
+
+ return orderedDocuments;
}
/**
* Support for 'make new document'.
+ * TODO: following tab support this has been disabled - need to discuss reimplmenting vs syntax.
*/
- (void)insertInOrderedDocuments:(TableDocument *)doc
{
- if ([[NSUserDefaults standardUserDefaults] boolForKey:SPAutoConnectToDefault])
+ [self newWindow:self];
+/* if ([[NSUserDefaults standardUserDefaults] boolForKey:SPAutoConnectToDefault])
[doc setShouldAutomaticallyConnect:YES];
[[NSDocumentController sharedDocumentController] addDocument:doc];
[doc makeWindowControllers];
- [doc showWindows];
+ [doc showWindows];*/
}
/**
diff --git a/Source/SPConnectionController.h b/Source/SPConnectionController.h
index 7e518e26..3e272abc 100644
--- a/Source/SPConnectionController.h
+++ b/Source/SPConnectionController.h
@@ -50,8 +50,8 @@
id delegate;
TableDocument *tableDocument;
- NSWindow *documentWindow;
- NSSplitView *contentView;
+ NSView *databaseConnectionSuperview;
+ NSSplitView *databaseConnectionView;
SPKeychain *keychain;
NSUserDefaults *prefs;
NSMutableArray *favorites;
@@ -79,6 +79,8 @@
NSString *connectionSSHKeychainItemName;
NSString *connectionSSHKeychainItemAccount;
+ NSMutableArray *nibObjectsToRelease;
+
IBOutlet NSView *connectionView;
IBOutlet NSSplitView *connectionSplitView;
IBOutlet BWAnchoredButtonBar *connectionSplitViewButtonBar;
diff --git a/Source/SPConnectionController.m b/Source/SPConnectionController.m
index 933accfb..582f80da 100644
--- a/Source/SPConnectionController.m
+++ b/Source/SPConnectionController.m
@@ -60,8 +60,8 @@
{
if (self = [super init]) {
tableDocument = theTableDocument;
- documentWindow = [tableDocument valueForKey:@"tableWindow"];
- contentView = [tableDocument valueForKey:@"contentViewSplitter"];
+ databaseConnectionSuperview = [tableDocument parentView];
+ databaseConnectionView = [tableDocument valueForKey:@"contentViewSplitter"];
connectionKeychainItemName = nil;
connectionKeychainItemAccount = nil;
connectionSSHKeychainItemName = nil;
@@ -70,20 +70,21 @@
sshTunnel = nil;
cancellingConnection = NO;
- // Load the connection nib
- [NSBundle loadNibNamed:@"ConnectionView" owner:self];
+ // Load the connection nib, keeping references to the top-level objects for later release
+ nibObjectsToRelease = [[NSMutableArray alloc] init];
+ NSArray *connectionViewTopLevelObjects = nil;
+ NSNib *nibLoader = [[NSNib alloc] initWithNibNamed:@"ConnectionView" bundle:[NSBundle mainBundle]];
+ [nibLoader instantiateNibWithOwner:self topLevelObjects:&connectionViewTopLevelObjects];
+ [nibObjectsToRelease addObjectsFromArray:connectionViewTopLevelObjects];
+ [nibLoader release];
// Hide the main view and position and display the connection view
- [contentView setHidden:YES];
- [connectionView setFrame:[contentView frame]];
- [[documentWindow contentView] addSubview:connectionView];
+ [databaseConnectionView setHidden:YES];
+ [connectionView setFrame:[databaseConnectionView frame]];
+ [databaseConnectionSuperview addSubview:connectionView];
[connectionSplitView setPosition:[[tableDocument valueForKey:@"dbTablesTableView"] frame].size.width ofDividerAtIndex:0];
[connectionSplitViewButtonBar setSplitViewDelegate:self];
- // Disable the toolbar icons
- NSArray *toolbarItems = [[documentWindow toolbar] items];
- for (NSInteger i = 0; i < [toolbarItems count]; i++) [[toolbarItems objectAtIndex:i] setEnabled:NO];
-
// Set up a keychain instance and preferences reference, and create the initial favorites list
keychain = [[SPKeychain alloc] init];
prefs = [[NSUserDefaults standardUserDefaults] retain];
@@ -98,7 +99,7 @@
[favoritesTable setDoubleAction:@selector(initiateConnection:)];
// Set the focus to the favorites table and select the appropriate row
- [documentWindow setInitialFirstResponder:favoritesTable];
+ [[tableDocument parentWindow] setInitialFirstResponder:favoritesTable];
NSInteger tableRow;
if ([prefs boolForKey:SPSelectLastFavoriteUsed] == YES) {
tableRow = [prefs integerForKey:SPLastFavoriteIndex] + 1;
@@ -114,11 +115,6 @@
previousType = SPTCPIPConnection;
[self resizeTabViewToConnectionType:SPTCPIPConnection animating:NO];
}
-
- // If the document is set to automatically connect, do so.
- if ([tableDocument shouldAutomaticallyConnect]) {
- [self performSelector:@selector(initiateConnection:) withObject:self afterDelay:0.0];
- }
}
return self;
@@ -129,6 +125,10 @@
[prefs removeObserver:self forKeyPath:SPFavorites];
[keychain release];
[prefs release];
+
+ for (id retainedObject in nibObjectsToRelease) [retainedObject release];
+ [nibObjectsToRelease release];
+
if (favorites) [favorites release];
if (mySQLConnection) [mySQLConnection release];
if (sshTunnel) [sshTunnel setConnectionStateChangeSelector:nil delegate:nil], [sshTunnel disconnect], [sshTunnel release];
@@ -153,13 +153,13 @@
{
// Ensure that host is not empty if this is a TCP/IP or SSH connection
if (([self type] == SPTCPIPConnection || [self type] == SPSSHTunnelConnection) && ![[self host] length]) {
- SPBeginAlertSheet(NSLocalizedString(@"Insufficient connection details", @"insufficient details message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, documentWindow, self, nil, nil, NSLocalizedString(@"Insufficient details provided to establish a connection. Please enter at least the hostname.", @"insufficient details informative message"));
+ SPBeginAlertSheet(NSLocalizedString(@"Insufficient connection details", @"insufficient details message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocument parentWindow], self, nil, nil, NSLocalizedString(@"Insufficient details provided to establish a connection. Please enter at least the hostname.", @"insufficient details informative message"));
return;
}
// If SSH is enabled, ensure that the SSH host is not nil
if ([self type] == SPSSHTunnelConnection && ![[self sshHost] length]) {
- SPBeginAlertSheet(NSLocalizedString(@"Insufficient connection details", @"insufficient details message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, documentWindow, self, nil, nil, NSLocalizedString(@"Insufficient details provided to establish a connection. Please enter the hostname for the SSH Tunnel, or disable the SSH Tunnel.", @"insufficient SSH tunnel details informative message"));
+ SPBeginAlertSheet(NSLocalizedString(@"Insufficient connection details", @"insufficient details message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocument parentWindow], self, nil, nil, NSLocalizedString(@"Insufficient details provided to establish a connection. Please enter the hostname for the SSH Tunnel, or disable the SSH Tunnel.", @"insufficient SSH tunnel details informative message"));
return;
}
@@ -185,9 +185,9 @@
if (connectionKeychainItemName) {
if ([[keychain getPasswordForName:connectionKeychainItemName account:connectionKeychainItemAccount] isEqualToString:[self password]]) {
[self setPassword:[[NSString string] stringByPaddingToLength:[[self password] length] withString:@"sp" startingAtIndex:0]];
- [[tableDocument undoManager] removeAllActionsWithTarget:standardPasswordField];
- [[tableDocument undoManager] removeAllActionsWithTarget:socketPasswordField];
- [[tableDocument undoManager] removeAllActionsWithTarget:sshPasswordField];
+ [[standardPasswordField undoManager] removeAllActionsWithTarget:standardPasswordField];
+ [[socketPasswordField undoManager] removeAllActionsWithTarget:socketPasswordField];
+ [[sshPasswordField undoManager] removeAllActionsWithTarget:sshPasswordField];
} else {
[connectionKeychainItemName release], connectionKeychainItemName = nil;
[connectionKeychainItemAccount release], connectionKeychainItemAccount = nil;
@@ -196,7 +196,7 @@
if (connectionSSHKeychainItemName) {
if ([[keychain getPasswordForName:connectionSSHKeychainItemName account:connectionSSHKeychainItemAccount] isEqualToString:[self sshPassword]]) {
[self setSshPassword:[[NSString string] stringByPaddingToLength:[[self sshPassword] length] withString:@"sp" startingAtIndex:0]];
- [[tableDocument undoManager] removeAllActionsWithTarget:sshSSHPasswordField];
+ [[sshSSHPasswordField undoManager] removeAllActionsWithTarget:sshSSHPasswordField];
} else {
[connectionSSHKeychainItemName release], connectionSSHKeychainItemName = nil;
[connectionSSHKeychainItemAccount release], connectionSSHKeychainItemAccount = nil;
@@ -236,7 +236,7 @@
// Set up the tunnel details
sshTunnel = [[SPSSHTunnel alloc] initToHost:[self sshHost] port:([[self sshPort] length]?[[self sshPort] integerValue]:22) login:[self sshUser] tunnellingToPort:([[self port] length]?[[self port] integerValue]:3306) onHost:[self host]];
- [sshTunnel setParentWindow:documentWindow];
+ [sshTunnel setParentWindow:[tableDocument parentWindow]];
// Add keychain or plaintext password as appropriate - note the checks in initiateConnection.
if (connectionSSHKeychainItemName) {
@@ -437,8 +437,8 @@
}
// Only display the connection error message if there is a window visible
- if ([documentWindow isVisible]) {
- SPBeginAlertSheet(theTitle, NSLocalizedString(@"OK", @"OK button"), (errorDetail) ? NSLocalizedString(@"Show Detail", @"Show detail button") : nil, (isSSHTunnelBindError) ? NSLocalizedString(@"Use Standard Connection", @"use standard connection button") : nil, documentWindow, self, @selector(connectionFailureSheetDidEnd:returnCode:contextInfo:), @"connect", theErrorMessage);
+ if ([[tableDocument parentWindow] isVisible]) {
+ SPBeginAlertSheet(theTitle, NSLocalizedString(@"OK", @"OK button"), (errorDetail) ? NSLocalizedString(@"Show Detail", @"Show detail button") : nil, (isSSHTunnelBindError) ? NSLocalizedString(@"Use Standard Connection", @"use standard connection button") : nil, [tableDocument parentWindow], self, @selector(connectionFailureSheetDidEnd:returnCode:contextInfo:), @"connect", theErrorMessage);
}
}
@@ -491,10 +491,10 @@
// Hide the connection view and restore the main view
[connectionView removeFromSuperviewWithoutNeedingDisplay];
- [contentView setHidden:NO];
+ [databaseConnectionView setHidden:NO];
// Restore the toolbar icons
- NSArray *toolbarItems = [[documentWindow toolbar] items];
+ NSArray *toolbarItems = [[[tableDocument parentWindow] toolbar] items];
for (NSInteger i = 0; i < [toolbarItems count]; i++) [[toolbarItems objectAtIndex:i] setEnabled:YES];
// Set keychain id for saving SPF files
@@ -628,7 +628,7 @@
NSLocalizedString(@"Use 127.0.0.1", @"Use 127.0.0.1 button"), // Main button
NSLocalizedString(@"Connect via socket", @"Connect via socket button"), // Alternate button
nil, // Other button
- documentWindow, // Window to attach to
+ [tableDocument parentWindow], // Window to attach to
self, // Modal delegate
@selector(localhostErrorSheetDidEnd:returnCode:contextInfo:), // Did end selector
nil, // Contextual info for selectors
@@ -728,15 +728,15 @@
switch([self type]) {
case SPTCPIPConnection:
if(![[standardPasswordField stringValue] length])
- [documentWindow makeFirstResponder:standardPasswordField];
+ [[tableDocument parentWindow] makeFirstResponder:standardPasswordField];
break;
case SPSocketConnection:
if(![[socketPasswordField stringValue] length])
- [documentWindow makeFirstResponder:socketPasswordField];
+ [[tableDocument parentWindow] makeFirstResponder:socketPasswordField];
break;
case SPSSHTunnelConnection:
if(![[sshPasswordField stringValue] length])
- [documentWindow makeFirstResponder:sshPasswordField];
+ [[tableDocument parentWindow] makeFirstResponder:sshPasswordField];
break;
}
}
@@ -928,7 +928,7 @@
*/
- (void) splitViewDidResizeSubviews:(NSNotification *)aNotification
{
- [contentView setPosition:[[[connectionSplitView subviews] objectAtIndex:0] frame].size.width ofDividerAtIndex:0];
+ [databaseConnectionView setPosition:[[[connectionSplitView subviews] objectAtIndex:0] frame].size.width ofDividerAtIndex:0];
}
/**
diff --git a/Source/SPConnectionDelegate.m b/Source/SPConnectionDelegate.m
index 258b4402..65ffa3f9 100644
--- a/Source/SPConnectionDelegate.m
+++ b/Source/SPConnectionDelegate.m
@@ -103,7 +103,7 @@
*/
- (void)noConnectionAvailable:(id)connection
{
- SPBeginAlertSheet(NSLocalizedString(@"No connection available", @"no connection available message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, NSLocalizedString(@"An error has occured and there doesn't seem to be a connection available.", @"no connection available informatie message"));
+ SPBeginAlertSheet(NSLocalizedString(@"No connection available", @"no connection available message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [self parentWindow], self, nil, nil, NSLocalizedString(@"An error has occured and there doesn't seem to be a connection available.", @"no connection available informatie message"));
}
/**
@@ -114,10 +114,13 @@
NSInteger connectionErrorCode = MCPConnectionCheckDisconnect;
// Only display the reconnect dialog if the window is visible
- if ([tableWindow isVisible]) {
+ if ([self parentWindow] && [[self parentWindow] isVisible]) {
+
+ // Ensure the window and tab are frontmost
+ [self makeKeyDocument];
// Display the connection error dialog and wait for the return code
- [NSApp beginSheet:connectionErrorDialog modalForWindow:tableWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
+ [NSApp beginSheet:connectionErrorDialog modalForWindow:[self parentWindow] modalDelegate:self didEndSelector:nil contextInfo:nil];
connectionErrorCode = [NSApp runModalForWindow:connectionErrorDialog];
[NSApp endSheet:connectionErrorDialog];
@@ -125,7 +128,7 @@
// If 'disconnect' was selected, trigger a window close.
if (connectionErrorCode == MCPConnectionCheckDisconnect) {
- [self performSelectorOnMainThread:@selector(closeDocumentWindowAndDisconnect) withObject:nil waitUntilDone:YES];
+ [self performSelectorOnMainThread:@selector(closeAndDisconnect) withObject:nil waitUntilDone:YES];
}
}
@@ -137,8 +140,8 @@
*/
- (void)showErrorWithTitle:(NSString *)theTitle message:(NSString *)theMessage
{
- if ([tableWindow isVisible]) {
- SPBeginAlertSheet(theTitle, NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, theMessage);
+ if ([[self parentWindow] isVisible]) {
+ SPBeginAlertSheet(theTitle, NSLocalizedString(@"OK", @"OK button"), nil, nil, [self parentWindow], self, nil, nil, theMessage);
}
}
@@ -152,17 +155,20 @@
/**
* Close the connection - should be performed on the main thread.
- * First hides the window to give code a little bit of time to clean
- * everything up before it's all deallocated as a result of the close.
- * Also sets alpha to fully transparent so accidental dialogs are hidden!
*/
-- (void) closeDocumentWindowAndDisconnect
+- (void) closeAndDisconnect
{
- _isConnected = NO;
- [self windowWillClose:nil];
- [tableWindow orderOut:self];
- [tableWindow setAlphaValue:0.0];
- [tableWindow performSelector:@selector(close) withObject:nil afterDelay:1.0];
+ NSWindow *theParentWindow = [self parentWindow];
+ _isConnected = NO;
+ if ([[[self parentTabViewItem] tabView] numberOfTabViewItems] == 1) {
+ [theParentWindow orderOut:self];
+ [theParentWindow setAlphaValue:0.0];
+ [theParentWindow performSelector:@selector(close) withObject:nil afterDelay:1.0];
+ } else {
+ [[[self parentTabViewItem] tabView] performSelector:@selector(removeTabViewItem:) withObject:[self parentTabViewItem] afterDelay:0.5];
+ [theParentWindow performSelector:@selector(makeKeyAndOrderFront:) withObject:nil afterDelay:0.6];
+ }
+ [self parentTabDidClose];
}
@end
diff --git a/Source/SPConstants.h b/Source/SPConstants.h
index a547d6c1..d893b825 100644
--- a/Source/SPConstants.h
+++ b/Source/SPConstants.h
@@ -109,6 +109,19 @@ typedef enum
SPLinkDrawStateBackgroundHighlight = 2
} SPTextAndLinkCellDrawState;
+// Menu tag constants
+typedef enum
+{
+ SPMainMenuSequelPro = 0,
+ SPMainMenuFile = 1,
+ SPMainMenuEdit = 2,
+ SPMainMenuView = 3,
+ SPMainMenuDatabase = 4,
+ SPMainMenuTable = 5,
+ SPMainMenuWindow = 6,
+ SPMainMenuHelp = 7
+} SPMainMenuTags;
+
// Long running notification time for Growl messages
extern const CGFloat SPLongRunningNotificationTime;
diff --git a/Source/SPContentFilterManager.h b/Source/SPContentFilterManager.h
index 7c6525ba..ba41a34f 100644
--- a/Source/SPContentFilterManager.h
+++ b/Source/SPContentFilterManager.h
@@ -25,7 +25,7 @@
#import <Cocoa/Cocoa.h>
-@class BWAnchoredButtonBar;
+@class BWAnchoredButtonBar, TableDocument;
@interface NSObject (SPContentFilterManagerDelegate)
@@ -37,6 +37,7 @@
{
NSUserDefaults *prefs;
+ TableDocument *tableDocumentInstance;
NSURL *delegatesFileURL;
IBOutlet id encodingPopUp;
IBOutlet id contentFilterTableView;
diff --git a/Source/SPContentFilterManager.m b/Source/SPContentFilterManager.m
index 30defe7a..ac9bef86 100644
--- a/Source/SPContentFilterManager.m
+++ b/Source/SPContentFilterManager.m
@@ -58,7 +58,8 @@
NSLog(@"ContentFilterManager was called without a delegate.");
return nil;
}
- delegatesFileURL = [[managerDelegate valueForKeyPath:@"tableDocumentInstance"] fileURL];
+ tableDocumentInstance = [managerDelegate valueForKeyPath:@"tableDocumentInstance"];
+ delegatesFileURL = [tableDocumentInstance fileURL];
filterType = [NSString stringWithString:compareType];
@@ -211,7 +212,7 @@
*/
- (id)customQueryInstance
{
- return [[[NSApp mainWindow] delegate] valueForKey:@"customQueryInstance"];
+ return [tableDocumentInstance valueForKey:@"customQueryInstance"];
}
@@ -371,7 +372,7 @@
[cf release];
// Inform all opened documents to update the query favorites list
- for(id doc in [[NSDocumentController sharedDocumentController] documents])
+ for(id doc in [[NSApp delegate] orderedDocuments])
if([[doc valueForKeyPath:@"tableContentInstance"] respondsToSelector:@selector(setCompareTypes:)])
[[doc valueForKeyPath:@"tableContentInstance"] setCompareTypes:nil];
diff --git a/Source/SPDocumentController.h b/Source/SPDocumentController.h
new file mode 100644
index 00000000..237e71a3
--- /dev/null
+++ b/Source/SPDocumentController.h
@@ -0,0 +1,32 @@
+//
+// $Id$
+//
+// SPDocumentController.h
+// sequel-pro
+//
+// Created by Rowan Beentje on May 23, 2010
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface SPDocumentController : NSDocument {
+
+}
+
+@end
diff --git a/Source/SPDocumentController.m b/Source/SPDocumentController.m
new file mode 100644
index 00000000..baec776b
--- /dev/null
+++ b/Source/SPDocumentController.m
@@ -0,0 +1,36 @@
+//
+// $Id$
+//
+// SPDocumentController.h
+// sequel-pro
+//
+// Created by Rowan Beentje on May 23, 2010
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+
+#import "SPDocumentController.h"
+
+
+@implementation SPDocumentController
+
+/**
+ * This is an empty, dummy implementation; this allows Sequel Pro to behave
+ * as if it were a document-based application.
+ */
+
+@end
diff --git a/Source/SPExportController.h b/Source/SPExportController.h
index b1c50933..773b678d 100644
--- a/Source/SPExportController.h
+++ b/Source/SPExportController.h
@@ -52,7 +52,6 @@ typedef NSUInteger SPExportSource;
{
// Table document
IBOutlet id tableDocumentInstance;
- IBOutlet id tableWindow;
// Tables list
IBOutlet id tablesListInstance;
@@ -122,7 +121,9 @@ typedef NSUInteger SPExportSource;
// Table/export operation mapping
NSMutableDictionary *tableExportMapping;
-
+
+ // Top-level nib objects that require releasing on dealloc
+ NSMutableArray *nibObjectsToRelease;
}
@property (readwrite, assign) BOOL exportCancelled;
diff --git a/Source/SPExportController.m b/Source/SPExportController.m
index dce7857b..559e8071 100644
--- a/Source/SPExportController.m
+++ b/Source/SPExportController.m
@@ -54,6 +54,7 @@
tables = [[NSMutableArray alloc] init];
operationQueue = [[NSOperationQueue alloc] init];
tableExportMapping = [NSMutableDictionary dictionary];
+ nibObjectsToRelease = [[NSMutableArray alloc] init];
}
return self;
@@ -76,7 +77,16 @@
*/
- (void)export
{
- if (!exportWindow) [NSBundle loadNibNamed:@"ExportDialog" owner:self];
+
+ // If the dialog hasn't been loaded yet, do so, retaining a reference to the top-level objects that need releasing.
+ if (!exportWindow)
+ {
+ NSArray *exportDialogTopLevelObjects = nil;
+ NSNib *nibLoader = [[NSNib alloc] initWithNibNamed:@"ExportDialog" bundle:[NSBundle mainBundle]];
+ [nibLoader instantiateNibWithOwner:self topLevelObjects:&exportDialogTopLevelObjects];
+ [nibObjectsToRelease addObjectsFromArray:exportDialogTopLevelObjects];
+ [nibLoader release];
+ }
NSUInteger i;
@@ -99,7 +109,7 @@
[exportPathField setStringValue:NSHomeDirectory()];
[NSApp beginSheet:exportWindow
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:nil];
@@ -277,6 +287,8 @@
{
[tables release], tables = nil;
[operationQueue release], operationQueue = nil;
+ for (id retainedObject in nibObjectsToRelease) [retainedObject release];
+ [nibObjectsToRelease release], nibObjectsToRelease = nil;
[super dealloc];
}
@@ -364,7 +376,7 @@
// Open the progress sheet
[NSApp beginSheet:exportProgressWindow
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:nil
contextInfo:nil];
diff --git a/Source/SPFieldEditorController.h b/Source/SPFieldEditorController.h
index d6a0be1e..6ba9018b 100644
--- a/Source/SPFieldEditorController.h
+++ b/Source/SPFieldEditorController.h
@@ -75,7 +75,7 @@
- (IBAction)dropImage:(id)sender;
- (id)editWithObject:(id)data fieldName:(NSString*)fieldName usingEncoding:(NSStringEncoding)anEncoding
- isObjectBlob:(BOOL)isFieldBlob isEditable:(BOOL)isEditable withWindow:(NSWindow *)tableWindow;
+ isObjectBlob:(BOOL)isFieldBlob isEditable:(BOOL)isEditable withWindow:(NSWindow *)theWindow;
- (void)setTextMaxLength:(unsigned long long)length;
diff --git a/Source/SPFieldEditorController.m b/Source/SPFieldEditorController.m
index cb4a11f7..7bef2719 100644
--- a/Source/SPFieldEditorController.m
+++ b/Source/SPFieldEditorController.m
@@ -131,7 +131,7 @@
}
- (id)editWithObject:(id)data fieldName:(NSString*)fieldName usingEncoding:(NSStringEncoding)anEncoding
- isObjectBlob:(BOOL)isFieldBlob isEditable:(BOOL)isEditable withWindow:(NSWindow *)tableWindow
+ isObjectBlob:(BOOL)isFieldBlob isEditable:(BOOL)isEditable withWindow:(NSWindow *)theWindow
{
// If required, use monospaced fonts
if (![prefs objectForKey:SPFieldEditorSheetFont]) {
@@ -192,7 +192,7 @@
[editTextView setEditable:isEditable];
[editImage setEditable:isEditable];
- [NSApp beginSheet:editSheet modalForWindow:tableWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
+ [NSApp beginSheet:editSheet modalForWindow:theWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
[editSheetProgressBar startAnimation:self];
diff --git a/Source/SPGrowlController.h b/Source/SPGrowlController.h
index 410ce914..e3f054a5 100644
--- a/Source/SPGrowlController.h
+++ b/Source/SPGrowlController.h
@@ -26,6 +26,8 @@
#import <Cocoa/Cocoa.h>
#import <Growl/Growl.h>
+@class TableDocument;
+
@interface SPGrowlController : NSObject <GrowlApplicationBridgeDelegate>
{
NSString *timingNotificationName;
@@ -38,14 +40,14 @@
// Post notification
- (void)notifyWithTitle:(NSString *)title
description:(NSString *)description
- window:(NSWindow *)window
+ document:(TableDocument *)document
notificationName:(NSString *)name;
- (void)notifyWithObject:(NSDictionary *)notificationDictionary;
- (void)notifyWithTitle:(NSString *)title
description:(NSString *)description
- window:(NSWindow *)window
+ document:(TableDocument *)document
notificationName:(NSString *)name
iconData:(NSData *)data
priority:(NSInteger)priority
diff --git a/Source/SPGrowlController.m b/Source/SPGrowlController.m
index b4f84780..50ca4906 100644
--- a/Source/SPGrowlController.m
+++ b/Source/SPGrowlController.m
@@ -31,6 +31,8 @@
static SPGrowlController *sharedGrowlController = nil;
+@class SPWindowController;
+
@implementation SPGrowlController
/**
@@ -84,21 +86,21 @@ static SPGrowlController *sharedGrowlController = nil;
* Calls the notification after a tiny delay to allow isKeyWindow to have updated
* after tasks.
*/
-- (void)notifyWithTitle:(NSString *)title description:(NSString *)description window:(NSWindow *)window notificationName:(NSString *)name
+- (void)notifyWithTitle:(NSString *)title description:(NSString *)description document:(TableDocument *)document notificationName:(NSString *)name
{
// Ensure that the delayed notification call is made on the main thread
if (![NSThread isMainThread]) {
- [[self onMainThread] notifyWithTitle:title description:description window:window notificationName:name];
+ [[self onMainThread] notifyWithTitle:title description:description document:document notificationName:name];
return;
}
NSMutableDictionary *notificationDictionary = [NSMutableDictionary dictionary];
[notificationDictionary setObject:title forKey:@"title"];
[notificationDictionary setObject:description forKey:@"description"];
- [notificationDictionary setObject:window forKey:@"window"];
+ [notificationDictionary setObject:document forKey:@"document"];
[notificationDictionary setObject:name forKey:@"name"];
- [notificationDictionary setObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:[window windowNumber]] forKey:@"notificationWindow"] forKey:@"clickContext"];
+ [notificationDictionary setObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInteger:[document hash]] forKey:@"notificationDocumentHash"] forKey:@"clickContext"];
[self performSelector:@selector(notifyWithObject:) withObject:notificationDictionary afterDelay:0.1];
}
@@ -112,7 +114,7 @@ static SPGrowlController *sharedGrowlController = nil;
{
[self notifyWithTitle:[notificationDictionary objectForKey:@"title"]
description:[notificationDictionary objectForKey:@"description"]
- window:[notificationDictionary objectForKey:@"window"]
+ document:[notificationDictionary objectForKey:@"document"]
notificationName:[notificationDictionary objectForKey:@"name"]
iconData:nil
priority:0
@@ -123,13 +125,17 @@ static SPGrowlController *sharedGrowlController = nil;
/**
* Posts a Growl notification using the supplied details and effectively ignoring the default values.
*/
-- (void)notifyWithTitle:(NSString *)title description:(NSString *)description window:(NSWindow *)window notificationName:(NSString *)name iconData:(NSData *)data priority:(NSInteger)priority isSticky:(BOOL)sticky clickContext:(id)clickContext
+- (void)notifyWithTitle:(NSString *)title description:(NSString *)description document:(TableDocument *)document notificationName:(NSString *)name iconData:(NSData *)data priority:(NSInteger)priority isSticky:(BOOL)sticky clickContext:(id)clickContext
{
BOOL postNotification = YES;
- // Don't post the notification if the notification window is key and order front
+ // Don't post the notification if the notification document is frontmost
// as that suggests the user is already viewing the notification result.
- if ([window isKeyWindow]) postNotification = NO;
+ if ([[document parentWindow] isKeyWindow]
+ && [[[document parentTabViewItem] tabView] selectedTabViewItem] == [document parentTabViewItem])
+ {
+ postNotification = NO;
+ }
// If a timing notification name exists, check to see if it matches the notification name;
// if it does, and the time exceeds the threshold, display the notification even for
@@ -158,11 +164,20 @@ static SPGrowlController *sharedGrowlController = nil;
*/
- (void)growlNotificationWasClicked:(NSDictionary *)clickContext
{
- if (clickContext && [clickContext objectForKey:@"notificationWindow"]) {
- NSWindow *targetWindow = [NSApp windowWithWindowNumber:[[clickContext objectForKey:@"notificationWindow"] integerValue]];
- if (targetWindow) {
- [NSApp activateIgnoringOtherApps:YES];
- [targetWindow makeKeyAndOrderFront:self];
+ if (clickContext && [clickContext objectForKey:@"notificationDocumentHash"]) {
+ NSUInteger documentHash = [[clickContext objectForKey:@"notificationDocumentHash"] unsignedIntegerValue];
+
+ // Loop through the windows, looking for the document
+ for (NSWindow *eachWindow in [NSApp orderedWindows]) {
+ if ([[eachWindow windowController] isKindOfClass:[SPWindowController class]]) {
+ for (TableDocument *eachDocument in [[eachWindow windowController] documents]) {
+ if ([eachDocument hash] == documentHash) {
+ [NSApp activateIgnoringOtherApps:YES];
+ [eachDocument makeKeyDocument];
+ return;
+ }
+ }
+ }
}
}
}
diff --git a/Source/SPHistoryController.m b/Source/SPHistoryController.m
index b8128a0f..421569e7 100644
--- a/Source/SPHistoryController.m
+++ b/Source/SPHistoryController.m
@@ -65,6 +65,7 @@
- (void) dealloc
{
+NSLog(@"history is dealloc'd");
[[NSNotificationCenter defaultCenter] removeObserver:self];
[tableContentStates release];
[history release];
diff --git a/Source/SPNavigatorController.m b/Source/SPNavigatorController.m
index 8261ec2b..7e2ae14d 100644
--- a/Source/SPNavigatorController.m
+++ b/Source/SPNavigatorController.m
@@ -326,8 +326,8 @@ static SPNavigatorController *sharedNavigatorController = nil;
// Detect if more than one connection windows with the connectionID are open.
// If so, don't remove it.
- if ([[[NSDocumentController sharedDocumentController] documents] count]) {
- for(id doc in [[NSDocumentController sharedDocumentController] documents]) {
+ if ([[NSApp delegate] frontDocument]) {
+ for(id doc in [[NSApp delegate] orderedDocuments]) {
if(![[doc valueForKeyPath:@"mySQLConnection"] isConnected]) continue;
if([[doc connectionID] isEqualToString:connectionID])
docCounter++;
@@ -384,7 +384,7 @@ static SPNavigatorController *sharedNavigatorController = nil;
NSArray *pathArray = [[[parentKeys objectAtIndex:0] description] componentsSeparatedByString:SPUniqueSchemaDelimiter];
if([pathArray count] > 1) {
- TableDocument *doc = [[NSDocumentController sharedDocumentController] currentDocument];
+ TableDocument *doc = [[NSApp delegate] frontDocument];
if([doc isWorking]) {
[SPTooltip showWithObject:NSLocalizedString(@"Active connection window is busy. Please wait and try again.", @"active connection window is busy. please wait and try again. tooltip")
atLocation:pos
@@ -432,7 +432,7 @@ static SPNavigatorController *sharedNavigatorController = nil;
}
- if (doc && [doc isKindOfClass:[TableDocument class]] && [[[NSDocumentController sharedDocumentController] documents] count]) {
+ if (doc && [doc isKindOfClass:[TableDocument class]]) {
id theConnection = [doc valueForKeyPath:@"mySQLConnection"];
@@ -585,8 +585,7 @@ static SPNavigatorController *sharedNavigatorController = nil;
{
// Reset everything for current active doc connection
- if (![[[NSDocumentController sharedDocumentController] documents] count]) return;
- id doc = [[NSDocumentController sharedDocumentController] currentDocument];
+ id doc = [[NSApp delegate] frontDocument];
if(!doc) return;
NSString *connectionID = [doc connectionID];
if(!connectionID || [connectionID length] < 2) return;
@@ -743,8 +742,8 @@ static SPNavigatorController *sharedNavigatorController = nil;
[searchField setStringValue:@""];
}
- if ([[[NSDocumentController sharedDocumentController] documents] count]) {
- TableDocument *doc = [[NSDocumentController sharedDocumentController] currentDocument];
+ TableDocument *doc = [[NSApp delegate] frontDocument];
+ if (doc) {
NSMutableString *key = [NSMutableString string];
[key setString:[doc connectionID]];
if([doc database] && [(NSString*)[doc database] length]){
diff --git a/Source/SPPrintController.m b/Source/SPPrintController.m
index d12f764f..b8f323c4 100644
--- a/Source/SPPrintController.m
+++ b/Source/SPPrintController.m
@@ -44,7 +44,7 @@
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
{
// Because we need the webFrame loaded (for preview), we've moved the actual printing here
- NSPrintInfo *printInfo = [self printInfo];
+ NSPrintInfo *printInfo = [NSPrintInfo sharedPrintInfo];
NSSize paperSize = [printInfo paperSize];
NSRect printableRect = [printInfo imageablePageBounds];
@@ -89,7 +89,7 @@
[op setPrintPanel:printPanel];
- [op runOperationModalForWindow:tableWindow
+ [op runOperationModalForWindow:[self parentWindow]
delegate:self
didRunSelector:nil
contextInfo:nil];
@@ -129,7 +129,7 @@
[[buttons objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask];
[[buttons objectAtIndex:1] setKeyEquivalent:@"\r"];
- [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(printWarningDidEnd:returnCode:contextInfo:) contextInfo:NULL];
+ [alert beginSheetModalForWindow:[self parentWindow] modalDelegate:self didEndSelector:@selector(printWarningDidEnd:returnCode:contextInfo:) contextInfo:NULL];
return;
}
@@ -196,7 +196,7 @@
- (void)generateHTMLForPrinting
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
+
// Set up template engine with your chosen matcher
MGTemplateEngine *engine = [MGTemplateEngine templateEngine];
diff --git a/Source/SPProcessListController.m b/Source/SPProcessListController.m
index dad68d18..83b9ae54 100644
--- a/Source/SPProcessListController.m
+++ b/Source/SPProcessListController.m
@@ -74,7 +74,7 @@
*/
- (void)awakeFromNib
{
- [[self window] setTitle:[NSString stringWithFormat:@"%@ %@", [[[NSDocumentController sharedDocumentController] currentDocument] name], NSLocalizedString(@"Server Processes", @"server processes window title")]];
+ [[self window] setTitle:[NSString stringWithFormat:@"%@ %@", [[[NSApp delegate] frontDocument] name], NSLocalizedString(@"Server Processes", @"server processes window title")]];
[self setWindowFrameAutosaveName:@"ProcessList"];
@@ -367,7 +367,7 @@
{
if (returnCode == NSOKButton) {
if ([processesFiltered count] > 0) {
- NSMutableString *processesString = [NSMutableString stringWithFormat:@"# MySQL server proceese for %@\n\n", [(TableDocument *)[[NSApp mainWindow] delegate] host]];
+ NSMutableString *processesString = [NSMutableString stringWithFormat:@"# MySQL server proceese for %@\n\n", [[[NSApp delegate] frontDocument] host]];
for (NSDictionary *process in processesFiltered)
{
diff --git a/Source/SPQueryController.m b/Source/SPQueryController.m
index c8906477..538e880b 100644
--- a/Source/SPQueryController.m
+++ b/Source/SPQueryController.m
@@ -594,7 +594,7 @@ static SPQueryController *sharedQueryController = nil;
{
// Check for multiple instance of the same document.
// Remove it if only one instance was registerd.
- NSArray *allDocs = [[NSDocumentController sharedDocumentController] documents];
+ NSArray *allDocs = [[NSApp delegate] orderedDocuments];
NSMutableArray *allURLs = [NSMutableArray array];
for(id doc in allDocs) {
if (![doc fileURL]) continue;
@@ -635,7 +635,7 @@ static SPQueryController *sharedQueryController = nil;
[historyContainer setObject:historyArray forKey:[fileURL absoluteString]];
// Inform all opened documents to update the history list
- for(id doc in [[NSDocumentController sharedDocumentController] documents])
+ for(id doc in [[NSApp delegate] orderedDocuments])
if([[doc valueForKeyPath:@"customQueryInstance"] respondsToSelector:@selector(historyItemsHaveBeenUpdated:)])
[[doc valueForKeyPath:@"customQueryInstance"] performSelectorOnMainThread:@selector(historyItemsHaveBeenUpdated:) withObject:self waitUntilDone:NO];
diff --git a/Source/SPQueryFavoriteManager.h b/Source/SPQueryFavoriteManager.h
index c803e565..c3b93ab5 100644
--- a/Source/SPQueryFavoriteManager.h
+++ b/Source/SPQueryFavoriteManager.h
@@ -25,7 +25,7 @@
#import <Cocoa/Cocoa.h>
-@class BWAnchoredButtonBar, CMTextView;
+@class BWAnchoredButtonBar, CMTextView, TableDocument;
@interface NSObject (SPQueryFavoriteManagerDelegate)
@@ -38,6 +38,7 @@
NSUserDefaults *prefs;
NSURL *delegatesFileURL;
+ TableDocument *tableDocumentInstance;
IBOutlet NSPopUpButton *encodingPopUp;
IBOutlet NSTableView *favoritesTableView;
IBOutlet NSTextField *favoriteNameTextField;
diff --git a/Source/SPQueryFavoriteManager.m b/Source/SPQueryFavoriteManager.m
index 91a8d90e..40648f91 100644
--- a/Source/SPQueryFavoriteManager.m
+++ b/Source/SPQueryFavoriteManager.m
@@ -59,7 +59,8 @@
NSLog(@"Query Favorite Manger was called without a delegate.");
return nil;
}
- delegatesFileURL = [[managerDelegate valueForKeyPath:@"tableDocumentInstance"] fileURL];
+ tableDocumentInstance = [managerDelegate valueForKeyPath:@"tableDocumentInstance"];
+ delegatesFileURL = [tableDocumentInstance fileURL];
}
return self;
@@ -181,7 +182,7 @@
*/
- (id)customQueryInstance
{
- return [[[NSApp mainWindow] delegate] valueForKey:@"customQueryInstance"];
+ return [tableDocumentInstance valueForKey:@"customQueryInstance"];
}
#pragma mark -
@@ -382,7 +383,7 @@
[prefs setObject:[self queryFavoritesForFileURL:nil] forKey:SPQueryFavorites];
// Inform all opened documents to update the query favorites list
- for(id doc in [[NSDocumentController sharedDocumentController] documents])
+ for(id doc in [[NSApp delegate] orderedDocuments])
if([[doc valueForKeyPath:@"customQueryInstance"] respondsToSelector:@selector(queryFavoritesHaveBeenUpdated:)])
[[doc valueForKeyPath:@"customQueryInstance"] queryFavoritesHaveBeenUpdated:self];
diff --git a/Source/SPSSHTunnel.m b/Source/SPSSHTunnel.m
index 6d9e64ca..59acb9e0 100644
--- a/Source/SPSSHTunnel.m
+++ b/Source/SPSSHTunnel.m
@@ -72,6 +72,8 @@
}
parentWindow = nil;
+ sshQuestionDialog = nil;
+ sshPasswordDialog = nil;
password = nil;
keychainName = nil;
keychainAccount = nil;
@@ -102,6 +104,11 @@
*/
- (void)setParentWindow:(NSWindow *)theWindow
{
+
+ // As this object is not a NSWindowController, use manual top-level nib item management
+ if (sshQuestionDialog) [sshQuestionDialog release], sshQuestionDialog = nil;
+ if (sshPasswordDialog) [sshPasswordDialog release], sshPasswordDialog = nil;
+
parentWindow = theWindow;
if (![NSBundle loadNibNamed:@"SSHQuestionDialog" owner:self]) {
NSLog(@"SSH query dialog could not be loaded; SSH tunnels will not function correctly.");
@@ -646,6 +653,10 @@
if (password) [password release];
if (keychainName) [keychainName release];
if (keychainAccount) [keychainAccount release];
+
+ // As this object is not a NSWindowController, use manual top-level nib item management
+ if (sshQuestionDialog) [sshQuestionDialog release], sshQuestionDialog = nil;
+ if (sshPasswordDialog) [sshPasswordDialog release], sshPasswordDialog = nil;
[super dealloc];
}
diff --git a/Source/SPServerVariablesController.m b/Source/SPServerVariablesController.m
index 37868f10..7243298d 100644
--- a/Source/SPServerVariablesController.m
+++ b/Source/SPServerVariablesController.m
@@ -165,7 +165,7 @@
{
if (returnCode == NSOKButton) {
if ([variablesFiltered count] > 0) {
- NSMutableString *variablesString = [NSMutableString stringWithFormat:@"# MySQL server variables for %@\n\n", [(TableDocument *)[[NSApp mainWindow] delegate] host]];
+ NSMutableString *variablesString = [NSMutableString stringWithFormat:@"# MySQL server variables for %@\n\n", [[[NSApp delegate] frontDocument] host]];
for (NSDictionary *variable in variablesFiltered)
{
diff --git a/Source/SPTableData.m b/Source/SPTableData.m
index feb77848..117f1a05 100644
--- a/Source/SPTableData.m
+++ b/Source/SPTableData.m
@@ -293,14 +293,15 @@
NSDictionary *columnData;
NSEnumerator *enumerator;
+ [columns removeAllObjects];
+ [columnNames removeAllObjects];
+ [constraints removeAllObjects];
+
if( [tableListInstance tableType] == SPTableTypeTable || [tableListInstance tableType] == SPTableTypeView ) {
tableData = [self informationForTable:[tableListInstance tableName]];
}
if (tableData == nil ) {
- [columns removeAllObjects];
- [columnNames removeAllObjects];
- [constraints removeAllObjects];
return FALSE;
}
diff --git a/Source/SPTableRelations.h b/Source/SPTableRelations.h
index 5b1db7dd..40ac2e79 100644
--- a/Source/SPTableRelations.h
+++ b/Source/SPTableRelations.h
@@ -33,7 +33,6 @@
IBOutlet id tableDataInstance;
IBOutlet id tableList;
- IBOutlet id tableWindow;
IBOutlet NSButton *addRelationButton;
IBOutlet NSButton *removeRelationButton;
diff --git a/Source/SPTableRelations.m b/Source/SPTableRelations.m
index 586f341d..e37d453d 100644
--- a/Source/SPTableRelations.m
+++ b/Source/SPTableRelations.m
@@ -186,7 +186,7 @@
[self selectReferenceTable:nil];
[NSApp beginSheet:addRelationPanel
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:nil
contextInfo:nil];
@@ -214,7 +214,7 @@
[[buttons objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask];
[[buttons objectAtIndex:1] setKeyEquivalent:@"\r"];
- [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:@"removeRelation"];
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:@"removeRelation"];
}
}
diff --git a/Source/SPTableTriggers.h b/Source/SPTableTriggers.h
index 8e97908a..c03b5f2c 100644
--- a/Source/SPTableTriggers.h
+++ b/Source/SPTableTriggers.h
@@ -33,7 +33,6 @@
IBOutlet id tableDataInstance;
IBOutlet id tableList;
- IBOutlet id tableWindow;
IBOutlet NSButton *addTriggerButton;
IBOutlet NSButton *removeTriggerButton;
diff --git a/Source/SPTableTriggers.m b/Source/SPTableTriggers.m
index 7a7cf8ac..e3cdda63 100644
--- a/Source/SPTableTriggers.m
+++ b/Source/SPTableTriggers.m
@@ -180,7 +180,7 @@
- (IBAction)addTrigger:(id)sender
{
[NSApp beginSheet:addTriggerPanel
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:nil
contextInfo:nil];
@@ -208,7 +208,7 @@
[[buttons objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask];
[[buttons objectAtIndex:1] setKeyEquivalent:@"\r"];
- [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:@"removeTrigger"];
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:@"removeTrigger"];
}
}
diff --git a/Source/SPTableView.m b/Source/SPTableView.m
index 4acf4879..58e2206e 100644
--- a/Source/SPTableView.m
+++ b/Source/SPTableView.m
@@ -37,14 +37,18 @@
- (NSMenu *)menuForEvent:(NSEvent *)event
{
+ // Try to retrieve a reference to the table document (assuming this is frontmost tab)
+ TableDocument *parentTableDocument = nil;
+ if ([[[[[self window] delegate] class] description] isEqualToString:@"SPWindowController"]) {
+ parentTableDocument = [[[self window] delegate] selectedTableDocument];
+ }
+
// If TableDocument is performing a task suppress any context menu
- if ([[[[[self window] delegate] class] description] isEqualToString:@"TableDocument"]
- && [[[self window] delegate] isWorking])
+ if (parentTableDocument && [parentTableDocument isWorking])
return nil;
// Check to see whether any edits-in-progress need to be saved before changing selections
- if ([[[[[self window] delegate] class] description] isEqualToString:@"TableDocument"]
- && ![[[self window] delegate] couldCommitCurrentViewActions])
+ if (parentTableDocument && ![parentTableDocument couldCommitCurrentViewActions])
return nil;
// If more than one row is selected only returns the default contextual menu
diff --git a/Source/SPWindowController.h b/Source/SPWindowController.h
new file mode 100644
index 00000000..00754848
--- /dev/null
+++ b/Source/SPWindowController.h
@@ -0,0 +1,46 @@
+//
+// $Id$
+//
+// SPWindowController.h
+// sequel-pro
+//
+// Created by Rowan Beentje on May 16, 2010
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import <Cocoa/Cocoa.h>
+@class PSMTabBarControl, TableDocument;
+
+@interface SPWindowController : NSWindowController <NSUserInterfaceValidations>
+{
+ IBOutlet PSMTabBarControl *tabBar;
+ IBOutlet NSTabView *tabView;
+
+ NSMenuItem *closeWindowMenuItem;
+ NSMenuItem *closeTabMenuItem;
+
+ NSMutableArray *managedDatabaseConnections;
+}
+
+// Database connection management
+- (IBAction) addNewConnection:(id)sender;
+- (TableDocument *) selectedTableDocument;
+- (void) updateAllTabTitles:(id)sender;
+- (IBAction)closeTab:(id)sender;
+- (NSArray *)documents;
+
+@end
diff --git a/Source/SPWindowController.m b/Source/SPWindowController.m
new file mode 100644
index 00000000..3c8b9be7
--- /dev/null
+++ b/Source/SPWindowController.m
@@ -0,0 +1,372 @@
+//
+// $Id$
+//
+// SPWindowController.m
+// sequel-pro
+//
+// Created by Rowan Beentje on May 16, 2010
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPWindowController.h"
+#import "SPConstants.h"
+#import "TableDocument.h"
+#import <PSMTabBar/PSMTabBarControl.h>
+#import <PSMTabBar/PSMTabStyle.h>
+
+@implementation SPWindowController
+
+/**
+ * awakeFromNib
+ */
+- (void) awakeFromNib
+{
+
+ // Disable automatic cascading - this occurs before the size is set, so let the app
+ // controller apply cascading after frame autosaving.
+ [self setShouldCascadeWindows:NO];
+
+ // Initialise the managed database connections array
+ managedDatabaseConnections = [[NSMutableArray alloc] init];
+
+ // Set up the tab bar
+ [tabBar setStyleNamed:@"Metal"];
+ [tabBar setCanCloseOnlyTab:NO];
+ [tabBar setHideForSingleTab:YES];
+ [tabBar setShowAddTabButton:YES];
+ [tabBar setSizeCellsToFit:NO];
+ [tabBar setCellMinWidth:100];
+ [tabBar setCellMaxWidth:250];
+ [tabBar setCellOptimumWidth:250];
+
+ // hook up add tab button
+ [[tabBar addTabButton] setTarget:self];
+ [[tabBar addTabButton] setAction:@selector(addNewConnection:)];
+
+ // Retrieve references to the 'Close Window' and 'Close Tab' menus. These are updated as window focus changes.
+ closeWindowMenuItem = [[[[NSApp mainMenu] itemWithTag:SPMainMenuFile] submenu] itemWithTag:1003];
+ closeTabMenuItem = [[[[NSApp mainMenu] itemWithTag:SPMainMenuFile] submenu] itemWithTag:1103];
+
+ // Add a new connection to the new window
+ [self addNewConnection:self];
+}
+
+/**
+ * Deallocation
+ */
+- (void) dealloc
+{
+ [managedDatabaseConnections release];
+}
+
+#pragma mark -
+#pragma mark Database connection management
+
+/**
+ * Add a new database connection to the window, in a tab view.
+ */
+- (IBAction) addNewConnection:(id)sender
+{
+
+ // Create a new database connection view
+ TableDocument *newTableDocument = [[TableDocument alloc] init];
+ [newTableDocument setParentWindowController:self];
+ [newTableDocument setParentWindow:[self window]];
+
+ // Set up a new tab with the connection view as the identifier, add the view, and add it to the tab view
+ NSTabViewItem *newItem = [[[NSTabViewItem alloc] initWithIdentifier:newTableDocument] autorelease];
+ [newItem setView:[newTableDocument parentView]];
+ [tabView addTabViewItem:newItem];
+ [tabView selectTabViewItem:newItem];
+ [newTableDocument setParentTabViewItem:newItem];
+
+ // Tell the new database connection view to set up the window and update titles
+ [newTableDocument didBecomeActiveTabInWindow];
+ [newTableDocument updateWindowTitle:self];
+
+ [newTableDocument release];
+}
+
+/**
+ * Retrieve the currently connection view in the window.
+ */
+- (TableDocument *) selectedTableDocument
+{
+ return [[tabView selectedTabViewItem] identifier];
+}
+
+/**
+ * Ask all the connection views to update their titles.
+ * As tab titles depend on the currently selected tab, changes
+ * within each tab may require other tabs to update their titles.
+ * If the sender is a tab, that tab is skipped when updating titles.
+ */
+- (void) updateAllTabTitles:(id)sender
+{
+ for (NSTabViewItem *eachItem in [tabView tabViewItems]) {
+ TableDocument *eachDocument = [eachItem identifier];
+ if (eachDocument != sender) [eachDocument updateWindowTitle:self];
+ }
+}
+
+
+/**
+ * Close the current tab, or if it's the last in the window, the window.
+ */
+- (IBAction)closeTab:(id)sender
+{
+
+ // Return if the frontmost tab shouldn't be closed
+ TableDocument *frontDocument = [[tabView selectedTabViewItem] identifier];
+ if (![frontDocument parentTabShouldClose]) return NO;
+
+ // If there are multiple tabs, close the front tab.
+ if ([tabView numberOfTabViewItems] > 1) {
+ [tabView removeTabViewItem:[tabView selectedTabViewItem]];
+ } else {
+ [[self window] performClose:self];
+ }
+}
+
+/**
+ * Retrieve the documents associated with this window.
+ */
+- (NSArray *)documents
+{
+ NSMutableArray *documentsArray = [NSMutableArray array];
+ for (NSTabViewItem *eachItem in [tabView tabViewItems]) {
+ [documentsArray addObject:[eachItem identifier]];
+ }
+ return documentsArray;
+}
+
+#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
+{
+ TableDocument *currentlySelectedDocument = [[tabView selectedTabViewItem] identifier];
+ [currentlySelectedDocument willResignActiveTabInWindow];
+}
+
+/**
+ * Called when a tab item was selected.
+ */
+- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
+{
+ TableDocument *theDocument = [tabViewItem identifier];
+ [theDocument didBecomeActiveTabInWindow];
+ if ([[self window] isKeyWindow]) [theDocument tabDidBecomeKey];
+ [self updateAllTabTitles:self];
+}
+
+/**
+ * Called to determine whether a tab view item can be closed
+ */
+- (BOOL)tabView:(NSTabView *)aTabView shouldCloseTabViewItem:(NSTabViewItem *)tabViewItem
+{
+ TableDocument *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
+{
+ TableDocument *theDocument = [tabViewItem identifier];
+ [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
+{
+ TableDocument *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
+ [[[draggedFromWindow windowController] selectedTableDocument] didBecomeActiveTabInWindow];
+
+ // Update the item's document's window
+ [draggedDocument willResignActiveTabInWindow];
+ [draggedDocument setParentWindow:[tabBarControl window]];
+ [draggedDocument didBecomeActiveTabInWindow];
+ }
+}
+
+- (void)tabView:(NSTabView *)aTabView closeWindowForLastTabViewItem:(NSTabViewItem *)tabViewItem
+{
+ [[aTabView window] close];
+}
+
+#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
+{
+ for (NSTabViewItem *eachItem in [tabView tabViewItems]) {
+ TableDocument *eachDocument = [eachItem identifier];
+ if (![eachDocument parentTabShouldClose]) return NO;
+ }
+
+ 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
+{
+ TableDocument *selectedTab = [[tabView selectedTabViewItem] identifier];
+ [selectedTab 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]) {
+ TableDocument *eachDocument = [eachItem identifier];
+ [eachDocument tabDidResize];
+ }
+}
+
+#pragma mark -
+#pragma mark First responder forwarding to active tab
+
+/**
+ * Delegate unrecognised methods to the selected table document, thanks to the magic
+ * of NSInvocation (see forwardInvocation: docs for background). Must be paired
+ * with methodSignationForSelector:.
+ */
+- (void) forwardInvocation:(NSInvocation *)theInvocation
+{
+ TableDocument *frontDocument = [[tabView selectedTabViewItem] identifier];
+ SEL theSelector = [theInvocation selector];
+ if (![frontDocument respondsToSelector:theSelector]) [self doesNotRecognizeSelector:theSelector];
+ [theInvocation invokeWithTarget:frontDocument];
+}
+
+/**
+ * Return the correct method signatures for the selected table document if
+ * NSObject doesn't implement the requested methods.
+ */
+- (NSMethodSignature *) methodSignatureForSelector:(SEL)theSelector
+{
+ NSMethodSignature *defaultSignature = [super methodSignatureForSelector:theSelector];
+ if (defaultSignature) return defaultSignature;
+
+ return [[[tabView selectedTabViewItem] identifier] methodSignatureForSelector:theSelector];
+}
+
+/**
+ * Override the default repondsToSelector:, returning true if either NSObject
+ * or the selected table document supports the selector.
+ */
+- (BOOL) respondsToSelector:(SEL)theSelector
+{
+ return ([super respondsToSelector:theSelector] || [[[tabView selectedTabViewItem] identifier] respondsToSelector:theSelector]);
+}
+
+/**
+ * Override the default performSelector:, again either using NSObject defaults
+ * or performing the selector on the selected table document.
+ */
+- (id) performSelector:(SEL)theSelector
+{
+ if ([super respondsToSelector:theSelector]) return [super performSelector:theSelector];
+
+ TableDocument *frontDocument = [[tabView selectedTabViewItem] identifier];
+ if (![frontDocument respondsToSelector:theSelector]) [self doesNotRecognizeSelector:theSelector];
+ return [frontDocument performSelector:theSelector];
+}
+
+/**
+ * Override the default performSelector:withObject: - see performSelector:
+ */
+- (id) performSelector:(SEL)theSelector withObject:(id)theObject
+{
+ if ([super respondsToSelector:theSelector]) return [super performSelector:theSelector withObject:theObject];
+
+ TableDocument *frontDocument = [[tabView selectedTabViewItem] identifier];
+ if (![frontDocument respondsToSelector:theSelector]) [self doesNotRecognizeSelector:theSelector];
+
+ return [frontDocument performSelector:theSelector withObject:theObject];
+}
+
+@end \ No newline at end of file
diff --git a/Source/TableContent.h b/Source/TableContent.h
index 9b2e953e..35bd6c31 100644
--- a/Source/TableContent.h
+++ b/Source/TableContent.h
@@ -40,7 +40,6 @@
IBOutlet SPTableInfo *tableInfoInstance;
IBOutlet SPHistoryController *spHistoryControllerInstance;
- IBOutlet id tableWindow;
IBOutlet CMCopyTable *tableContentView;
IBOutlet NSPopUpButton *fieldField;
IBOutlet id compareField;
@@ -72,6 +71,7 @@
BOOL _mainNibLoaded;
BOOL isWorking;
pthread_mutex_t tableValuesLock;
+ NSMutableArray *nibObjectsToRelease;
NSString *selectedTable, *usedQuery;
SPDataStorage *tableValues;
diff --git a/Source/TableContent.m b/Source/TableContent.m
index 3e9c933a..cf639b72 100644
--- a/Source/TableContent.m
+++ b/Source/TableContent.m
@@ -63,6 +63,7 @@
_mainNibLoaded = NO;
isWorking = NO;
pthread_mutex_init(&tableValuesLock, NULL);
+ nibObjectsToRelease = [[NSMutableArray alloc] init];
tableValues = [[SPDataStorage alloc] init];
tableRowsCount = 0;
@@ -138,10 +139,17 @@
// Set the table content view's vertical gridlines if required
[tableContentView setGridStyleMask:([prefs boolForKey:SPDisplayTableViewVerticalGridlines]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone];
- // Add the pagination view to the content area with ourselves as the owner
- if (![NSBundle loadNibNamed:@"ContentPaginationView" owner:self]) {
+ // Load the pagination view, keeping references to the top-level objects for later release
+ NSArray *paginationViewTopLevelObjects = nil;
+ NSNib *nibLoader = [[NSNib alloc] initWithNibNamed:@"ContentPaginationView" bundle:[NSBundle mainBundle]];
+ if (![nibLoader instantiateNibWithOwner:self topLevelObjects:&paginationViewTopLevelObjects]) {
NSLog(@"Content pagination nib could not be loaded; pagination will not function correctly.");
+ } else {
+ [nibObjectsToRelease addObjectsFromArray:paginationViewTopLevelObjects];
}
+ [nibLoader release];
+
+ // Add the pagination view to the content area
NSRect paginationViewFrame = [paginationView frame];
NSRect paginationButtonFrame = [paginationButton frame];
paginationViewHeight = paginationViewFrame.size.height;
@@ -464,7 +472,7 @@
}
// Store the current first responder so filter field doesn't steal focus
- id currentFirstResponder = [tableWindow firstResponder];
+ id currentFirstResponder = [[tableDocumentInstance parentWindow] firstResponder];
// Enable and initialize filter fields (with tags for position of menu item and field position)
[fieldField setEnabled:YES];
@@ -505,7 +513,7 @@
if ([prefs boolForKey:SPLimitResults]) contentPage = pageToRestore;
// Restore first responder
- [tableWindow makeFirstResponder:currentFirstResponder];
+ [[tableDocumentInstance parentWindow] makeFirstResponder:currentFirstResponder];
// Set the state of the table buttons
[addButton setEnabled:enableInteraction];
@@ -1213,19 +1221,19 @@
paginationViewFrame.size.height = paginationViewHeight;
[paginationButton setState:NSOnState];
[paginationButton setImage:[NSImage imageNamed:@"button_action"]];
- [tableWindow makeFirstResponder:paginationPageField];
+ [[tableDocumentInstance parentWindow] makeFirstResponder:paginationPageField];
} else {
if (paginationViewFrame.size.height == 0) return;
paginationViewFrame.size.height = 0;
[paginationButton setState:NSOffState];
[paginationButton setImage:[NSImage imageNamed:@"button_pagination"]];
- if ([tableWindow firstResponder] == paginationPageField
- || ([[tableWindow firstResponder] respondsToSelector:@selector(superview)]
- && [(id)[tableWindow firstResponder] superview]
- && [[(id)[tableWindow firstResponder] superview] respondsToSelector:@selector(superview)]
- && [[(id)[tableWindow firstResponder] superview] superview] == paginationPageField))
+ if ([[tableDocumentInstance parentWindow] firstResponder] == paginationPageField
+ || ([[[tableDocumentInstance parentWindow] firstResponder] respondsToSelector:@selector(superview)]
+ && [(id)[[tableDocumentInstance parentWindow] firstResponder] superview]
+ && [[(id)[[tableDocumentInstance parentWindow] firstResponder] superview] respondsToSelector:@selector(superview)]
+ && [[(id)[[tableDocumentInstance parentWindow] firstResponder] superview] superview] == paginationPageField))
{
- [tableWindow makeFirstResponder:nil];
+ [[tableDocumentInstance parentWindow] makeFirstResponder:nil];
}
}
@@ -1321,7 +1329,7 @@
if ( [tableContentView numberOfSelectedRows] < 1 )
return;
if ( [tableContentView numberOfSelectedRows] > 1 ) {
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, NSLocalizedString(@"You can only copy single rows.", @"message of panel when trying to copy multiple rows"));
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil, NSLocalizedString(@"You can only copy single rows.", @"message of panel when trying to copy multiple rows"));
return;
}
@@ -1376,7 +1384,7 @@
// return;
// cancel editing (maybe this is not the ideal method -- see xcode docs for that method)
- [tableWindow endEditingFor:nil];
+ [[tableDocumentInstance parentWindow] endEditingFor:nil];
if (![tableContentView numberOfSelectedRows])
@@ -1427,7 +1435,7 @@
[alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"Are you sure you want to delete the selected %ld rows from this table? This action cannot be undone.", @"delete rows informative message"), (long)[tableContentView numberOfSelectedRows]]];
}
- [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(removeRowSheetDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(removeRowSheetDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
}
/**
@@ -2066,7 +2074,7 @@
// Open query favorite manager
[NSApp beginSheet:[contentFilterManager window]
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:contentFilterManager
didEndSelector:nil
contextInfo:nil];
@@ -2201,7 +2209,7 @@
// If no rows have been changed, show error if appropriate.
if ( ![mySQLConnection affectedRows] && ![mySQLConnection queryErrored] ) {
if ( [prefs boolForKey:SPShowNoAffectedRowsError] ) {
- SPBeginAlertSheet(NSLocalizedString(@"Warning", @"warning"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Warning", @"warning"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
NSLocalizedString(@"The row was not written to the MySQL database. You probably haven't changed anything.\nReload the table to be sure that the row exists and use a primary key for your table.\n(This error can be turned off in the preferences.)", @"message of panel when no rows have been affected after writing to the db"));
} else {
NSBeep();
@@ -2220,7 +2228,7 @@
// New row created successfully
if ( isEditingNewRow ) {
if ( [prefs boolForKey:SPReloadAfterAddingRow] ) {
- [tableWindow endEditingFor:nil];
+ [[tableDocumentInstance parentWindow] endEditingFor:nil];
previousTableRowsCount = tableRowsCount;
[self loadTableValues];
} else {
@@ -2239,7 +2247,7 @@
// Reload table if set to - otherwise no action required.
if ( [prefs boolForKey:SPReloadAfterEditingRow] ) {
- [tableWindow endEditingFor:nil];
+ [[tableDocumentInstance parentWindow] endEditingFor:nil];
previousTableRowsCount = tableRowsCount;
[self loadTableValues];
}
@@ -2250,7 +2258,7 @@
// Report errors which have occurred
} else {
- SPBeginAlertSheet(NSLocalizedString(@"Couldn't write row", @"Couldn't write row error"), NSLocalizedString(@"Edit row", @"Edit row button"), NSLocalizedString(@"Discard changes", @"discard changes button"), nil, tableWindow, self, @selector(addRowErrorSheetDidEnd:returnCode:contextInfo:), nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Couldn't write row", @"Couldn't write row error"), NSLocalizedString(@"Edit row", @"Edit row button"), NSLocalizedString(@"Discard changes", @"discard changes button"), nil, [tableDocumentInstance parentWindow], self, @selector(addRowErrorSheetDidEnd:returnCode:contextInfo:), nil,
[NSString stringWithFormat:NSLocalizedString(@"MySQL said:\n\n%@", @"message of panel when error while adding row to db"), [mySQLConnection getLastErrorMessage]]);
return NO;
}
@@ -2267,7 +2275,7 @@
// Edit row selected - reselect the row, and start editing.
if ( returnCode == NSAlertDefaultReturn ) {
[tableContentView selectRowIndexes:[NSIndexSet indexSetWithIndex:currentlyEditingRow] byExtendingSelection:NO];
- [tableContentView performSelector:@selector(keyDown:) withObject:[NSEvent keyEventWithType:NSKeyDown location:NSMakePoint(0,0) modifierFlags:0 timestamp:0 windowNumber:[tableWindow windowNumber] context:[NSGraphicsContext currentContext] characters:nil charactersIgnoringModifiers:nil isARepeat:NO keyCode:0x24] afterDelay:0.0];
+ [tableContentView performSelector:@selector(keyDown:) withObject:[NSEvent keyEventWithType:NSKeyDown location:NSMakePoint(0,0) modifierFlags:0 timestamp:0 windowNumber:[[tableDocumentInstance parentWindow] windowNumber] context:[NSGraphicsContext currentContext] characters:nil charactersIgnoringModifiers:nil isARepeat:NO keyCode:0x24] afterDelay:0.0];
// Discard changes selected
} else {
@@ -2294,7 +2302,7 @@
- (BOOL)saveRowOnDeselect
{
// Save any edits which have been made but not saved to the table yet.
- [tableWindow endEditingFor:nil];
+ [[tableDocumentInstance parentWindow] endEditingFor:nil];
// If no rows are currently being edited, or a save is in progress, return success at once.
if (!isEditingRow || isSavingRow) return YES;
@@ -2357,7 +2365,7 @@
// When the option to not show blob or text options is set, we have a problem - we don't have
// the right values to use in the WHERE statement. Throw an error if this is the case.
if ( [prefs boolForKey:SPLoadBlobsAsNeeded] && [self tableContainsBlobOrTextColumns] ) {
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
NSLocalizedString(@"You can't hide blob and text fields when working with tables without index.", @"message of panel when trying to edit tables without index and with hidden blob/text fields"));
[keys removeAllObjects];
[tableContentView deselectAll:self];
@@ -2465,7 +2473,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, [tableDocumentInstance parentWindow], self, nil, nil,
[error objectAtIndex:1]);
}
@@ -2942,7 +2950,7 @@
[self loadTableValues];
if ([mySQLConnection queryErrored]) {
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"Couldn't sort table. MySQL said: %@", @"message of panel when sorting of table failed"), [mySQLConnection getLastErrorMessage]]);
[tableDocumentInstance endTask];
[sortPool drain];
@@ -3037,7 +3045,7 @@
MCPResult *tempResult = [mySQLConnection queryString:query];
if (![tempResult numOfRows]) {
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
NSLocalizedString(@"Couldn't load the row. Reload the table to be sure that the row exists and use a primary key for your table.", @"message of panel when loading of row failed"));
return NO;
}
@@ -3064,7 +3072,7 @@
usingEncoding:[mySQLConnection encoding]
isObjectBlob:isBlob
isEditable:YES
- withWindow:tableWindow] retain];
+ withWindow:[tableDocumentInstance parentWindow]] retain];
if (editData) {
if (!isEditingRow) {
@@ -3363,13 +3371,13 @@
NSUInteger numOfArgs = [[filter objectForKey:@"NumberOfArguments"] integerValue];
switch(numOfArgs) {
case 2:
- [tableWindow makeFirstResponder:firstBetweenField];
+ [[tableDocumentInstance parentWindow] makeFirstResponder:firstBetweenField];
break;
case 1:
- [tableWindow makeFirstResponder:argumentField];
+ [[tableDocumentInstance parentWindow] makeFirstResponder:argumentField];
break;
default:
- [tableWindow makeFirstResponder:compareField];
+ [[tableDocumentInstance parentWindow] makeFirstResponder:compareField];
}
}
}
@@ -3378,7 +3386,7 @@
// Last but not least
- (void)dealloc
-{
+{NSLog(@"content is deallocd");
[[NSNotificationCenter defaultCenter] removeObserver:self];
[tableValues release];
diff --git a/Source/TableDocument.h b/Source/TableDocument.h
index b3cbb6e7..539d14b2 100644
--- a/Source/TableDocument.h
+++ b/Source/TableDocument.h
@@ -29,12 +29,12 @@
#import <MCPKit/MCPKit.h>
#import <WebKit/WebKit.h>
-@class SPConnectionController, SPProcessListController, SPServerVariablesController, SPUserManager;
+@class SPConnectionController, SPProcessListController, SPServerVariablesController, SPUserManager, SPWindowController;
/**
* The TableDocument class controls the primary database view window.
*/
-@interface TableDocument : NSDocument
+@interface TableDocument : NSObject <NSUserInterfaceValidations>
{
// IBOutlets
IBOutlet id tablesListInstance;
@@ -58,7 +58,7 @@
IBOutlet NSSearchField *listFilterField;
- IBOutlet NSWindow *tableWindow;
+ IBOutlet NSView *parentView;
IBOutlet id titleAccessoryView;
IBOutlet id titleImageView;
@@ -135,12 +135,12 @@
NSString *selectedDatabase;
NSString *mySQLVersion;
NSUserDefaults *prefs;
+ NSMutableArray *nibObjectsToRelease;
NSMenu *selectEncodingMenu;
BOOL _supportsEncoding;
NSString *_encoding;
BOOL _encodingViaLatin1;
- BOOL _shouldOpenConnectionAutomatically;
BOOL _isConnected;
NSInteger _isWorkingLevel;
BOOL _mainNibLoaded;
@@ -168,6 +168,7 @@
NSString *queryEditorInitString;
+ NSURL *spfFileURL;
NSDictionary *spfSession;
NSMutableDictionary *spfPreferences;
NSMutableDictionary *spfDocData;
@@ -177,8 +178,17 @@
NSThread *printThread;
id statusValues;
+
+ // Properties
+ SPWindowController *parentWindowController;
+ NSWindow *parentWindow;
+ NSTabViewItem *parentTabViewItem;
+ BOOL isProcessing;
}
+@property (readwrite, assign) SPWindowController *parentWindowController;
+@property (readwrite, assign) NSTabViewItem *parentTabViewItem;
+
- (BOOL)isUntitled;
- (BOOL)couldCommitCurrentViewActions;
@@ -187,8 +197,6 @@
// Connection callback and methods
- (void)setConnection:(MCPConnection *)theConnection;
- (MCPConnection *) getConnection;
-- (void)setShouldAutomaticallyConnect:(BOOL)shouldAutomaticallyConnect;
-- (BOOL)shouldAutomaticallyConnect;
- (void)setKeychainID:(NSString *)theID;
// Database methods
@@ -271,6 +279,7 @@
- (IBAction)toggleNavigator:(id)sender;
// Accessor methods
+- (NSView *)parentView;
- (NSString *)host;
- (NSString *)name;
- (NSString *)database;
@@ -278,7 +287,6 @@
- (NSString *)port;
- (NSString *)mySQLVersion;
- (NSString *)user;
-- (NSString *)displaySPName;
- (NSString *)keyChainID;
- (NSString *)connectionID;
@@ -288,7 +296,7 @@
- (void)applicationWillTerminate:(NSNotification *)notification;
// Menu methods
-- (BOOL)validateMenuItem:(NSMenuItem *)anItem;
+- (BOOL)validateMenuItem:(NSMenuItem *)menuItem;
- (IBAction)saveConnectionSheet:(id)sender;
- (IBAction)import:(id)sender;
- (IBAction)importFromClipboard:(id)sender;
@@ -309,9 +317,23 @@
- (void)clearStatusIcon;
// Toolbar methods
+- (void)updateWindowTitle:(id)sender;
- (void)setupToolbar;
- (NSString *)selectedToolbarItemIdentifier;
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag;
- (void)updateChooseDatabaseToolbarItemWidth;
+// Tab methods
+- (void)makeKeyDocument;
+- (BOOL)parentTabShouldClose;
+- (void)parentTabDidClose;
+- (void)willResignActiveTabInWindow;
+- (void)didBecomeActiveTabInWindow;
+- (void)tabDidBecomeKey;
+- (void)tabDidResize;
+- (void)setIsProcessing:(BOOL)value;
+- (BOOL)isProcessing;
+- (void)setParentWindow:(NSWindow *)aWindow;
+- (NSWindow *)parentWindow;
+
@end
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
diff --git a/Source/TableDump.h b/Source/TableDump.h
index e506a6d2..cec3d92b 100644
--- a/Source/TableDump.h
+++ b/Source/TableDump.h
@@ -38,8 +38,6 @@
IBOutlet id tableDataInstance;
IBOutlet id customQueryInstance;
- IBOutlet id tableWindow;
-
IBOutlet id exportDumpView;
IBOutlet id exportCSVView;
IBOutlet id exportMultipleCSVView;
@@ -97,6 +95,7 @@
MCPConnection *mySQLConnection;
NSMutableArray *tables;
+ NSMutableArray *nibObjectsToRelease;
// Field Mapper Controller
SPFieldMapperController *fieldMapperController;
@@ -122,6 +121,7 @@
NSUInteger exportMode;
NSUserDefaults *prefs;
BOOL progressCancelled;
+ BOOL _mainNibLoaded;
NSSavePanel *currentExportPanel;
}
diff --git a/Source/TableDump.m b/Source/TableDump.m
index d6c703ca..3527ed35 100644
--- a/Source/TableDump.m
+++ b/Source/TableDump.m
@@ -142,7 +142,7 @@
- (void)export
{
[self reloadTables:self];
- [NSApp beginSheet:exportWindow modalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:nil];
+ [NSApp beginSheet:exportWindow modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:nil];
}
- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
@@ -264,7 +264,7 @@
// Open the savePanel
[currentExportPanel beginSheetForDirectory:[prefs objectForKey:@"savePath"]
- file:file modalForWindow:tableWindow modalDelegate:self
+ file:file modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self
didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
@@ -325,7 +325,7 @@
if ( [[NSFileManager defaultManager] fileExistsAtPath:exportFile] ) {
if ( ![[NSFileManager defaultManager] isWritableFileAtPath:exportFile]
|| !(fileHandle = [SPFileHandle fileHandleForWritingAtPath:exportFile]) ) {
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
NSLocalizedString(@"Couldn't replace the file. Be sure that you have the necessary privileges.", @"message of panel when file cannot be replaced"));
[pool release];
return;
@@ -334,7 +334,7 @@
// Otherwise attempt to create a file
} else {
if ( ![[NSFileManager defaultManager] createFileAtPath:exportFile contents:[NSData data] attributes:nil] ) {
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
NSLocalizedString(@"Couldn't write to file. Be sure that you have the necessary privileges.", @"message of panel when file cannot be written"));
[pool release];
return;
@@ -344,7 +344,7 @@
fileHandle = [SPFileHandle fileHandleForWritingAtPath:exportFile];
if ( !fileHandle ) {
[[NSFileManager defaultManager] removeFileAtPath:exportFile handler:nil];
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
NSLocalizedString(@"Couldn't write to file. Be sure that you have the necessary privileges.", @"message of panel when file cannot be written"));
[pool release];
return;
@@ -374,7 +374,7 @@
[[singleProgressText onMainThread] setStringValue:NSLocalizedString(@"Exporting data...", @"text showing that app is preparing data")];
[[singleProgressBar onMainThread] setUsesThreadedAnimation:YES];
[[singleProgressBar onMainThread] setIndeterminate:YES];
- [[NSApp onMainThread] beginSheet:singleProgressSheet modalForWindow:tableWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
+ [[NSApp onMainThread] beginSheet:singleProgressSheet modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:nil contextInfo:nil];
[[singleProgressSheet onMainThread] makeKeyWindow];
[[singleProgressBar onMainThread] startAnimation:self];
@@ -417,7 +417,7 @@
[[singleProgressText onMainThread] setStringValue:NSLocalizedString(@"Exporting data...", @"text showing that app is preparing data")];
[[singleProgressBar onMainThread] setUsesThreadedAnimation:YES];
[[singleProgressBar onMainThread] setIndeterminate:YES];
- [[NSApp onMainThread] beginSheet:singleProgressSheet modalForWindow:tableWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
+ [[NSApp onMainThread] beginSheet:singleProgressSheet modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:nil contextInfo:nil];
[[singleProgressSheet onMainThread] makeKeyWindow];
[[singleProgressBar onMainThread] startAnimation:self];
@@ -475,14 +475,14 @@
// Display error message on problems
if ( !progressCancelled && !success ) {
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
NSLocalizedString(@"Couldn't write to file. Be sure that you have the necessary privileges.", @"message of panel when file cannot be written"));
}
// Export finished Growl notification
[[SPGrowlController sharedGrowlController] notifyWithTitle:@"Export Finished"
description:[NSString stringWithFormat:NSLocalizedString(@"Finished exporting to %@",@"description for finished exporting growl notification"), [exportFile lastPathComponent]]
- window:tableWindow
+ document:tableDocumentInstance
notificationName:@"Export Finished"];
[pool release];
}
@@ -495,12 +495,6 @@
invoked when user clicks on an ImportFromClipboard menuItem
*/
{
- // Load accessory nib each time
- if(![NSBundle loadNibNamed:@"ImportAccessory" owner:self]) {
- NSBeep();
- NSLog(@"ImportAccessory accessory dialog could not be loaded.");
- return;
- }
// clipboard textview with no wrapping
const CGFloat LargeNumberForText = 1.0e7;
@@ -527,7 +521,7 @@
[importFromClipboardAccessoryView addSubview:importCSVView];
[NSApp beginSheet:importFromClipboardSheet
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
contextInfo:@"importFromClipboard"];
@@ -543,13 +537,6 @@
// prepare open panel and accessory view
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
- // Load accessory nib each time
- if(![NSBundle loadNibNamed:@"ImportAccessory" owner:self]) {
- NSBeep();
- NSLog(@"ImportAccessory accessory dialog could not be loaded.");
- return;
- }
-
// Preset the accessory view with prefs defaults
[importFieldsTerminatedField setStringValue:[prefs objectForKey:SPCSVImportFieldTerminator]];
[importLinesTerminatedField setStringValue:[prefs objectForKey:SPCSVImportLineTerminator]];
@@ -567,7 +554,7 @@
// Show openPanel
[openPanel beginSheetForDirectory:[prefs objectForKey:@"openPath"]
file:[lastFilename lastPathComponent]
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
contextInfo:nil];
@@ -624,7 +611,7 @@
if (!sqlFileHandle) {
SPBeginAlertSheet(NSLocalizedString(@"Import Error title", @"Import Error"),
NSLocalizedString(@"OK button label", @"OK button"),
- nil, nil, tableWindow, self, nil, nil,
+ nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
NSLocalizedString(@"SQL file open error", @"The SQL file you selected could not be found or read."));
if([filename hasPrefix:SPImportClipboardTempFileNamePrefix])
[[NSFileManager defaultManager] removeItemAtPath:filename error:nil];
@@ -646,7 +633,7 @@
[[singleProgressBar onMainThread] startAnimation:self];
// Open the progress sheet
- [[NSApp onMainThread] beginSheet:singleProgressSheet modalForWindow:tableWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
+ [[NSApp onMainThread] beginSheet:singleProgressSheet modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:nil contextInfo:nil];
[[singleProgressSheet onMainThread] makeKeyWindow];
[tableDocumentInstance setQueryMode:SPImportExportQueryMode];
@@ -668,7 +655,7 @@
[self closeAndStopProgressSheet];
SPBeginAlertSheet(NSLocalizedString(@"SQL read error title", @"File read error"),
NSLocalizedString(@"OK", @"OK button"),
- nil, nil, tableWindow, self, nil, nil,
+ nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"SQL read error", @"An error occurred when reading the file.\n\nOnly %ld queries were executed.\n\n(%@)"), (long)queriesPerformed, [exception reason]]);
[sqlParser release];
[sqlDataBuffer release];
@@ -718,7 +705,7 @@
[self closeAndStopProgressSheet];
SPBeginAlertSheet(NSLocalizedString(@"SQL read error title", @"File read error"),
NSLocalizedString(@"OK", @"OK button"),
- nil, nil, tableWindow, self, nil, nil,
+ nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"SQL encoding read error", @"An error occurred when reading the file, as it could not be read in either UTF-8 or %@.\n\nOnly %ld queries were executed."), [[tableDocumentInstance connectionEncoding] UTF8String], (long)queriesPerformed]);
[sqlParser release];
[sqlDataBuffer release];
@@ -842,7 +829,7 @@
// Import finished Growl notification
[[SPGrowlController sharedGrowlController] notifyWithTitle:@"Import Finished"
description:[NSString stringWithFormat:NSLocalizedString(@"Finished importing %@",@"description for finished importing growl notification"), [filename lastPathComponent]]
- window:tableWindow
+ document:tableDocumentInstance
notificationName:@"Import Finished"];
}
@@ -887,7 +874,7 @@
if (!csvFileHandle) {
SPBeginAlertSheet(NSLocalizedString(@"Import Error title", @"Import Error"),
NSLocalizedString(@"OK button label", @"OK button"),
- nil, nil, tableWindow, self, nil, nil,
+ nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
NSLocalizedString(@"CSV file open error", @"The CSV file you selected could not be found or read."));
if([filename hasPrefix:SPImportClipboardTempFileNamePrefix])
[[NSFileManager defaultManager] removeItemAtPath:filename error:nil];
@@ -907,7 +894,7 @@
[[singleProgressBar onMainThread] startAnimation:self];
// Open the progress sheet
- [[NSApp onMainThread] beginSheet:singleProgressSheet modalForWindow:tableWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
+ [[NSApp onMainThread] beginSheet:singleProgressSheet modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:nil contextInfo:nil];
[[singleProgressSheet onMainThread] makeKeyWindow];
[tableDocumentInstance setQueryMode:SPImportExportQueryMode];
@@ -947,7 +934,7 @@
[self closeAndStopProgressSheet];
SPBeginAlertSheet(NSLocalizedString(@"CSV read error title", @"File read error"),
NSLocalizedString(@"OK", @"OK button"),
- nil, nil, tableWindow, self, nil, nil,
+ nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"CSV read error", @"An error occurred when reading the file.\n\nOnly %ld rows were imported.\n\n(%@)"), (long)rowsImported, [exception reason]]);
[csvParser release];
[csvDataBuffer release];
@@ -996,7 +983,7 @@
[self closeAndStopProgressSheet];
SPBeginAlertSheet(NSLocalizedString(@"CSV read error title", @"File read error"),
NSLocalizedString(@"OK", @"OK button"),
- nil, nil, tableWindow, self, nil, nil,
+ nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"CSV encoding read error", @"An error occurred when reading the file, as it could not be read using %@.\n\nOnly %ld rows were imported."), [[tableDocumentInstance connectionEncoding] UTF8String], (long)rowsImported]);
[csvParser release];
[csvDataBuffer release];
@@ -1073,7 +1060,7 @@
[[singleProgressBar onMainThread] setIndeterminate:NO];
[[singleProgressBar onMainThread] setMaxValue:fileTotalLength];
[[singleProgressBar onMainThread] startAnimation:self];
- [[NSApp onMainThread] beginSheet:singleProgressSheet modalForWindow:tableWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
+ [[NSApp onMainThread] beginSheet:singleProgressSheet modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:nil contextInfo:nil];
[[singleProgressSheet onMainThread] makeKeyWindow];
// Set up the field names import string for INSERT or REPLACE INTO
@@ -1277,7 +1264,7 @@
// Import finished Growl notification
[[SPGrowlController sharedGrowlController] notifyWithTitle:@"Import Finished"
description:[NSString stringWithFormat:NSLocalizedString(@"Finished importing %@",@"description for finished importing growl notification"), [filename lastPathComponent]]
- window:tableWindow
+ document:tableDocumentInstance
notificationName:@"Import Finished"];
// If the table selected for import is also selected in the content view,
@@ -1360,7 +1347,6 @@
- (void)startSQLImportProcessWithFile:(NSString *)filename
{
- if (!importFormatPopup) [NSBundle loadNibNamed:@"ImportAccessory" owner:self];
[importFormatPopup selectItemWithTitle:@"SQL"];
[NSThread detachNewThreadSelector:@selector(importBackgroundProcess:) toTarget:self withObject:filename];
}
@@ -1380,7 +1366,7 @@
SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"),
NSLocalizedString(@"OK", @"OK button"),
nil, nil,
- tableWindow, self,
+ [tableDocumentInstance parentWindow], self,
nil, nil,
NSLocalizedString(@"Could not parse file as CSV", @"Error when we can't parse/split file as CSV")
);
@@ -1393,7 +1379,7 @@
SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"),
NSLocalizedString(@"OK", @"OK button"),
nil, nil,
- tableWindow, self,
+ [tableDocumentInstance parentWindow], self,
nil, nil,
NSLocalizedString(@"The CSV was read as containing more than 512 columns, more than the maximum columns permitted for speed reasons by Sequel Pro.\n\nThis usually happens due to errors reading the CSV; please double-check the CSV to be imported and the line endings and escape characters at the bottom of the CSV selection dialog.", @"Error when CSV appears to have too many columns to import, probably due to line ending mismatch")
);
@@ -1407,7 +1393,7 @@
SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"),
NSLocalizedString(@"OK", @"OK button"),
nil, nil,
- tableWindow, self,
+ [tableDocumentInstance parentWindow], self,
nil, nil,
NSLocalizedString(@"Can't import CSV data into a database without any tables!", @"error text when trying to import csv data, but we have no tables in the db")
);
@@ -1430,7 +1416,7 @@
// Show field mapper sheet and set the focus to it
[[NSApp onMainThread] beginSheet:[fieldMapperController window]
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:@selector(fieldMapperDidEndSheet:returnCode:contextInfo:)
contextInfo:nil];
@@ -1655,7 +1641,7 @@
// Open the progress sheet
[[NSApp onMainThread] beginSheet:singleProgressSheet
- modalForWindow:tableWindow modalDelegate:self
+ modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self
didEndSelector:nil contextInfo:nil];
[[singleProgressSheet onMainThread] makeKeyWindow];
@@ -2162,7 +2148,7 @@
// Open the progress sheet
[[NSApp onMainThread] beginSheet:singleProgressSheet
- modalForWindow:tableWindow modalDelegate:self
+ modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self
didEndSelector:nil contextInfo:nil];
[[singleProgressSheet onMainThread] makeKeyWindow];
@@ -2368,7 +2354,7 @@
// Open progress sheet
[[NSApp onMainThread] beginSheet:singleProgressSheet
- modalForWindow:tableWindow modalDelegate:self
+ modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self
didEndSelector:nil contextInfo:nil];
[[singleProgressSheet onMainThread] makeKeyWindow];
}
@@ -2595,7 +2581,7 @@
// Open progress sheet
[[NSApp onMainThread] beginSheet:singleProgressSheet
- modalForWindow:tableWindow modalDelegate:self
+ modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self
didEndSelector:nil contextInfo:nil];
[[singleProgressSheet onMainThread] makeKeyWindow];
}
@@ -2762,7 +2748,7 @@
// Open the progress sheet
[[NSApp onMainThread] beginSheet:singleProgressSheet
- modalForWindow:tableWindow modalDelegate:self
+ modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self
didEndSelector:nil contextInfo:nil];
[[singleProgressSheet onMainThread] makeKeyWindow];
@@ -3190,8 +3176,18 @@
- (void)awakeFromNib
{
+ if (_mainNibLoaded) return;
+ _mainNibLoaded = YES;
+
[self switchTab:[[exportToolbar items] objectAtIndex:0]];
[exportToolbar setSelectedItemIdentifier:[[[exportToolbar items] objectAtIndex:0] itemIdentifier]];
+
+ // Load the import accessory view, retaining a reference to the top-level objects that need releasing.
+ NSArray *importAccessoryTopLevelObjects = nil;
+ NSNib *nibLoader = [[NSNib alloc] initWithNibNamed:@"ImportAccessory" bundle:[NSBundle mainBundle]];
+ [nibLoader instantiateNibWithOwner:self topLevelObjects:&importAccessoryTopLevelObjects];
+ [nibObjectsToRelease addObjectsFromArray:importAccessoryTopLevelObjects];
+ [nibLoader release];
}
- (id)init
@@ -3199,6 +3195,7 @@
self = [super init];
tables = [[NSMutableArray alloc] init];
+ nibObjectsToRelease = [[NSMutableArray alloc] init];
fieldMappingArray = nil;
fieldMappingGlobalValueArray = nil;
fieldMappingTableColumnNames = nil;
@@ -3215,6 +3212,7 @@
prefs = nil;
lastFilename = nil;
+ _mainNibLoaded = NO;
return self;
}
@@ -3225,6 +3223,8 @@
if (fieldMappingImportArray) [fieldMappingImportArray release];
if (lastFilename) [lastFilename release];
if (prefs) [prefs release];
+ for (id retainedObject in nibObjectsToRelease) [retainedObject release];
+ [nibObjectsToRelease release];
[super dealloc];
}
@@ -3256,7 +3256,7 @@
[errorsView setString:message];
[NSApp beginSheet:errorsSheet
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:nil];
diff --git a/Source/TableSource.h b/Source/TableSource.h
index 1d5cbcc0..0278f282 100644
--- a/Source/TableSource.h
+++ b/Source/TableSource.h
@@ -34,7 +34,6 @@
IBOutlet id tableInfoInstance;
IBOutlet id extendedTableInfoInstance;
- IBOutlet id tableWindow;
IBOutlet id indexSheet;
IBOutlet id keySheet;
IBOutlet id resetAutoIncrementSheet;
diff --git a/Source/TableSource.m b/Source/TableSource.m
index c3424c0a..1ae93a00 100644
--- a/Source/TableSource.m
+++ b/Source/TableSource.m
@@ -362,7 +362,7 @@
[alert setAlertStyle:NSCriticalAlertStyle];
- [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"cannotremovefield"];
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"cannotremovefield"];
}
@@ -400,7 +400,7 @@
[[buttons objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask];
[[buttons objectAtIndex:1] setKeyEquivalent:@"\r"];
- [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(removeFieldSheetDidEnd:returnCode:contextInfo:) contextInfo:(hasForeignKey) ? @"removeFieldAndForeignKey" : @"removeField"];
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(removeFieldSheetDidEnd:returnCode:contextInfo:) contextInfo:(hasForeignKey) ? @"removeFieldAndForeignKey" : @"removeField"];
}
/**
@@ -477,7 +477,7 @@
[[buttons objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask];
[[buttons objectAtIndex:1] setKeyEquivalent:@"\r"];
- [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(removeIndexSheetDidEnd:returnCode:contextInfo:) contextInfo:(hasForeignKey) ? @"removeIndexAndForeignKey" : @"removeIndex"];
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(removeIndexSheetDidEnd:returnCode:contextInfo:) contextInfo:(hasForeignKey) ? @"removeIndexAndForeignKey" : @"removeIndex"];
}
/**
@@ -516,7 +516,7 @@
// Begin the sheet
[NSApp beginSheet:resetAutoIncrementSheet
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:@selector(resetAutoincrementSheetDidEnd:returnCode:contextInfo:)
contextInfo:@"resetAutoIncrement"];
@@ -577,7 +577,7 @@
// Begin the sheet
[NSApp beginSheet:indexSheet
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:@selector(addIndexSheetDidEnd:returnCode:contextInfo:)
contextInfo:@"addIndex"];
@@ -762,7 +762,7 @@ closes the keySheet
isSavingRow = YES;
// Save any edits which have been made but not saved to the table yet.
- [tableWindow endEditingFor:nil];
+ [[tableDocumentInstance parentWindow] endEditingFor:nil];
// Attempt to save the row, and return YES if the save succeeded.
if ([self addRowToDB]) {
@@ -921,7 +921,7 @@ closes the keySheet
[chooseKeyButton selectItemAtIndex:0];
[NSApp beginSheet:keySheet
- modalForWindow:tableWindow modalDelegate:self
+ modalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self
didEndSelector:nil
contextInfo:nil];
@@ -980,7 +980,7 @@ closes the keySheet
if([mySQLConnection getLastErrorID] == 1146) { // If the current table doesn't exist anymore
SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"),
NSLocalizedString(@"OK", @"OK button"),
- nil, nil, tableWindow, self, nil, nil,
+ nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to alter table '%@'.\n\nMySQL said: %@", @"error while trying to alter table message"),
selectedTable, [mySQLConnection getLastErrorMessage]]);
@@ -1004,14 +1004,14 @@ closes the keySheet
if (isEditingNewRow) {
SPBeginAlertSheet(NSLocalizedString(@"Error adding field", @"error adding field message"),
NSLocalizedString(@"Edit row", @"Edit row button"),
- NSLocalizedString(@"Discard changes", @"discard changes button"), nil, tableWindow, self, @selector(addRowErrorSheetDidEnd:returnCode:contextInfo:), nil,
+ NSLocalizedString(@"Discard changes", @"discard changes button"), nil, [tableDocumentInstance parentWindow], self, @selector(addRowErrorSheetDidEnd:returnCode:contextInfo:), nil,
[NSString stringWithFormat:NSLocalizedString(@"An error occurred when trying to add the field '%@'.\n\nMySQL said: %@", @"error adding field informative message"),
[theRow objectForKey:@"Field"], [mySQLConnection getLastErrorMessage]]);
}
else {
SPBeginAlertSheet(NSLocalizedString(@"Error changing field", @"error changing field message"),
NSLocalizedString(@"Edit row", @"Edit row button"),
- NSLocalizedString(@"Discard changes", @"discard changes button"), nil, tableWindow, self, @selector(addRowErrorSheetDidEnd:returnCode:contextInfo:), nil,
+ NSLocalizedString(@"Discard changes", @"discard changes button"), nil, [tableDocumentInstance parentWindow], self, @selector(addRowErrorSheetDidEnd:returnCode:contextInfo:), nil,
[NSString stringWithFormat:NSLocalizedString(@"An error occurred when trying to change the field '%@'.\n\nMySQL said: %@", @"error changing field informative message"),
[theRow objectForKey:@"Field"], [mySQLConnection getLastErrorMessage]]);
}
@@ -1036,7 +1036,7 @@ closes the keySheet
// Problem: reentering edit mode for first cell doesn't function
[tableSourceView selectRowIndexes:[NSIndexSet indexSetWithIndex:currentlyEditingRow] byExtendingSelection:NO];
- [tableSourceView performSelector:@selector(keyDown:) withObject:[NSEvent keyEventWithType:NSKeyDown location:NSMakePoint(0,0) modifierFlags:0 timestamp:0 windowNumber:[tableWindow windowNumber] context:[NSGraphicsContext currentContext] characters:nil charactersIgnoringModifiers:nil isARepeat:NO keyCode:0x24] afterDelay:0.0];
+ [tableSourceView performSelector:@selector(keyDown:) withObject:[NSEvent keyEventWithType:NSKeyDown location:NSMakePoint(0,0) modifierFlags:0 timestamp:0 windowNumber:[[tableDocumentInstance parentWindow] windowNumber] context:[NSGraphicsContext currentContext] characters:nil charactersIgnoringModifiers:nil isARepeat:NO keyCode:0x24] afterDelay:0.0];
}
// Discard changes and cancel editing
@@ -1077,7 +1077,7 @@ closes the keySheet
// Display the error sheet
SPBeginAlertSheet([errorDictionary objectForKey:@"title"], NSLocalizedString(@"OK", @"OK button"),
- nil, nil, tableWindow, self, nil, nil,
+ nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[errorDictionary objectForKey:@"message"]);
}
@@ -1517,7 +1517,7 @@ would result in a position change.
// Run the query; report any errors, or reload the table on success
[mySQLConnection queryString:queryString];
if ([mySQLConnection queryErrored]) {
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"Couldn't move field. MySQL said: %@", @"message of panel when field cannot be added in drag&drop operation"), [mySQLConnection getLastErrorMessage]]);
} else {
[tableDataInstance resetAllData];
@@ -1774,7 +1774,7 @@ would result in a position change.
// Check for errors, but only if the query wasn't cancelled
if ([mySQLConnection queryErrored] && ![mySQLConnection queryCancelled]) {
- SPBeginAlertSheet(NSLocalizedString(@"Unable to add index", @"add index error message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Unable to add index", @"add index error message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"An error occured while trying to add the index.\n\nMySQL said: %@", @"add index error informative message"), [mySQLConnection getLastErrorMessage]]);
}
else {
diff --git a/Source/TablesList.h b/Source/TablesList.h
index 36d3ccaa..6a313d44 100644
--- a/Source/TablesList.h
+++ b/Source/TablesList.h
@@ -51,7 +51,6 @@
IBOutlet id tableTriggersInstance;
IBOutlet SPHistoryController *spHistoryControllerInstance;
- IBOutlet id tableWindow;
IBOutlet id copyTableSheet;
IBOutlet id tablesListView;
IBOutlet id copyTableButton;
diff --git a/Source/TablesList.m b/Source/TablesList.m
index 2a77db53..be617aa2 100644
--- a/Source/TablesList.m
+++ b/Source/TablesList.m
@@ -271,7 +271,7 @@
return;
}
- [tableWindow endEditingFor:nil];
+ [[tableDocumentInstance parentWindow] endEditingFor:nil];
// Populate the table type (engine) popup button
[tableTypeButton removeAllItems];
@@ -288,7 +288,7 @@
}
[NSApp beginSheet:tableSheet
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:@"addTable"];
@@ -311,7 +311,7 @@
if (![tablesListView numberOfSelectedRows])
return;
- [tableWindow endEditingFor:nil];
+ [[tableDocumentInstance parentWindow] endEditingFor:nil];
NSAlert *alert = [NSAlert alertWithMessageText:@"" defaultButton:NSLocalizedString(@"Delete", @"delete button") alternateButton:NSLocalizedString(@"Cancel", @"cancel button") otherButton:nil informativeTextWithFormat:@""];
@@ -379,7 +379,7 @@
[alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"Are you sure you want to delete the selected %@? This operation cannot be undone.", @"delete tables/views informative message"), tblTypes]];
}
- [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"removeRow"];
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"removeRow"];
}
/**
@@ -392,7 +392,7 @@
if ([tablesListView numberOfSelectedRows] != 1) return;
if (![tableSourceInstance saveRowOnDeselect] || ![tableContentInstance saveRowOnDeselect]) return;
- [tableWindow endEditingFor:nil];
+ [[tableDocumentInstance parentWindow] endEditingFor:nil];
// Detect table type: table or view
NSInteger tblType = [[filteredTableTypes objectAtIndex:[tablesListView selectedRow]] integerValue];
@@ -423,7 +423,7 @@
[copyTableContentSwitch setState:NSOffState];
[NSApp beginSheet:copyTableSheet
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:@"copyTable"];
@@ -438,7 +438,7 @@
return;
}
- [tableWindow endEditingFor:nil];
+ [[tableDocumentInstance parentWindow] endEditingFor:nil];
if ([tablesListView numberOfSelectedRows] != 1) return;
if (![[self tableName] length]) return;
@@ -471,7 +471,7 @@
[NSApp beginSheet:tableRenameSheet
- modalForWindow:tableWindow
+ modalForWindow:[tableDocumentInstance parentWindow]
modalDelegate:self
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:@"renameTable"];
@@ -486,7 +486,7 @@
if (![tablesListView numberOfSelectedRows])
return;
- [tableWindow endEditingFor:nil];
+ [[tableDocumentInstance parentWindow] endEditingFor:nil];
NSAlert *alert = [NSAlert alertWithMessageText:@""
defaultButton:NSLocalizedString(@"Truncate", @"truncate button")
@@ -512,7 +512,7 @@
[alert setInformativeText:NSLocalizedString(@"Are you sure you want to delete ALL records in the selected tables? This operation cannot be undone.", @"truncate tables informative message")];
}
- [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"truncateTable"];
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"truncateTable"];
}
/**
@@ -862,7 +862,7 @@
[[tableSubMenu itemAtIndex:10] setHidden:NO];
// set window title
- [tableWindow setTitle:[tableDocumentInstance displaySPName]];
+ [tableDocumentInstance updateWindowTitle:self];
return;
}
@@ -1035,7 +1035,7 @@
}
// set window title
- [tableWindow setTitle:[tableDocumentInstance displaySPName]];
+ [tableDocumentInstance updateWindowTitle:self];
}
#pragma mark -
@@ -1333,7 +1333,7 @@
if (![self isTableNameValid:newTableName forType:selectedTableType ignoringSelectedTable:YES]) {
// Table has invalid name
// Since we trimmed whitespace and checked for empty string, this means there is already a table with that name
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self,
@selector(sheetDidEnd:returnCode:contextInfo:), nil,
[NSString stringWithFormat: NSLocalizedString(@"The name '%@' is already used.", @"message when trying to rename a table/view/proc/etc to an already used name"), newTableName]);
return;
@@ -1380,11 +1380,11 @@
}
}
@catch (NSException * myException) {
- SPBeginAlertSheet( NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, [myException reason]);
+ SPBeginAlertSheet( NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil, [myException reason]);
}
// Set window title to reflect the new table name
- [tableWindow setTitle:[tableDocumentInstance displaySPName]];
+ [tableDocumentInstance updateWindowTitle:self];
// Query the structure of all databases in the background (mainly for completion)
[NSThread detachNewThreadSelector:@selector(queryDbStructureWithUserInfo:) toTarget:mySQLConnection withObject:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], @"forceUpdate", nil]];
@@ -1425,7 +1425,7 @@
if (!tableListIsSelectable) return NO;
// End editing (otherwise problems when user hits reload button)
- [tableWindow endEditingFor:nil];
+ [[tableDocumentInstance parentWindow] endEditingFor:nil];
if ( alertSheetOpened ) {
return NO;
@@ -1651,10 +1651,10 @@
- (void) makeTableListFilterHaveFocus
{
if([tables count] > 20) {
- [tableWindow makeFirstResponder:listFilterField];
+ [[tableDocumentInstance parentWindow] makeFirstResponder:listFilterField];
}
else if([tables count] > 2) {
- [tableWindow makeFirstResponder:tablesListView];
+ [[tableDocumentInstance parentWindow] makeFirstResponder:tablesListView];
if([tablesListView numberOfSelectedRows] < 1)
[tablesListView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
@@ -1940,7 +1940,7 @@
[alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"Couldn't delete '%@'.\nMySQL said: %@", @"message of panel when an item cannot be deleted"), [tables objectAtIndex:currentIndex], [mySQLConnection getLastErrorMessage]]];
[alert setAlertStyle:NSWarningAlertStyle];
if ([indexes indexLessThanIndex:currentIndex] == NSNotFound) {
- [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:nil contextInfo:nil];
currentIndex = NSNotFound;
} else {
NSInteger choice = [alert runModal];
@@ -1965,7 +1965,7 @@
[tablesListView reloadData];
// set window title
- [tableWindow setTitle:[tableDocumentInstance displaySPName]];
+ [tableDocumentInstance updateWindowTitle:self];
[tablesListView deselectAll:self];
@@ -2003,7 +2003,7 @@
// [[buttons objectAtIndex:0] setKeyEquivalent:@"t"];
// [[buttons objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask];
// [[buttons objectAtIndex:1] setKeyEquivalent:@"\r"];
- [alert beginSheetModalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"truncateTableError"];
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:@"truncateTableError"];
}
// Get next index (beginning from the end)
@@ -2097,7 +2097,7 @@
alertSheetOpened = YES;
SPBeginAlertSheet(NSLocalizedString(@"Error adding new table", @"error adding new table message"),
- NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self,
+ NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self,
@selector(sheetDidEnd:returnCode:contextInfo:), @"addRow",
[NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to add the new table '%@'.\n\nMySQL said: %@", @"error adding new table informative message"), tableName, [mySQLConnection getLastErrorMessage]]);
@@ -2116,7 +2116,7 @@
NSString *tableType = @"";
if ([[copyTableNameField stringValue] isEqualToString:@""]) {
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, NSLocalizedString(@"Table must have a name.", @"message of panel when no name is given for table"));
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil, NSLocalizedString(@"Table must have a name.", @"message of panel when no name is given for table"));
return;
}
@@ -2152,7 +2152,7 @@
if ( ![queryResult numOfRows] ) {
//error while getting table structure
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"Couldn't get create syntax.\nMySQL said: %@", @"message of panel when table information cannot be retrieved"), [mySQLConnection getLastErrorMessage]]);
} else {
@@ -2198,7 +2198,7 @@
// Check for errors, only displaying if the connection hasn't been terminated
if ([mySQLConnection queryErrored]) {
if ([mySQLConnection isConnected]) {
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"An error occured while retrieving the create syntax for '%@'.\nMySQL said: %@", @"message of panel when create syntax cannot be retrieved"), selectedTableName, [mySQLConnection getLastErrorMessage]]);
}
return;
@@ -2211,7 +2211,7 @@
[mySQLConnection queryString:[tableSyntax stringByReplacingOccurrencesOfRegex:[NSString stringWithFormat:@"(?<=%@ )(`[^`]+?`)", [tableType uppercaseString]] withString:[[copyTableNameField stringValue] backtickQuotedString]]];
if ([mySQLConnection queryErrored]) {
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"Couldn't duplicate '%@'.\nMySQL said: %@", @"message of panel when an item cannot be renamed"), [copyTableNameField stringValue], [mySQLConnection getLastErrorMessage]]);
}
@@ -2219,7 +2219,7 @@
if ([mySQLConnection queryErrored]) {
//error while creating new table
- SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil,
+ SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [tableDocumentInstance parentWindow], self, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"Couldn't create '%@'.\nMySQL said: %@", @"message of panel when table cannot be created"), [copyTableNameField stringValue], [mySQLConnection getLastErrorMessage]]);
} else {
@@ -2237,7 +2237,7 @@
NSLocalizedString(@"OK", @"OK button"),
nil,
nil,
- tableWindow,
+ [tableDocumentInstance parentWindow],
self,
nil,
nil,