diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/SPAlertSheets.h | 32 | ||||
-rw-r--r-- | Source/SPAlertSheets.m | 148 | ||||
-rw-r--r-- | Source/SPCustomQuery.h | 1 | ||||
-rw-r--r-- | Source/SPCustomQuery.m | 27 | ||||
-rw-r--r-- | Source/SPDatabaseDocument.m | 138 | ||||
-rw-r--r-- | Source/SPDatabaseStructure.m | 18 | ||||
-rw-r--r-- | Source/SPDotExporter.m | 4 | ||||
-rw-r--r-- | Source/SPEditorPreferencePane.m | 25 | ||||
-rw-r--r-- | Source/SPExtendedTableInfo.m | 140 | ||||
-rw-r--r-- | Source/SPFavoritesOutlineView.h | 1 | ||||
-rw-r--r-- | Source/SPNavigatorController.m | 14 | ||||
-rw-r--r-- | Source/SPProcessListController.m | 70 | ||||
-rw-r--r-- | Source/SPProcessListControllerDataSource.h | 35 | ||||
-rw-r--r-- | Source/SPProcessListControllerDataSource.m | 98 | ||||
-rw-r--r-- | Source/SPSQLExporter.m | 6 | ||||
-rw-r--r-- | Source/SPTableContent.m | 2 | ||||
-rw-r--r-- | Source/SPTableData.m | 12 | ||||
-rw-r--r-- | Source/SPTableFieldValidation.m | 2 | ||||
-rw-r--r-- | Source/SPTableRelations.m | 6 | ||||
-rw-r--r-- | Source/SPTableStructure.m | 2 | ||||
-rw-r--r-- | Source/SPTableStructureDelegate.m | 4 | ||||
-rw-r--r-- | Source/SPTableStructureLoading.m | 2 |
22 files changed, 473 insertions, 314 deletions
diff --git a/Source/SPAlertSheets.h b/Source/SPAlertSheets.h index ab6f1812..fd5b46cf 100644 --- a/Source/SPAlertSheets.h +++ b/Source/SPAlertSheets.h @@ -30,6 +30,23 @@ // // More info at <http://code.google.com/p/sequel-pro/> +@interface SPAlertSheets : NSObject + ++ (void)beginWaitingAlertSheetWithTitle:(NSString *)title + defaultButton:(NSString *)defaultButton + alternateButton:(NSString *)alternateButton + otherButton:(NSString *)otherButton + alertStyle:(NSAlertStyle)alertStyle + docWindow:(NSWindow *)docWindow + modalDelegate:(id)modalDelegate + didEndSelector:(SEL)didEndSelector + contextInfo:(void *)contextInfo + msg:(NSString *)msg + infoText:(NSString *)infoText + returnCode:(NSInteger *)returnCode; + +@end + void SPBeginAlertSheet( NSString *title, NSString *defaultButton, @@ -41,18 +58,3 @@ void SPBeginAlertSheet( void *contextInfo, NSString *msg ); - -void SPBeginWaitingAlertSheet( - NSString *title, - NSString *defaultButton, - NSString *alternateButton, - NSString *otherButton, -NSAlertStyle alertStyle, - NSWindow *docWindow, - id modalDelegate, - SEL didEndSelector, - void *contextInfo, - NSString *msg, - NSString *infoText, - NSInteger *returnCode -); diff --git a/Source/SPAlertSheets.m b/Source/SPAlertSheets.m index fe45741e..f30e6d33 100644 --- a/Source/SPAlertSheets.m +++ b/Source/SPAlertSheets.m @@ -31,54 +31,9 @@ // More info at <http://code.google.com/p/sequel-pro/> #import "SPAlertSheets.h" +#import "SPMainThreadTrampoline.h" -/** - * Provide a simple alias of NSBeginAlertSheet, with a few differences: - * - printf-type format strings are no longer supported within the "msg" - * message text argument, preventing access of random stack areas for - * error text which contains inadvertant printf formatting. - * - The didDismissSelector is no longer supported - * - The sheet no longer needs to be orderOut:ed after use - * - The alert is always shown on the main thread. - */ -void SPBeginAlertSheet( - NSString *title, - NSString *defaultButton, - NSString *alternateButton, - NSString *otherButton, - NSWindow *docWindow, - id modalDelegate, - SEL didEndSelector, - void *contextInfo, - NSString *msg) -{ - NSButton *aButton; - - // Set up an NSAlert with the supplied details - NSAlert *alert = [[[NSAlert alloc] init] autorelease]; - [alert setMessageText:title]; - aButton = [alert addButtonWithTitle:defaultButton]; - [aButton setTag:NSAlertDefaultReturn]; - - // Add 'alternate' and 'other' buttons as appropriate - if (alternateButton) { - aButton = [alert addButtonWithTitle:alternateButton]; - [aButton setTag:NSAlertAlternateReturn]; - } - if (otherButton) { - aButton = [alert addButtonWithTitle:otherButton]; - [aButton setTag:NSAlertOtherReturn]; - } - - // Set the informative message if supplied - if (msg) [alert setInformativeText:msg]; - - // Run the alert on the main thread - [[alert onMainThread] beginSheetModalForWindow:docWindow modalDelegate:modalDelegate didEndSelector:didEndSelector contextInfo:contextInfo]; - - // Ensure the alerting window is frontmost - [[docWindow onMainThread] makeKeyWindow]; -} +@implementation SPAlertSheets /** * Provide a simple alias of a NSApp-wide modal NSBeginAlertSheet which waits @@ -91,21 +46,36 @@ void SPBeginAlertSheet( * - The sheet no longer needs to be orderOut:ed after use * - The alert is always shown on the main thread. */ -void SPBeginWaitingAlertSheet( - NSString *title, - NSString *defaultButton, - NSString *alternateButton, - NSString *otherButton, - NSAlertStyle alertStyle, - NSWindow *docWindow, - id modalDelegate, - SEL didEndSelector, - void *contextInfo, - NSString *msg, - NSString *infoText, - NSInteger *returnCode) ++ (void)beginWaitingAlertSheetWithTitle:(NSString *)title + defaultButton:(NSString *)defaultButton + alternateButton:(NSString *)alternateButton + otherButton:(NSString *)otherButton + alertStyle:(NSAlertStyle)alertStyle + docWindow:(NSWindow *)docWindow + modalDelegate:(id)modalDelegate + didEndSelector:(SEL)didEndSelector + contextInfo:(void *)contextInfo + msg:(NSString *)msg + infoText:(NSString *)infoText + returnCode:(NSInteger *)returnCode { + // Ensure execution on the main thread + if (![[NSThread currentThread] isMainThread]) { + return [[self onMainThread] beginWaitingAlertSheetWithTitle:title + defaultButton:defaultButton + alternateButton:alternateButton + otherButton:otherButton + alertStyle:alertStyle + docWindow:docWindow + modalDelegate:modalDelegate + didEndSelector:didEndSelector + contextInfo:contextInfo + msg:msg + infoText:infoText + returnCode:returnCode]; + } + NSButton *aButton; // Initialize returnCode with a value which can't be returned as @@ -142,10 +112,10 @@ void SPBeginWaitingAlertSheet( if (msg) [alert setMessageText:msg]; // Run the alert on the main thread - [[alert onMainThread] beginSheetModalForWindow:docWindow modalDelegate:modalDelegate didEndSelector:didEndSelector contextInfo:contextInfo]; + [alert beginSheetModalForWindow:docWindow modalDelegate:modalDelegate didEndSelector:didEndSelector contextInfo:contextInfo]; // wait for the sheet - NSModalSession session = [[NSApp onMainThread] beginModalSessionForWindow:[alert window]]; + NSModalSession session = [NSApp beginModalSessionForWindow:[alert window]]; for (;;) { // Since the returnCode can only be -1, 0, or 1 @@ -169,6 +139,56 @@ void SPBeginWaitingAlertSheet( } - [[NSApp onMainThread] endModalSession:session]; - [[NSApp onMainThread] endSheet:[alert window]]; + [NSApp endModalSession:session]; + [NSApp endSheet:[alert window]]; +} + +@end + +/** + * Provide a simple alias of NSBeginAlertSheet, with a few differences: + * - printf-type format strings are no longer supported within the "msg" + * message text argument, preventing access of random stack areas for + * error text which contains inadvertant printf formatting. + * - The didDismissSelector is no longer supported + * - The sheet no longer needs to be orderOut:ed after use + * - The alert is always shown on the main thread. + */ +void SPBeginAlertSheet( + NSString *title, + NSString *defaultButton, + NSString *alternateButton, + NSString *otherButton, + NSWindow *docWindow, + id modalDelegate, + SEL didEndSelector, + void *contextInfo, + NSString *msg) +{ + NSButton *aButton; + + // Set up an NSAlert with the supplied details + NSAlert *alert = [[[NSAlert alloc] init] autorelease]; + [alert setMessageText:title]; + aButton = [alert addButtonWithTitle:defaultButton]; + [aButton setTag:NSAlertDefaultReturn]; + + // Add 'alternate' and 'other' buttons as appropriate + if (alternateButton) { + aButton = [alert addButtonWithTitle:alternateButton]; + [aButton setTag:NSAlertAlternateReturn]; + } + if (otherButton) { + aButton = [alert addButtonWithTitle:otherButton]; + [aButton setTag:NSAlertOtherReturn]; + } + + // Set the informative message if supplied + if (msg) [alert setInformativeText:msg]; + + // Run the alert on the main thread + [[alert onMainThread] beginSheetModalForWindow:docWindow modalDelegate:modalDelegate didEndSelector:didEndSelector contextInfo:contextInfo]; + + // Ensure the alerting window is frontmost + [[docWindow onMainThread] makeKeyWindow]; } diff --git a/Source/SPCustomQuery.h b/Source/SPCustomQuery.h index ffca796b..a9dc3180 100644 --- a/Source/SPCustomQuery.h +++ b/Source/SPCustomQuery.h @@ -91,6 +91,7 @@ IBOutlet SPCopyTable *customQueryView; IBOutlet NSScrollView *customQueryScrollView; IBOutlet id errorText; + IBOutlet NSTextField *errorTextTitle; IBOutlet NSScrollView *errorTextScrollView; IBOutlet id affectedRowsText; IBOutlet id valueSheet; diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m index b5a99a37..9090dd1a 100644 --- a/Source/SPCustomQuery.m +++ b/Source/SPCustomQuery.m @@ -574,6 +574,7 @@ } [tableDocumentInstance startTaskWithDescription:taskString]; + [errorTextTitle setStringValue:NSLocalizedString(@"Query Status", @"Query Status")]; [errorText setString:taskString]; [affectedRowsText setStringValue:@""]; @@ -740,21 +741,26 @@ [errors appendFormat:NSLocalizedString(@"[ERROR in query %ld] %@\n", @"error text when multiple custom query failed"), (long)(i+1), errorString]; + [[errorTextTitle onMainThread] setStringValue:NSLocalizedString(@"Last Error Message", @"Last Error Message")]; [[errorText onMainThread] setString:errors]; // ask the user to continue after detecting an error if (![mySQLConnection lastQueryWasCancelled]) { [tableDocumentInstance setTaskIndicatorShouldAnimate:NO]; - SPBeginWaitingAlertSheet(@"title", - NSLocalizedString(@"Run All", @"run all button"), NSLocalizedString(@"Continue", @"continue button"), NSLocalizedString(@"Stop", @"stop button"), - NSWarningAlertStyle, [tableDocumentInstance parentWindow], self, - @selector(sheetDidEnd:returnCode:contextInfo:), - @"runAllContinueStopSheet", - NSLocalizedString(@"MySQL Error", @"mysql error message"), - [mySQLConnection lastErrorMessage], - &runAllContinueStopSheetReturnCode - ); + [SPAlertSheets beginWaitingAlertSheetWithTitle:@"title" + defaultButton:NSLocalizedString(@"Run All", @"run all button") + alternateButton:NSLocalizedString(@"Continue", @"continue button") + otherButton:NSLocalizedString(@"Stop", @"stop button") + alertStyle:NSWarningAlertStyle + docWindow:[tableDocumentInstance parentWindow] + modalDelegate:self + didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) + contextInfo:@"runAllContinueStopSheet" + msg:NSLocalizedString(@"MySQL Error", @"mysql error message") + infoText:[mySQLConnection lastErrorMessage] + returnCode:&runAllContinueStopSheetReturnCode]; + [tableDocumentInstance setTaskIndicatorShouldAnimate:YES]; switch (runAllContinueStopSheetReturnCode) { @@ -1309,6 +1315,7 @@ #ifndef SP_REFACTOR // set the error text + [errorTextTitle setStringValue:NSLocalizedString(@"Last Error Message", @"Last Error Message")]; [errorText setString:[errorsString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]]; [[errorTextScrollView verticalScroller] setFloatValue:1.0f]; #endif @@ -1370,6 +1377,7 @@ } } else if ( [errorsString length] && queryIsTableSorter ) { + [errorTextTitle setStringValue:NSLocalizedString(@"Last Error Message", @"Last Error Message")]; [errorText setString:NSLocalizedString(@"Couldn't sort column.", @"text shown if an error occured while sorting the result table")]; NSBeep(); } else { @@ -1976,6 +1984,7 @@ NSString *tableForColumn = [columnDefinition objectForKey:@"org_table"]; if(!tableForColumn || ![tableForColumn length]) { + [errorTextTitle setStringValue:NSLocalizedString(@"Last Error Message", @"Last Error Message")]; [errorText setString:[NSString stringWithFormat:NSLocalizedString(@"Couldn't identify field origin unambiguously. The column '%@' contains data from more than one table.", @"Custom Query result editing error - could not identify a corresponding column"), [columnDefinition objectForKey:@"name"]]]; NSBeep(); return; diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m index fc4fd335..39d67245 100644 --- a/Source/SPDatabaseDocument.m +++ b/Source/SPDatabaseDocument.m @@ -3171,15 +3171,18 @@ static NSString *SPRenameDatabaseAction = @"SPRenameDatabase"; if(!spf || ![spf count] || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - SPBeginWaitingAlertSheet(@"title", - NSLocalizedString(@"OK", @"OK button"), NSLocalizedString(@"Ignore", @"ignore button"), nil, - NSCriticalAlertStyle, parentWindow, self, - @selector(sheetDidEnd:returnCode:contextInfo:), - @"saveDocPrefSheetStatus", - [NSString stringWithFormat:NSLocalizedString(@"Error while reading connection data file", @"error while reading connection data file")], - [NSString stringWithFormat:NSLocalizedString(@"Connection data file “%@” couldn't be read. Please try to save the document under a different name.", @"message error while reading connection data file and suggesting to save it under a differnet name"), [fileName lastPathComponent]], - &saveDocPrefSheetStatus - ); + [SPAlertSheets beginWaitingAlertSheetWithTitle:@"title" + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:NSLocalizedString(@"Ignore", @"ignore button") + otherButton:nil + alertStyle:NSCriticalAlertStyle + docWindow:parentWindow + modalDelegate:self + didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) + contextInfo:@"saveDocPrefSheetStatus" + msg:[NSString stringWithFormat:NSLocalizedString(@"Error while reading connection data file", @"error while reading connection data file")] + infoText:[NSString stringWithFormat:NSLocalizedString(@"Connection data file “%@” couldn't be read. Please try to save the document under a different name.", @"message error while reading connection data file and suggesting to save it under a differnet name"), [fileName lastPathComponent]] + returnCode:&saveDocPrefSheetStatus]; if (spf) [spf release]; if(saveDocPrefSheetStatus == NSAlertAlternateReturn) @@ -3416,17 +3419,19 @@ static NSString *SPRenameDatabaseAction = @"SPRenameDatabase"; */ - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { + SEL action = [menuItem action]; + if ([menuItem menu] == chooseDatabaseButton) { return (_isConnected && databaseListIsSelectable); } if (!_isConnected || _isWorkingLevel) { - return ([menuItem action] == @selector(newWindow:) || - [menuItem action] == @selector(terminate:) || - [menuItem action] == @selector(closeTab:)); + return (action == @selector(newWindow:) || + action == @selector(terminate:) || + action == @selector(closeTab:)); } - if ([menuItem action] == @selector(openCurrentConnectionInNewWindow:)) + if (action == @selector(openCurrentConnectionInNewWindow:)) { if ([self isUntitled]) { [menuItem setTitle:NSLocalizedString(@"Open in New Window", @"menu item open in new window")]; @@ -3439,12 +3444,12 @@ static NSString *SPRenameDatabaseAction = @"SPRenameDatabase"; } // Data export - if ([menuItem action] == @selector(export:)) { + if (action == @selector(export:)) { return (([self database] != nil) && ([[tablesListInstance tables] count] > 1)); } // Selected tables data export - if ([menuItem action] == @selector(exportSelectedTablesAs:)) { + if (action == @selector(exportSelectedTablesAs:)) { NSInteger tag = [menuItem tag]; NSInteger type = [tablesListInstance tableType]; @@ -3470,39 +3475,56 @@ static NSString *SPRenameDatabaseAction = @"SPRenameDatabase"; return (enable && (tag == SPSQLExport)); } } + + // Can only be enabled on mysql 4.1+ + if (action == @selector(alterDatabase:)) { + return (([self database] != nil) && [serverSupport supportsPost41CharacterSetHandling]); + } + + // Table specific actions + if (action == @selector(viewStructure:) || + action == @selector(viewContent:) || + action == @selector(viewRelations:) || + action == @selector(viewStatus:) || + action == @selector(viewTriggers:)) + { + return [self database] != nil && [[[tablesListInstance valueForKeyPath:@"tablesListView"] selectedRowIndexes] count]; + + } - if ([menuItem action] == @selector(import:) || - [menuItem action] == @selector(removeDatabase:) || - [menuItem action] == @selector(copyDatabase:) || - [menuItem action] == @selector(renameDatabase:) || - [menuItem action] == @selector(openDatabaseInNewTab:) || - [menuItem action] == @selector(refreshTables:)) + // Database specific actions + if (action == @selector(import:) || + action == @selector(removeDatabase:) || + action == @selector(copyDatabase:) || + action == @selector(renameDatabase:) || + action == @selector(openDatabaseInNewTab:) || + action == @selector(refreshTables:)) { - return ([self database] != nil); + return [self database] != nil; } - if ([menuItem action] == @selector(importFromClipboard:)) - { + if (action == @selector(importFromClipboard:)){ return [self database] && [[NSPasteboard generalPasteboard] availableTypeFromArray:[NSArray arrayWithObjects:NSStringPboardType, nil]]; - } // Change "Save Query/Queries" menu item title dynamically // and disable it if no query in the editor - if ([menuItem action] == @selector(saveConnectionSheet:) && [menuItem tag] == 0) { - if([customQueryInstance numberOfQueries] < 1) { + if (action == @selector(saveConnectionSheet:) && [menuItem tag] == 0) { + if ([customQueryInstance numberOfQueries] < 1) { [menuItem setTitle:NSLocalizedString(@"Save Query…", @"Save Query…")]; + return NO; } - else if([customQueryInstance numberOfQueries] == 1) - [menuItem setTitle:NSLocalizedString(@"Save Query…", @"Save Query…")]; - else - [menuItem setTitle:NSLocalizedString(@"Save Queries…", @"Save Queries…")]; + else { + [menuItem setTitle:[customQueryInstance numberOfQueries] == 1 ? + NSLocalizedString(@"Save Query…", @"Save Query…") : + NSLocalizedString(@"Save Queries…", @"Save Queries…")]; + } return YES; } - if ([menuItem action] == @selector(printDocument:)) { + if (action == @selector(printDocument:)) { return (([self database] != nil && [[tablesListInstance valueForKeyPath:@"tablesListView"] numberOfSelectedRows] == 1) || // If Custom Query Tab is active the textView will handle printDocument by itself // if it is first responder; otherwise allow to print the Query Result table even @@ -3510,70 +3532,70 @@ static NSString *SPRenameDatabaseAction = @"SPRenameDatabase"; [tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]] == 2); } - if ([menuItem action] == @selector(chooseEncoding:)) { + if (action == @selector(chooseEncoding:)) { return [self supportsEncoding]; } - if ([menuItem action] == @selector(analyzeTable:) || - [menuItem action] == @selector(optimizeTable:) || - [menuItem action] == @selector(repairTable:) || - [menuItem action] == @selector(flushTable:) || - [menuItem action] == @selector(checkTable:) || - [menuItem action] == @selector(checksumTable:) || - [menuItem action] == @selector(showCreateTableSyntax:) || - [menuItem action] == @selector(copyCreateTableSyntax:)) + // Table actions and view switching + if (action == @selector(analyzeTable:) || + action == @selector(optimizeTable:) || + action == @selector(repairTable:) || + action == @selector(flushTable:) || + action == @selector(checkTable:) || + action == @selector(checksumTable:) || + action == @selector(showCreateTableSyntax:) || + action == @selector(copyCreateTableSyntax:)) { return [[[tablesListInstance valueForKeyPath:@"tablesListView"] selectedRowIndexes] count]; } - if ([menuItem action] == @selector(addConnectionToFavorites:)) { - return ![connectionController selectedFavorite]; + if (action == @selector(addConnectionToFavorites:)) { + return ![connectionController selectedFavorite] || [connectionController isEditingConnection]; } // Backward in history menu item - if (([menuItem action] == @selector(backForwardInHistory:)) && ([menuItem tag] == 0)) { + if ((action == @selector(backForwardInHistory:)) && ([menuItem tag] == 0)) { return (([[spHistoryControllerInstance history] count]) && ([spHistoryControllerInstance historyPosition] > 0)); } // Forward in history menu item - if (([menuItem action] == @selector(backForwardInHistory:)) && ([menuItem tag] == 1)) { + if ((action == @selector(backForwardInHistory:)) && ([menuItem tag] == 1)) { return (([[spHistoryControllerInstance history] count]) && (([spHistoryControllerInstance historyPosition] + 1) < [[spHistoryControllerInstance history] count])); } // Show/hide console - if ([menuItem action] == @selector(toggleConsole:)) { + if (action == @selector(toggleConsole:)) { [menuItem setTitle:([[[SPQueryController sharedQueryController] window] isVisible] && [[[NSApp keyWindow] windowController] isKindOfClass:[SPQueryController class]]) ? NSLocalizedString(@"Hide Console", @"hide console") : NSLocalizedString(@"Show Console", @"show console")]; } // Clear console - if ([menuItem action] == @selector(clearConsole:)) { + if (action == @selector(clearConsole:)) { return ([[SPQueryController sharedQueryController] consoleMessageCount] > 0); } // Show/hide console - if ([menuItem action] == @selector(toggleNavigator:)) { + if (action == @selector(toggleNavigator:)) { [menuItem setTitle:([[[SPNavigatorController sharedNavigatorController] window] isVisible]) ? NSLocalizedString(@"Hide Navigator", @"hide navigator") : NSLocalizedString(@"Show Navigator", @"show navigator")]; } // Focus on table content filter - if ([menuItem action] == @selector(focusOnTableContentFilter:) || [menuItem action] == @selector(showFilterTable:)) { + if (action == @selector(focusOnTableContentFilter:) || [menuItem action] == @selector(showFilterTable:)) { return ([self table] != nil && [[self table] isNotEqualTo:@""]); } // Focus on table list or filter resp. - if ([menuItem action] == @selector(makeTableListFilterHaveFocus:)) { + if (action == @selector(makeTableListFilterHaveFocus:)) { - if([[tablesListInstance valueForKeyPath:@"tables"] count] > 20) - [menuItem setTitle:NSLocalizedString(@"Filter Tables", @"filter tables menu item")]; - else - [menuItem setTitle:NSLocalizedString(@"Change Focus to Table List", @"change focus to table list menu item")]; + [menuItem setTitle:[[tablesListInstance valueForKeyPath:@"tables"] count] > 20 ? + NSLocalizedString(@"Filter Tables", @"filter tables menu item") : + NSLocalizedString(@"Change Focus to Table List", @"change focus to table list menu item")]; - return ([[tablesListInstance valueForKeyPath:@"tables"] count] > 1); + return [[tablesListInstance valueForKeyPath:@"tables"] count] > 1; } // If validation for the sort favorites tableview items reaches here then the preferences window isn't // open return NO. - if (([menuItem action] == @selector(sortFavorites:)) || ([menuItem action] == @selector(reverseSortFavorites:))) { + if ((action == @selector(sortFavorites:)) || ([menuItem action] == @selector(reverseSortFavorites:))) { return NO; } @@ -3589,10 +3611,10 @@ static NSString *SPRenameDatabaseAction = @"SPRenameDatabase"; // Obviously don't add if it already exists. We shouldn't really need this as the menu item validation // enables or disables the menu item based on the same method. Although to be safe do the check anyway // as we don't know what's calling this method. - if ([connectionController selectedFavorite]) return; + if ([connectionController selectedFavorite] && ![connectionController isEditingConnection]) return; // Request the connection controller to add its details to favorites - [connectionController addFavorite:self]; + [connectionController addFavoriteUsingCurrentDetails:self]; } /** diff --git a/Source/SPDatabaseStructure.m b/Source/SPDatabaseStructure.m index c342e2cb..399fe3f7 100644 --- a/Source/SPDatabaseStructure.m +++ b/Source/SPDatabaseStructure.m @@ -480,19 +480,19 @@ return; } - // Retrieve the column details - theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SELECT * FROM `information_schema`.`ROUTINES` WHERE `information_schema`.`ROUTINES`.`ROUTINE_SCHEMA` = '%@'", [currentDatabase stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"]]]; + // Retrieve the column details (only those we need so we don't fetch the whole function body which might be huge) + theResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SELECT SPECIFIC_NAME, ROUTINE_TYPE, DTD_IDENTIFIER, IS_DETERMINISTIC, SQL_DATA_ACCESS, SECURITY_TYPE, DEFINER FROM `information_schema`.`ROUTINES` WHERE `ROUTINE_SCHEMA` = %@", [currentDatabase tickQuotedString]]]; [theResult setDefaultRowReturnType:SPMySQLResultRowAsArray]; // Loop through the rows and extract the function details for (NSArray *row in theResult) { - NSString *fname = [row objectAtIndex:0]; - NSString *type = ([[row objectAtIndex:4] isEqualToString:@"FUNCTION"]) ? @"3" : @"2"; - NSString *dtd = [row objectAtIndex:5]; - NSString *det = [row objectAtIndex:11]; - NSString *dataaccess = [row objectAtIndex:12]; - NSString *security_type = [row objectAtIndex:14]; - NSString *definer = [row objectAtIndex:19]; + NSString *fname = [row objectAtIndex:0]; + NSString *type = ([[row objectAtIndex:1] isEqualToString:@"FUNCTION"]) ? @"3" : @"2"; + NSString *dtd = [row objectAtIndex:2]; + NSString *det = [row objectAtIndex:3]; + NSString *dataaccess = [row objectAtIndex:4]; + NSString *security_type = [row objectAtIndex:5]; + NSString *definer = [row objectAtIndex:6]; // Generate "table" and "field" names and add to structure key store NSString *table_id = [NSString stringWithFormat:@"%@%@%@", db_id, SPUniqueSchemaDelimiter, fname]; diff --git a/Source/SPDotExporter.m b/Source/SPDotExporter.m index 62cfbc48..13bf13a5 100644 --- a/Source/SPDotExporter.m +++ b/Source/SPDotExporter.m @@ -175,10 +175,10 @@ } // Get the column references. Currently the columns themselves are an array, - // while reference columns and tables are comma separated if there are more than + // while tables are comma separated if there are more than // one. Only use the first of each for the time being. NSArray *originColumns = [constraint objectForKey:@"columns"]; - NSArray *referenceColumns = [[constraint objectForKey:@"ref_columns"] componentsSeparatedByString:@","]; + NSArray *referenceColumns = [constraint objectForKey:@"ref_columns"]; NSString *extra = @""; diff --git a/Source/SPEditorPreferencePane.m b/Source/SPEditorPreferencePane.m index b9df9845..186af05a 100644 --- a/Source/SPEditorPreferencePane.m +++ b/Source/SPEditorPreferencePane.m @@ -758,19 +758,18 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; [[NSColorPanel sharedColorPanel] close]; - SPBeginWaitingAlertSheet(@"title", - NSLocalizedString(@"Proceed", @"proceed button"), - NSLocalizedString(@"Cancel", @"cancel button"), - nil, - NSWarningAlertStyle, - [[self view] window], - self, - @selector(checkForUnsavedThemeDidEndSheet:returnCode:contextInfo:), - nil, - NSLocalizedString(@"Unsaved Theme", @"unsaved theme message"), - NSLocalizedString(@"The current color theme is unsaved. Do you want to proceed without saving it?", @"unsaved theme informative message"), - &checkForUnsavedThemeSheetStatus - ); + [SPAlertSheets beginWaitingAlertSheetWithTitle:@"title" + defaultButton:NSLocalizedString(@"Proceed", @"proceed button") + alternateButton:NSLocalizedString(@"Cancel", @"cancel button") + otherButton:nil + alertStyle:NSWarningAlertStyle + docWindow:[[self view] window] + modalDelegate:self + didEndSelector:@selector(checkForUnsavedThemeDidEndSheet:returnCode:contextInfo:) + contextInfo:nil + msg:NSLocalizedString(@"Unsaved Theme", @"unsaved theme message") + infoText:NSLocalizedString(@"The current color theme is unsaved. Do you want to proceed without saving it?", @"unsaved theme informative message") + returnCode:&checkForUnsavedThemeSheetStatus]; return (checkForUnsavedThemeSheetStatus == NSAlertDefaultReturn); } diff --git a/Source/SPExtendedTableInfo.m b/Source/SPExtendedTableInfo.m index 91c51a36..ce9e6e7f 100644 --- a/Source/SPExtendedTableInfo.m +++ b/Source/SPExtendedTableInfo.m @@ -44,8 +44,24 @@ #import <SPMySQL/SPMySQL.h> -static NSString *SPUpdateTableTypeCurrentType = @"SPUpdateTableTypeCurrentType"; static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; +static NSString *SPUpdateTableTypeCurrentType = @"SPUpdateTableTypeCurrentType"; + +// MySQL status field names +static NSString *SPMySQLEngineField = @"Engine"; +static NSString *SPMySQLRowFormatField = @"Row_format"; +static NSString *SPMySQLRowsField = @"Rows"; +static NSString *SPMySQLAverageRowLengthField = @"Avg_row_length"; +static NSString *SPMySQLDataLengthField = @"Data_length"; +static NSString *SPMySQLMaxDataLengthField = @"Max_data_length"; +static NSString *SPMySQLIndexLengthField = @"Index_length"; +static NSString *SPMySQLDataFreeField = @"Data_free"; +static NSString *SPMySQLAutoIncrementField = @"Auto_increment"; +static NSString *SPMySQLCreateTimeField = @"Create_time"; +static NSString *SPMySQLUpdateTimeField = @"Update_time"; +static NSString *SPMySQLCheckTimeField = @"Check_time"; +static NSString *SPMySQLCollationField = @"Collation"; +static NSString *SPMySQLCommentField = @"Comment"; @interface SPExtendedTableInfo () @@ -100,13 +116,13 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; - (IBAction)updateTableType:(id)sender { NSString *newType = [sender titleOfSelectedItem]; - NSString *currentType = [tableDataInstance statusValueForKey:@"Engine"]; + NSString *currentType = [tableDataInstance statusValueForKey:SPMySQLEngineField]; // Check if the user selected the same type if ([currentType isEqualToString:newType]) return; // If the table is empty, perform the change directly - if ([[[tableDataInstance statusValues] objectForKey:@"Rows"] isEqualToString:@"0"]) { + if ([[[tableDataInstance statusValues] objectForKey:SPMySQLRowsField] isEqualToString:@"0"]) { [self _changeCurrentTableTypeFrom:currentType to:newType]; return; } @@ -170,7 +186,7 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; - (IBAction)updateTableCollation:(id)sender { NSString *newCollation = [sender titleOfSelectedItem]; - NSString *currentCollation = [tableDataInstance statusValueForKey:@"Collation"]; + NSString *currentCollation = [tableDataInstance statusValueForKey:SPMySQLCollationField]; // Check if the user selected the same collation if ([currentCollation isEqualToString:newCollation]) return; @@ -252,7 +268,7 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; [tableEncodingPopUpButton setEnabled:NO]; [tableCollationPopUpButton setEnabled:NO]; - if ([[statusFields objectForKey:@"Engine"] isEqualToString:@"View"]) { + if ([[statusFields objectForKey:SPMySQLEngineField] isEqualToString:@"View"]) { [tableTypePopUpButton addItemWithTitle:@"View"]; // Set create syntax [tableCreateSyntaxTextView setEditable:YES]; @@ -297,9 +313,12 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; [tableCommentsTextView setString:@""]; [tableCommentsTextView didChangeText]; - if([[statusFields objectForKey:@"Engine"] isEqualToString:@"View"] && [statusFields objectForKey:@"CharacterSetClient"] && [statusFields objectForKey:@"Collation"]) { + if ([[statusFields objectForKey:SPMySQLEngineField] isEqualToString:@"View"] && + [statusFields objectForKey:@"CharacterSetClient"] && + [statusFields objectForKey:SPMySQLCollationField]) + { [tableEncodingPopUpButton addItemWithTitle:[statusFields objectForKey:@"CharacterSetClient"]]; - [tableCollationPopUpButton addItemWithTitle:[statusFields objectForKey:@"Collation"]]; + [tableCollationPopUpButton addItemWithTitle:[statusFields objectForKey:SPMySQLCollationField]]; } return; @@ -309,15 +328,15 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; NSArray *encodings = [databaseDataInstance getDatabaseCharacterSetEncodings]; NSArray *collations = [databaseDataInstance getDatabaseCollationsForEncoding:[tableDataInstance tableEncoding]]; - if (([engines count] > 0) && ([statusFields objectForKey:@"Engine"])) { + if (([engines count] > 0) && ([statusFields objectForKey:SPMySQLEngineField])) { // Populate type popup button for (NSDictionary *engine in engines) { - [tableTypePopUpButton addItemWithTitle:[engine objectForKey:@"Engine"]]; + [tableTypePopUpButton addItemWithTitle:[engine objectForKey:SPMySQLEngineField]]; } - [tableTypePopUpButton selectItemWithTitle:[statusFields objectForKey:@"Engine"]]; + [tableTypePopUpButton selectItemWithTitle:[statusFields objectForKey:SPMySQLEngineField]]; [tableTypePopUpButton setEnabled:enableInteraction]; } else { @@ -346,37 +365,38 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; [tableEncodingPopUpButton addItemWithTitle:NSLocalizedString(@"Not available", @"not available label")]; } - if (([collations count] > 0) && ([statusFields objectForKey:@"Collation"])) { + if (([collations count] > 0) && ([statusFields objectForKey:SPMySQLCollationField])) { + // Populate collation popup button for (NSDictionary *collation in collations) { [tableCollationPopUpButton addItemWithTitle:[collation objectForKey:@"COLLATION_NAME"]]; } - [tableCollationPopUpButton selectItemWithTitle:[statusFields objectForKey:@"Collation"]]; + [tableCollationPopUpButton selectItemWithTitle:[statusFields objectForKey:SPMySQLCollationField]]; [tableCollationPopUpButton setEnabled:enableInteraction]; } else { [tableCollationPopUpButton addItemWithTitle:NSLocalizedString(@"Not available", @"not available label")]; } - [tableCreatedAt setStringValue:[self _formatValueWithKey:@"Create_time" inDictionary:statusFields]]; - [tableUpdatedAt setStringValue:[self _formatValueWithKey:@"Update_time" inDictionary:statusFields]]; + [tableCreatedAt setStringValue:[self _formatValueWithKey:SPMySQLCreateTimeField inDictionary:statusFields]]; + [tableUpdatedAt setStringValue:[self _formatValueWithKey:SPMySQLUpdateTimeField inDictionary:statusFields]]; // Set row values - [tableRowNumber setStringValue:[self _formatValueWithKey:@"Rows" inDictionary:statusFields]]; - [tableRowFormat setStringValue:[self _formatValueWithKey:@"Row_format" inDictionary:statusFields]]; - [tableRowAvgLength setStringValue:[self _formatValueWithKey:@"Avg_row_length" inDictionary:statusFields]]; - [tableRowAutoIncrement setStringValue:[self _formatValueWithKey:@"Auto_increment" inDictionary:statusFields]]; + [tableRowNumber setStringValue:[self _formatValueWithKey:SPMySQLRowsField inDictionary:statusFields]]; + [tableRowFormat setStringValue:[self _formatValueWithKey:SPMySQLRowFormatField inDictionary:statusFields]]; + [tableRowAvgLength setStringValue:[self _formatValueWithKey:SPMySQLAverageRowLengthField inDictionary:statusFields]]; + [tableRowAutoIncrement setStringValue:[self _formatValueWithKey:SPMySQLAutoIncrementField inDictionary:statusFields]]; // Set size values - [tableDataSize setStringValue:[self _formatValueWithKey:@"Data_length" inDictionary:statusFields]]; - [tableMaxDataSize setStringValue:[self _formatValueWithKey:@"Max_data_length" inDictionary:statusFields]]; - [tableIndexSize setStringValue:[self _formatValueWithKey:@"Index_length" inDictionary:statusFields]]; - [tableSizeFree setStringValue:[self _formatValueWithKey:@"Data_free" inDictionary:statusFields]]; + [tableDataSize setStringValue:[self _formatValueWithKey:SPMySQLDataLengthField inDictionary:statusFields]]; + [tableMaxDataSize setStringValue:[self _formatValueWithKey:SPMySQLMaxDataLengthField inDictionary:statusFields]]; + [tableIndexSize setStringValue:[self _formatValueWithKey:SPMySQLIndexLengthField inDictionary:statusFields]]; + [tableSizeFree setStringValue:[self _formatValueWithKey:SPMySQLDataFreeField inDictionary:statusFields]]; // Set comments - NSString *commentText = [statusFields objectForKey:@"Comment"]; + NSString *commentText = [statusFields objectForKey:SPMySQLCommentField]; if (!commentText) commentText = @""; @@ -401,7 +421,7 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; [tableCreateSyntaxTextView setEditable:NO]; // Validate Reset AUTO_INCREMENT button - if ([statusFields objectForKey:@"Auto_increment"] && ![[statusFields objectForKey:@"Auto_increment"] isNSNull]) { + if ([statusFields objectForKey:SPMySQLAutoIncrementField] && ![[statusFields objectForKey:SPMySQLAutoIncrementField] isNSNull]) { [resetAutoIncrementResetButton setHidden:NO]; } } @@ -429,43 +449,43 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; [tableInfo setObject:[tableCollationPopUpButton titleOfSelectedItem] forKey:@"collation"]; } - if ([self _formatValueWithKey:@"Create_time" inDictionary:statusFields]) { - [tableInfo setObject:[self _formatValueWithKey:@"Create_time" inDictionary:statusFields] forKey:@"createdAt"]; + if ([self _formatValueWithKey:SPMySQLCreateTimeField inDictionary:statusFields]) { + [tableInfo setObject:[self _formatValueWithKey:SPMySQLCreateTimeField inDictionary:statusFields] forKey:@"createdAt"]; } - if ([self _formatValueWithKey:@"Update_time" inDictionary:statusFields]) { - [tableInfo setObject:[self _formatValueWithKey:@"Update_time" inDictionary:statusFields] forKey:@"updatedAt"]; + if ([self _formatValueWithKey:SPMySQLUpdateTimeField inDictionary:statusFields]) { + [tableInfo setObject:[self _formatValueWithKey:SPMySQLUpdateTimeField inDictionary:statusFields] forKey:@"updatedAt"]; } - if ([self _formatValueWithKey:@"Rows" inDictionary:statusFields]) { - [tableInfo setObject:[self _formatValueWithKey:@"Rows" inDictionary:statusFields] forKey:@"rowNumber"]; + if ([self _formatValueWithKey:SPMySQLRowsField inDictionary:statusFields]) { + [tableInfo setObject:[self _formatValueWithKey:SPMySQLRowsField inDictionary:statusFields] forKey:@"rowNumber"]; } - if ([self _formatValueWithKey:@"Row_format" inDictionary:statusFields]) { - [tableInfo setObject:[self _formatValueWithKey:@"Row_format" inDictionary:statusFields] forKey:@"rowFormat"]; + if ([self _formatValueWithKey:SPMySQLRowFormatField inDictionary:statusFields]) { + [tableInfo setObject:[self _formatValueWithKey:SPMySQLRowFormatField inDictionary:statusFields] forKey:@"rowFormat"]; } - if ([self _formatValueWithKey:@"Avg_row_length" inDictionary:statusFields]) { - [tableInfo setObject:[self _formatValueWithKey:@"Avg_row_length" inDictionary:statusFields] forKey:@"rowAvgLength"]; + if ([self _formatValueWithKey:SPMySQLAverageRowLengthField inDictionary:statusFields]) { + [tableInfo setObject:[self _formatValueWithKey:SPMySQLAverageRowLengthField inDictionary:statusFields] forKey:@"rowAvgLength"]; } - if ([self _formatValueWithKey:@"Auto_increment" inDictionary:statusFields]) { - [tableInfo setObject:[self _formatValueWithKey:@"Auto_increment" inDictionary:statusFields] forKey:@"rowAutoIncrement"]; + if ([self _formatValueWithKey:SPMySQLAutoIncrementField inDictionary:statusFields]) { + [tableInfo setObject:[self _formatValueWithKey:SPMySQLAutoIncrementField inDictionary:statusFields] forKey:@"rowAutoIncrement"]; } - if ([self _formatValueWithKey:@"Data_length" inDictionary:statusFields]) { - [tableInfo setObject:[self _formatValueWithKey:@"Data_length" inDictionary:statusFields] forKey:@"dataSize"]; + if ([self _formatValueWithKey:SPMySQLDataLengthField inDictionary:statusFields]) { + [tableInfo setObject:[self _formatValueWithKey:SPMySQLDataLengthField inDictionary:statusFields] forKey:@"dataSize"]; } - if ([self _formatValueWithKey:@"Max_data_length" inDictionary:statusFields]) { - [tableInfo setObject:[self _formatValueWithKey:@"Max_data_length" inDictionary:statusFields] forKey:@"maxDataSize"]; + if ([self _formatValueWithKey:SPMySQLMaxDataLengthField inDictionary:statusFields]) { + [tableInfo setObject:[self _formatValueWithKey:SPMySQLMaxDataLengthField inDictionary:statusFields] forKey:@"maxDataSize"]; } - if ([self _formatValueWithKey:@"Index_length" inDictionary:statusFields]) { - [tableInfo setObject:[self _formatValueWithKey:@"Index_length" inDictionary:statusFields] forKey:@"indexSize"]; + if ([self _formatValueWithKey:SPMySQLIndexLengthField inDictionary:statusFields]) { + [tableInfo setObject:[self _formatValueWithKey:SPMySQLIndexLengthField inDictionary:statusFields] forKey:@"indexSize"]; } - [tableInfo setObject:[self _formatValueWithKey:@"Data_free" inDictionary:statusFields] forKey:@"sizeFree"]; + [tableInfo setObject:[self _formatValueWithKey:SPMySQLDataFreeField inDictionary:statusFields] forKey:@"sizeFree"]; if ([tableCommentsTextView string]) { [tableInfo setObject:[tableCommentsTextView string] forKey:@"comments"]; @@ -541,6 +561,7 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; - (void)confirmChangeTableTypeDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(NSDictionary *)contextInfo { [[alert window] orderOut:self]; + if (returnCode == NSAlertDefaultReturn) { [self _changeCurrentTableTypeFrom:[contextInfo objectForKey:SPUpdateTableTypeCurrentType] to:[contextInfo objectForKey:SPUpdateTableTypeNewType]]; @@ -579,7 +600,7 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; NSDictionary *statusFields = [tableDataInstance statusValues]; - if (!selectedTable || ![selectedTable length] || [[statusFields objectForKey:@"Engine"] isEqualToString:@"View"]) return; + if (!selectedTable || ![selectedTable length] || [[statusFields objectForKey:SPMySQLEngineField] isEqualToString:@"View"]) return; // If we are viewing tables in the information_schema database, then disable all controls that cause table // changes as these tables are not modifiable by anyone. @@ -588,15 +609,18 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; [[tableDocumentInstance database] isEqualToString:SPMySQLPerformanceSchemaDatabase] || [[tableDocumentInstance database] isEqualToString:SPMySQLDatabase]); - if ([[databaseDataInstance getDatabaseStorageEngines] count] && [statusFields objectForKey:@"Engine"]) { + if ([[databaseDataInstance getDatabaseStorageEngines] count] && [statusFields objectForKey:SPMySQLEngineField]) { [tableTypePopUpButton setEnabled:(!isSystemSchemaDb)]; } - if ([[databaseDataInstance getDatabaseCharacterSetEncodings] count] && [tableDataInstance tableEncoding] && [[tableDocumentInstance serverSupport] supportsPost41CharacterSetHandling]) { + if ([[databaseDataInstance getDatabaseCharacterSetEncodings] count] && [tableDataInstance tableEncoding] && + [[tableDocumentInstance serverSupport] supportsPost41CharacterSetHandling]) + { [tableEncodingPopUpButton setEnabled:(!isSystemSchemaDb)]; } - if ([[databaseDataInstance getDatabaseCollationsForEncoding:[tableDataInstance tableEncoding]] count] && [statusFields objectForKey:@"Collation"]) + if ([[databaseDataInstance getDatabaseCollationsForEncoding:[tableDataInstance tableEncoding]] count] && + [statusFields objectForKey:SPMySQLCollationField]) { [tableCollationPopUpButton setEnabled:(!isSystemSchemaDb)]; } @@ -650,16 +674,16 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; } else { // Format size strings - if ([key isEqualToString:@"Data_length"] || - [key isEqualToString:@"Max_data_length"] || - [key isEqualToString:@"Index_length"] || - [key isEqualToString:@"Data_free"]) { + if ([key isEqualToString:SPMySQLDataLengthField] || + [key isEqualToString:SPMySQLMaxDataLengthField] || + [key isEqualToString:SPMySQLIndexLengthField] || + [key isEqualToString:SPMySQLDataFreeField]) { value = [NSString stringForByteSize:[value longLongValue]]; } // Format date strings to the user's long date format - else if ([key isEqualToString:@"Create_time"] || - [key isEqualToString:@"Update_time"]) { + else if ([key isEqualToString:SPMySQLCreateTimeField] || + [key isEqualToString:SPMySQLUpdateTimeField]) { // Create date formatter NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; @@ -672,9 +696,9 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; value = [dateFormatter stringFromDate:[NSDate dateWithNaturalLanguageString:value]]; } // Format numbers - else if ([key isEqualToString:@"Rows"] || - [key isEqualToString:@"Avg_row_length"] || - [key isEqualToString:@"Auto_increment"]) { + else if ([key isEqualToString:SPMySQLRowsField] || + [key isEqualToString:SPMySQLAverageRowLengthField] || + [key isEqualToString:SPMySQLAutoIncrementField]) { NSNumberFormatter *numberFormatter = [[[NSNumberFormatter alloc] init] autorelease]; @@ -683,13 +707,13 @@ static NSString *SPUpdateTableTypeNewType = @"SPUpdateTableTypeNewType"; value = [numberFormatter stringFromNumber:[NSNumber numberWithLongLong:[value longLongValue]]]; // Prefix number of rows with '~' if it is not an accurate count - if ([key isEqualToString:@"Rows"] && ![[infoDict objectForKey:@"RowsCountAccurate"] boolValue]) { + if ([key isEqualToString:SPMySQLRowsField] && ![[infoDict objectForKey:@"RowsCountAccurate"] boolValue]) { value = [@"~" stringByAppendingString:value]; } } } - return ([value length] > 0) ? value : NSLocalizedString(@"Not available", @"not available label"); + return [value length] ? value : NSLocalizedString(@"Not available", @"not available label"); } #pragma mark - diff --git a/Source/SPFavoritesOutlineView.h b/Source/SPFavoritesOutlineView.h index d2fa0846..8eb45ed0 100644 --- a/Source/SPFavoritesOutlineView.h +++ b/Source/SPFavoritesOutlineView.h @@ -33,6 +33,7 @@ @interface SPFavoritesOutlineView : NSOutlineView { SInt32 systemVersion; + BOOL justGainedFocus; } @property (assign) BOOL justGainedFocus; diff --git a/Source/SPNavigatorController.m b/Source/SPNavigatorController.m index 9977773c..6e7c3d68 100644 --- a/Source/SPNavigatorController.m +++ b/Source/SPNavigatorController.m @@ -1250,28 +1250,28 @@ static NSComparisonResult compareStrings(NSString *s1, NSString *s2, void* conte if(type == 2) // PROCEDURE switch(anIndex) { case 0: - return @"DTD Identifier"; + return NSLocalizedString(@"DTD Identifier",@"dtd identifier label (Navigator)"); case 1: - return @"SQL Data Access"; + return NSLocalizedString(@"SQL Data Access",@"sql data access label (Navigator)"); case 2: - return @"Is Deterministic"; + return NSLocalizedString(@"Is Deterministic",@"is deterministic label (Navigator)"); case 3: return NSLocalizedString(@"Execution Privilege", @"execution privilege label (Navigator)"); case 4: - return @"Definer"; + return NSLocalizedString(@"Definer",@"definer label (Navigator)"); } if(type == 3) // FUNCTION switch(anIndex) { case 0: return NSLocalizedString(@"Return Type", @"return type label (Navigator)"); case 1: - return @"SQL Data Access"; + return NSLocalizedString(@"SQL Data Access",@"sql data access label (Navigator)"); case 2: - return @"Is Deterministic"; + return NSLocalizedString(@"Is Deterministic",@"is deterministic label (Navigator)"); case 3: return NSLocalizedString(@"Execution Privilege", @"execution privilege label (Navigator)"); case 4: - return @"Definer"; + return NSLocalizedString(@"Definer",@"definer label (Navigator)"); } return @""; } diff --git a/Source/SPProcessListController.m b/Source/SPProcessListController.m index 7540ed43..2b26eb90 100644 --- a/Source/SPProcessListController.m +++ b/Source/SPProcessListController.m @@ -246,7 +246,7 @@ static NSString *SPTableViewIDColumnIdentifier = @"Id"; // No process selected. Interface validation should prevent this. if ([processListTableView numberOfSelectedRows] != 1) return; - long long processId = [[[processes objectAtIndex:[processListTableView selectedRow]] valueForKey:@"Id"] longLongValue]; + long long processId = [[[processesFiltered objectAtIndex:[processListTableView selectedRow]] valueForKey:@"Id"] longLongValue]; NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Kill query?", @"kill query message") defaultButton:NSLocalizedString(@"Kill", @"kill button") @@ -274,7 +274,7 @@ static NSString *SPTableViewIDColumnIdentifier = @"Id"; // No process selected. Interface validation should prevent this. if ([processListTableView numberOfSelectedRows] != 1) return; - long long processId = [[[processes objectAtIndex:[processListTableView selectedRow]] valueForKey:@"Id"] longLongValue]; + long long processId = [[[processesFiltered objectAtIndex:[processListTableView selectedRow]] valueForKey:@"Id"] longLongValue]; NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Kill connection?", @"kill connection message") defaultButton:NSLocalizedString(@"Kill", @"kill button") @@ -382,7 +382,7 @@ static NSString *SPTableViewIDColumnIdentifier = @"Id"; [self _startAutoRefreshTimerWithInterval:[customIntervalTextField integerValue]]; } else { - long long processId = [[[processes objectAtIndex:[processListTableView selectedRow]] valueForKey:@"Id"] longLongValue]; + long long processId = [[[processesFiltered objectAtIndex:[processListTableView selectedRow]] valueForKey:@"Id"] longLongValue]; if ([contextInfo isEqualToString:SPKillProcessQueryMode]) { [self _killProcessQueryWithId:processId]; @@ -478,70 +478,6 @@ static NSString *SPTableViewIDColumnIdentifier = @"Id"; } #pragma mark - -#pragma mark Tableview delegate methods - -/** - * Table view delegate method. Returns the number of rows in the table veiw. - */ -- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView -{ - return [processesFiltered count]; -} - -/** - * Table view delegate method. Returns the specific object for the request column and row. - */ -- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row -{ - id object = ((NSUInteger)row < [processesFiltered count]) ? [[processesFiltered objectAtIndex:row] valueForKey:[tableColumn identifier]] : @""; - - if ([object isNSNull]) { - return [prefs stringForKey:SPNullValue]; - } - - // If the string is exactly 100 characters long, and FULL process lists are not enabled, it's a safe - // bet that the string is truncated - if (!showFullProcessList && [object isKindOfClass:[NSString class]] && [(NSString *)object length] == 100) { - return [object stringByAppendingString:@"…"]; - } - - return object; -} - -/** - * Table view delegate method. Called when the user changes the sort by column. - */ -- (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray *)oldDescriptors -{ - [processesFiltered sortUsingDescriptors:[tableView sortDescriptors]]; - - [tableView reloadData]; -} - -/** - * Table view delegate method. Called whenever the user changes a column width. - */ -- (void)tableViewColumnDidResize:(NSNotification *)notification -{ - NSTableColumn *column = [[notification userInfo] objectForKey:@"NSTableColumn"]; - - // Get the existing table column widths dictionary if it exists - NSMutableDictionary *tableColumnWidths = ([prefs objectForKey:SPProcessListTableColumnWidths]) ? - [NSMutableDictionary dictionaryWithDictionary:[prefs objectForKey:SPProcessListTableColumnWidths]] : - [NSMutableDictionary dictionary]; - - // Save column size - NSString *columnName = [[column headerCell] stringValue]; - - if (columnName) { - [tableColumnWidths setObject:[NSNumber numberWithDouble:[column width]] forKey:columnName]; - - [prefs setObject:tableColumnWidths forKey:SPProcessListTableColumnWidths]; - } -} - - -#pragma mark - #pragma mark Text field delegate methods /** diff --git a/Source/SPProcessListControllerDataSource.h b/Source/SPProcessListControllerDataSource.h new file mode 100644 index 00000000..3d0cc571 --- /dev/null +++ b/Source/SPProcessListControllerDataSource.h @@ -0,0 +1,35 @@ +// +// $Id$ +// +// SPProcessListControllerDataSource.h +// sequel-pro +// +// Created by Stuart Connolly (stuconnolly.com) on April 3, 2013. +// Copyright (c) 2013 Stuart Connolly. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#import "SPProcessListController.h" + +@interface SPProcessListController (SPProcessListControllerDataSource) + +@end diff --git a/Source/SPProcessListControllerDataSource.m b/Source/SPProcessListControllerDataSource.m new file mode 100644 index 00000000..90e0c113 --- /dev/null +++ b/Source/SPProcessListControllerDataSource.m @@ -0,0 +1,98 @@ +// +// $Id$ +// +// SPProcessListControllerDataSource.m +// sequel-pro +// +// Created by Stuart Connolly (stuconnolly.com) on April 3, 2013. +// Copyright (c) 2013 Stuart Connolly. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#import "SPProcessListControllerDataSource.h" + +@implementation SPProcessListController (SPProcessListControllerDataSource) + +#pragma mark - +#pragma mark Tableview delegate methods + +/** + * Table view delegate method. Returns the number of rows in the table veiw. + */ +- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView +{ + return [processesFiltered count]; +} + +/** + * Table view delegate method. Returns the specific object for the request column and row. + */ +- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + id object = ((NSUInteger)row < [processesFiltered count]) ? [[processesFiltered objectAtIndex:row] valueForKey:[tableColumn identifier]] : @""; + + if ([object isNSNull]) { + return [prefs stringForKey:SPNullValue]; + } + + // If the string is exactly 100 characters long, and FULL process lists are not enabled, it's a safe + // bet that the string is truncated + if (!showFullProcessList && [object isKindOfClass:[NSString class]] && [(NSString *)object length] == 100) { + return [object stringByAppendingString:@"…"]; + } + + return object; +} + +/** + * Table view delegate method. Called when the user changes the sort by column. + */ +- (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray *)oldDescriptors +{ + [processesFiltered sortUsingDescriptors:[tableView sortDescriptors]]; + + [tableView reloadData]; +} + +/** + * Table view delegate method. Called whenever the user changes a column width. + */ +- (void)tableViewColumnDidResize:(NSNotification *)notification +{ + NSTableColumn *column = [[notification userInfo] objectForKey:@"NSTableColumn"]; + + // Get the existing table column widths dictionary if it exists + NSMutableDictionary *tableColumnWidths = ([prefs objectForKey:SPProcessListTableColumnWidths]) ? + [NSMutableDictionary dictionaryWithDictionary:[prefs objectForKey:SPProcessListTableColumnWidths]] : + [NSMutableDictionary dictionary]; + + // Save column size + NSString *columnName = [[column headerCell] stringValue]; + + if (columnName) { + [tableColumnWidths setObject:[NSNumber numberWithDouble:[column width]] forKey:columnName]; + + [prefs setObject:tableColumnWidths forKey:SPProcessListTableColumnWidths]; + } +} + +@end diff --git a/Source/SPSQLExporter.m b/Source/SPSQLExporter.m index c1ce7412..f2ee87bb 100644 --- a/Source/SPSQLExporter.m +++ b/Source/SPSQLExporter.m @@ -882,7 +882,11 @@ if ([[column objectForKey:@"unsigned"] integerValue] == 1) [fieldString appendString:@" UNSIGNED"]; if ([[column objectForKey:@"zerofill"] integerValue] == 1) [fieldString appendString:@" ZEROFILL"]; if ([[column objectForKey:@"binary"] integerValue] == 1) [fieldString appendString:@" BINARY"]; - if ([[column objectForKey:@"null"] integerValue] == 0) [fieldString appendString:@" NOT NULL"]; + if ([[column objectForKey:@"null"] integerValue] == 0) { + [fieldString appendString:@" NOT NULL"]; + } else { + [fieldString appendString:@" NULL"]; + } // Provide the field default if appropriate if ([column objectForKey:@"default"]) { diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m index 136613dc..08c5c736 100644 --- a/Source/SPTableContent.m +++ b/Source/SPTableContent.m @@ -512,7 +512,7 @@ static NSString *SPTableFilterSetDefaultOperator = @"SPTableFilterSetDefaultOper for (NSDictionary *constraint in constraints) { NSString *firstColumn = [[constraint objectForKey:@"columns"] objectAtIndex:0]; - NSString *firstRefColumn = [[[constraint objectForKey:@"ref_columns"] componentsSeparatedByString:@","] objectAtIndex:0]; + NSString *firstRefColumn = [[constraint objectForKey:@"ref_columns"] objectAtIndex:0]; NSUInteger columnIndex = [columnNames indexOfObject:firstColumn]; if (columnIndex != NSNotFound && ![[dataColumns objectAtIndex:columnIndex] objectForKey:@"foreignkeyreference"]) { diff --git a/Source/SPTableData.m b/Source/SPTableData.m index a591226e..b7826264 100644 --- a/Source/SPTableData.m +++ b/Source/SPTableData.m @@ -645,8 +645,16 @@ [fieldsParser setString:[[parts objectAtIndex:6] stringByTrimmingCharactersInSet:bracketSet]]; [constraintDetails setObject:[fieldsParser unquotedString] forKey:@"ref_table"]; - [fieldsParser setString:[[parts objectAtIndex:7] stringByTrimmingCharactersInSet:bracketSet]]; - [constraintDetails setObject:[fieldsParser unquotedString] forKey:@"ref_columns"]; + NSMutableArray *refKeyColumns = [NSMutableArray array]; + NSArray *refKeyColumnStrings = [[[parts objectAtIndex:7] stringByTrimmingCharactersInSet:bracketSet] componentsSeparatedByString:@","]; + + for (NSString *keyColumn in refKeyColumnStrings) + { + [fieldsParser setString:[[keyColumn stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] stringByTrimmingCharactersInSet:bracketSet]]; + [refKeyColumns addObject:[fieldsParser unquotedString]]; + } + + [constraintDetails setObject:refKeyColumns forKey:@"ref_columns"]; NSUInteger nextOffs = 12; diff --git a/Source/SPTableFieldValidation.m b/Source/SPTableFieldValidation.m index bcd1dc8b..3a465338 100644 --- a/Source/SPTableFieldValidation.m +++ b/Source/SPTableFieldValidation.m @@ -102,7 +102,7 @@ if (![fieldTypes containsObject:type]) return YES; - return (([fieldTypes indexOfObject:type] > 17) && ([fieldTypes indexOfObject:type] < 32)); + return ((([fieldTypes indexOfObject:type] > 17) && ([fieldTypes indexOfObject:type] < 24) || (([fieldTypes indexOfObject:type] > 29) && ([fieldTypes indexOfObject:type] < 32)))); } /** diff --git a/Source/SPTableRelations.m b/Source/SPTableRelations.m index 45450bf1..26ab8195 100644 --- a/Source/SPTableRelations.m +++ b/Source/SPTableRelations.m @@ -589,9 +589,9 @@ static NSString *SPRelationOnDeleteKey = @"on_delete"; { [relationData addObject:[NSDictionary dictionaryWithObjectsAndKeys: [constraint objectForKey:SPRelationNameKey], SPRelationNameKey, - [[constraint objectForKey:SPRelationColumnsKey] objectAtIndex:0], SPRelationColumnsKey, + [[constraint objectForKey:SPRelationColumnsKey] componentsJoinedByCommas], SPRelationColumnsKey, [constraint objectForKey:@"ref_table"], SPRelationFKTableKey, - [constraint objectForKey:@"ref_columns"], SPRelationFKColumnsKey, + [[constraint objectForKey:@"ref_columns"] componentsJoinedByCommas], SPRelationFKColumnsKey, ([constraint objectForKey:@"update"] ? [constraint objectForKey:@"update"] : @""), SPRelationOnUpdateKey, ([constraint objectForKey:@"delete"] ? [constraint objectForKey:@"delete"] : @""), SPRelationOnDeleteKey, nil]]; @@ -624,7 +624,7 @@ static NSString *SPRelationOnDeleteKey = @"on_delete"; [tableDataInstance resetAllData]; NSDictionary *tableInfo = [tableDataInstance informationForTable:table]; - NSArray *columns = [tableInfo objectForKey:SPRelationColumnsKey]; + NSArray *columns = [tableInfo objectForKey:@"columns"]; NSMutableArray *validColumns = [NSMutableArray array]; diff --git a/Source/SPTableStructure.m b/Source/SPTableStructure.m index fcbc7d13..01ff6be9 100644 --- a/Source/SPTableStructure.m +++ b/Source/SPTableStructure.m @@ -796,7 +796,7 @@ } // ADD COLLATE - if([fieldEncoding length] && [[theRow objectForKey:@"collation"] integerValue] > 0) { + if([fieldEncoding length] && [[theRow objectForKey:@"collation"] integerValue] > 0 && ![[theRow objectForKey:@"binary"] integerValue]) { NSArray *theCollations = [databaseDataInstance getDatabaseCollationsForEncoding:fieldEncoding]; NSString *col = [[theCollations objectAtIndex:[[theRow objectForKey:@"collation"] integerValue]-1] objectForKey:@"COLLATION_NAME"]; [queryString appendFormat:@"\n COLLATE %@", col]; diff --git a/Source/SPTableStructureDelegate.m b/Source/SPTableStructureDelegate.m index d797f7ab..858f97f2 100644 --- a/Source/SPTableStructureDelegate.m +++ b/Source/SPTableStructureDelegate.m @@ -558,12 +558,12 @@ // Only string fields allow encoding settings if (([[aTableColumn identifier] isEqualToString:@"encoding"])) { - [aCell setEnabled:([fieldValidation isFieldTypeString:theRowType] && ![theRowType hasSuffix:@"BINARY"] && ![theRowType hasSuffix:@"BLOB"]) && [[tableDocumentInstance serverSupport] supportsPost41CharacterSetHandling]]; + [aCell setEnabled:([fieldValidation isFieldTypeString:theRowType] && [[tableDocumentInstance serverSupport] supportsPost41CharacterSetHandling])]; } // Only string fields allow collation settings and string field is not set to BINARY since BINARY sets the collation to *_bin else if ([[aTableColumn identifier] isEqualToString:@"collation"]) { - [aCell setEnabled:([fieldValidation isFieldTypeString:theRowType] && [[theRow objectForKey:@"binary"] integerValue] == 0 && ![theRowType hasSuffix:@"BINARY"] && ![theRowType hasSuffix:@"BLOB"] && [[tableDocumentInstance serverSupport] supportsPost41CharacterSetHandling])]; + [aCell setEnabled:([fieldValidation isFieldTypeString:theRowType] && [[theRow objectForKey:@"binary"] integerValue] == 0 && [[tableDocumentInstance serverSupport] supportsPost41CharacterSetHandling])]; } // Check if UNSIGNED and ZEROFILL is allowed diff --git a/Source/SPTableStructureLoading.m b/Source/SPTableStructureLoading.m index 4d7bb4dd..c7177720 100644 --- a/Source/SPTableStructureLoading.m +++ b/Source/SPTableStructureLoading.m @@ -170,7 +170,7 @@ NSString *collation = nil; NSString *encoding = nil; - if ([fieldValidation isFieldTypeString:type] && ![type hasSuffix:@"BINARY"] && ![type hasSuffix:@"BLOB"]) { + if ([fieldValidation isFieldTypeString:type]) { collation = [theField objectForKey:@"collation"] ? [theField objectForKey:@"collation"] : [[tableDataInstance statusValues] objectForKey:@"collation"]; encoding = [theField objectForKey:@"encoding"] ? [theField objectForKey:@"encoding"] : [tableDataInstance tableEncoding]; |