diff options
author | stuconnolly <stuart02@gmail.com> | 2009-11-12 23:44:09 +0000 |
---|---|---|
committer | stuconnolly <stuart02@gmail.com> | 2009-11-12 23:44:09 +0000 |
commit | a5af1bc73e296ff0b545310782a446259d896389 (patch) | |
tree | 82165af1afe69187bafd3e96c8b6e9bb41b4700b /Source | |
parent | 64010e52c3f4bcec585b7fb2494ccf38a481b5f6 (diff) | |
download | sequelpro-a5af1bc73e296ff0b545310782a446259d896389.tar.gz sequelpro-a5af1bc73e296ff0b545310782a446259d896389.tar.bz2 sequelpro-a5af1bc73e296ff0b545310782a446259d896389.zip |
- New server processes panel, accessible via the 'Database' menu and alt+cmd+P. Includes the ability to kill queries and connections as well as live filtering support and the ability to save all processes or the current filtered set to a file. Implements issue #458.
- Reorganise 'Database' menu.
- Give 'Flush Privileges' key equivalent of shift+cmd+F.
Diffstat (limited to 'Source')
-rw-r--r-- | Source/SPConstants.h | 6 | ||||
-rw-r--r-- | Source/SPConstants.m | 4 | ||||
-rw-r--r-- | Source/SPProcessListController.h | 56 | ||||
-rw-r--r-- | Source/SPProcessListController.m | 498 | ||||
-rw-r--r-- | Source/TableDocument.h | 4 | ||||
-rw-r--r-- | Source/TableDocument.m | 36 |
6 files changed, 598 insertions, 6 deletions
diff --git a/Source/SPConstants.h b/Source/SPConstants.h index aafabd73..e42b11b7 100644 --- a/Source/SPConstants.h +++ b/Source/SPConstants.h @@ -58,7 +58,7 @@ #define MAIN_TOOLBAR_TABLE_RELATIONS @"SwitchToTableRelationsToolbarItemIdentifier" #define MAIN_TOOLBAR_USER_MANAGER @"SwitchToUserManagerToolbarItemIdentifier" -// View Modes +// View modes typedef enum { SPStructureViewMode = 1, SPContentViewMode = 2, @@ -67,6 +67,10 @@ typedef enum { SPQueryEditorViewMode = 5 } SPViewMode; +// Kill mode constants +extern NSString *SPKillProcessQueryMode; +extern NSString *SPKillProcessConnectionMode; + // Preference key constants // General Prefpane extern NSString *SPDefaultFavorite; diff --git a/Source/SPConstants.m b/Source/SPConstants.m index 21b9bfe7..188a6282 100644 --- a/Source/SPConstants.m +++ b/Source/SPConstants.m @@ -25,6 +25,10 @@ #import "SPConstants.h" +// Kill mode constants +NSString *SPKillProcessQueryMode = @"SPKillProcessQueryMode"; +NSString *SPKillProcessConnectionMode = @"SPKillProcessConnectionMode"; + // Preference key constants // General Prefpane NSString *SPDefaultFavorite = @"DefaultFavorite"; diff --git a/Source/SPProcessListController.h b/Source/SPProcessListController.h new file mode 100644 index 00000000..3e93f117 --- /dev/null +++ b/Source/SPProcessListController.h @@ -0,0 +1,56 @@ +// +// $Id$ +// +// SPProcessListController.h +// sequel-pro +// +// Created by Stuart Connolly (stuconnolly.com) on November 12, 2009 +// Copyright (c) 2009 Stuart Connolly. All rights reserved. +// +// 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 MCPConnection; + +@interface SPProcessListController : NSWindowController +{ + MCPConnection *connection; + + NSMutableArray *processes, *processesFiltered; + + IBOutlet NSTableView *processListTableView; + IBOutlet NSTextField *processesCountTextField; + IBOutlet NSSearchField *filterProcessesSearchField; + IBOutlet NSProgressIndicator *refreshProgressIndicator; + IBOutlet NSButton *closeProcessListButton; + IBOutlet NSButton *saveProcessesButton; + IBOutlet NSButton *refreshProcessesButton; +} + +@property (readwrite, assign) MCPConnection *connection; + +- (IBAction)copy:(id)sender; +- (IBAction)closeSheet:(id)sender; +- (IBAction)refreshProcessList:(id)sender; +- (IBAction)saveServerProcesses:(id)sender; +- (IBAction)killProcessQuery:(id)sender; +- (IBAction)killProcessConnection:(id)sender; + +- (void)displayProcessListSheetAttachedToWindow:(NSWindow *)window; + +@end diff --git a/Source/SPProcessListController.m b/Source/SPProcessListController.m new file mode 100644 index 00000000..c1f52d3c --- /dev/null +++ b/Source/SPProcessListController.m @@ -0,0 +1,498 @@ +// +// $Id$ +// +// SPProcessListController.m +// sequel-pro +// +// Created by Stuart Connolly (stuconnolly.com) on November 12, 2009 +// Copyright (c) 2009 Stuart Connolly. All rights reserved. +// +// 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 <MCPKit/MCPKit.h> + +#import "SPProcessListController.h" +#import "SPConstants.h" +#import "SPArrayAdditions.h" + +@interface SPProcessListController (PrivateAPI) + +- (void)_getDatabaseProcessList; +- (void)_killProcessQueryWithId:(NSUInteger)processId; +- (void)_killProcessConnectionWithId:(NSUInteger)processId; +- (void)_updateServerProcessesFilterForFilterString:(NSString *)filterString; + +@end + +@implementation SPProcessListController + +@synthesize connection; + +/** + * Initialisation + */ +- (id)init +{ + if ((self = [super initWithWindowNibName:@"DatabaseProcessList"])) { + processes = [[NSMutableArray alloc] init]; + } + + return self; +} + +/** + * Interface initialisation + */ +- (void)awakeFromNib +{ + // Set the process table view's vertical gridlines if required + [processListTableView setGridStyleMask:([[NSUserDefaults standardUserDefaults] boolForKey:SPDisplayTableViewVerticalGridlines]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone]; +} + +#pragma mark - +#pragma mark IBAction methods + +/** + * Copies the currently selected process(es) to the pasteboard. + */ +- (IBAction)copy:(id)sender +{ + NSResponder *firstResponder = [[self window] firstResponder]; + + if ((firstResponder == processListTableView) && ([processListTableView numberOfSelectedRows] > 0)) { + + NSMutableString *string = [NSMutableString string]; + NSIndexSet *rows = [processListTableView selectedRowIndexes]; + + NSUInteger i = [rows firstIndex]; + + while (i != NSNotFound) + { + if (i < [processesFiltered count]) { + NSDictionary *process = NSArrayObjectAtIndex(processesFiltered, i); + + NSString *stringTmp = [NSString stringWithFormat:@"%@ %@ %@ %@ %@ %@ %@ %@", + [process objectForKey:@"Id"], + [process objectForKey:@"User"], + [process objectForKey:@"Host"], + [process objectForKey:@"db"], + [process objectForKey:@"Command"], + [process objectForKey:@"Time"], + [process objectForKey:@"State"], + [process objectForKey:@"Info"]]; + + [string appendString:stringTmp]; + [string appendString:@"\n"]; + } + + i = [rows indexGreaterThanIndex:i]; + } + + NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; + + // Copy the string to the pasteboard + [pasteBoard declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] owner:nil]; + [pasteBoard setString:string forType:NSStringPboardType]; + } +} + +/** + * Close the process list sheet. + */ +- (IBAction)closeSheet:(id)sender +{ + [NSApp endSheet:[self window] returnCode:[sender tag]]; + [[self window] orderOut:self]; + + // If the filtered array is allocated and it's not a reference to the processes array get rid of it + if ((processesFiltered) && (processesFiltered != processes)) { + [processesFiltered release], processesFiltered = nil; + } +} + +/** + * Refreshes the process list. + */ +- (IBAction)refreshProcessList:(id)sender +{ + // Start progress Indicator + [refreshProgressIndicator startAnimation:self]; + [refreshProgressIndicator setHidden:NO]; + + // Disable controls + [refreshProcessesButton setEnabled:NO]; + [closeProcessListButton setEnabled:NO]; + [saveProcessesButton setEnabled:NO]; + [filterProcessesSearchField setEnabled:NO]; + + [self _getDatabaseProcessList]; + + // Reapply any filters is required + if ([[filterProcessesSearchField stringValue] length] > 0) { + [self _updateServerProcessesFilterForFilterString:[filterProcessesSearchField stringValue]]; + } + + [processListTableView reloadData]; + + // Enable controls + [filterProcessesSearchField setEnabled:YES]; + [saveProcessesButton setEnabled:YES]; + [closeProcessListButton setEnabled:YES]; + [refreshProcessesButton setEnabled:YES]; + + // Stop progress Indicator + [refreshProgressIndicator stopAnimation:self]; + [refreshProgressIndicator setHidden:YES]; +} + +/** + * Saves the process list to the selected file. + */ +- (IBAction)saveServerProcesses:(id)sender +{ + NSSavePanel *panel = [NSSavePanel savePanel]; + + [panel setExtensionHidden:NO]; + [panel setAllowsOtherFileTypes:YES]; + [panel setCanSelectHiddenExtension:YES]; + + [panel beginSheetForDirectory:nil file:@"ServerProcesses" modalForWindow:[self window] modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:nil]; +} + +/** + * Kills the currently selected process' query. + */ +- (IBAction)killProcessQuery:(id)sender +{ + // No process selected. Interface validation should prevent this. + if ([processListTableView numberOfSelectedRows] != 1) return; + + NSUInteger processId = [[[processes objectAtIndex:[processListTableView selectedRow]] valueForKey:@"Id"] integerValue]; + + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Kill query?", @"kill query message") + defaultButton:NSLocalizedString(@"Kill", @"kill button") + alternateButton:NSLocalizedString(@"Cancel", @"cancel button") + otherButton:nil + informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"Are you sure you want to kill the current query executing on connection ID %d.\n\nPlease be aware that continuing to kill this query may result in data corruption. Please proceed with caution.", @"kill query informative message"), processId]]; + + NSArray *buttons = [alert buttons]; + + // Change the alert's cancel button to have the key equivalent of return + [[buttons objectAtIndex:0] setKeyEquivalent:@"k"]; + [[buttons objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask]; + [[buttons objectAtIndex:1] setKeyEquivalent:@"\r"]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + + [alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:SPKillProcessQueryMode]; +} + +/** + * Kills the currently selected proceess' connection. + */ +- (IBAction)killProcessConnection:(id)sender +{ + // No process selected. Interface validation should prevent this. + if ([processListTableView numberOfSelectedRows] != 1) return; + + NSUInteger processId = [[[processes objectAtIndex:[processListTableView selectedRow]] valueForKey:@"Id"] integerValue]; + + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Kill connection?", @"kill connection message") + defaultButton:NSLocalizedString(@"Kill", @"kill button") + alternateButton:NSLocalizedString(@"Cancel", @"cancel button") + otherButton:nil + informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"Are you sure you want to kill connection ID %d.\n\nPlease be aware that continuing to kill this connection may result in data corruption. Please proceed with caution.", @"kill connection informative message"), processId]]; + + NSArray *buttons = [alert buttons]; + + // Change the alert's cancel button to have the key equivalent of return + [[buttons objectAtIndex:0] setKeyEquivalent:@"k"]; + [[buttons objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask]; + [[buttons objectAtIndex:1] setKeyEquivalent:@"\r"]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + + [alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:SPKillProcessConnectionMode]; +} + +#pragma mark - +#pragma mark Other methods + +/** + * Displays the process list sheet attached to the supplied window. + */ +- (void)displayProcessListSheetAttachedToWindow:(NSWindow *)window +{ + // Weak reference + processesFiltered = processes; + + // Get the current process list + [self _getDatabaseProcessList]; + + // Reload the tableview + [processListTableView reloadData]; + + // If the search field already has value from when the panel was previously open, apply the filter. + if ([[filterProcessesSearchField stringValue] length] > 0) { + [self _updateServerProcessesFilterForFilterString:[filterProcessesSearchField stringValue]]; + } + + // Open the sheet + [NSApp beginSheet:[self window] modalForWindow:window modalDelegate:self didEndSelector:nil contextInfo:nil]; +} + +/** + * Invoked when the kill alerts are dismissed. Decide what to do based on the user's decision. + */ +- (void)sheetDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo +{ + if (returnCode == NSAlertDefaultReturn) { + NSUInteger processId = [[[processes objectAtIndex:[processListTableView selectedRow]] valueForKey:@"Id"] integerValue]; + + if ([contextInfo isEqualToString:SPKillProcessQueryMode]) { + [self _killProcessQueryWithId:processId]; + } + else if ([contextInfo isEqualToString:SPKillProcessConnectionMode]) { + [self _killProcessConnectionWithId:processId]; + } + } +} + +/** + * Invoked when the save panel is dismissed. + */ +- (void)savePanelDidEnd:(NSSavePanel *)panel returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo +{ + if (returnCode == NSAlertDefaultReturn) { + if ([processesFiltered count] > 0) { + NSMutableString *processesString = [NSMutableString string]; + + for (NSDictionary *process in processesFiltered) + { + NSString *stringTmp = [NSString stringWithFormat:@"%@ %@ %@ %@ %@ %@ %@ %@", + [process objectForKey:@"Id"], + [process objectForKey:@"User"], + [process objectForKey:@"Host"], + [process objectForKey:@"db"], + [process objectForKey:@"Command"], + [process objectForKey:@"Time"], + [process objectForKey:@"State"], + [process objectForKey:@"Info"]]; + + [processesString appendString:stringTmp]; + [processesString appendString:@"\n"]; + } + + [processesString writeToFile:[panel filename] atomically:YES encoding:NSUTF8StringEncoding error:NULL]; + } + } +} + +/** + * Menu item validation. + */ +- (BOOL)validateMenuItem:(NSMenuItem *)menuItem +{ + SEL action = [menuItem action]; + + if (action == @selector(copy:)) { + return ([processListTableView numberOfSelectedRows] > 0); + } + + if ((action == @selector(killProcessQuery:)) || (action == @selector(killProcessConnection:))) { + return ([processListTableView numberOfSelectedRows] == 1); + } + + return YES; +} + +/** + * This method is called as part of Key Value Observing which is used to watch for prefernce changes which effect the interface. + */ +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ([keyPath isEqualToString:SPDisplayTableViewVerticalGridlines]) { + [processListTableView setGridStyleMask:([[change objectForKey:NSKeyValueChangeNewKey] boolValue]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone]; + } +} + +#pragma mark - +#pragma mark Tableview delegate methods + +/** + * Table view delegate method. Returns the number of rows in the table veiw. + */ +- (int)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 = [[processesFiltered objectAtIndex:row] valueForKey:[tableColumn identifier]]; + + return (![object isNSNull]) ? object : @"NULL"; +} + +#pragma mark - +#pragma mark Text field delegate methods + +/** + * Apply the filter string to the current process list. + */ +- (void)controlTextDidChange:(NSNotification *)notification +{ + id object = [notification object]; + + if (object == filterProcessesSearchField) { + [self _updateServerProcessesFilterForFilterString:[object stringValue]]; + } +} + +#pragma mark - + +/** + * Dealloc + */ +- (void)dealloc +{ + [processes release], processes = nil; + + [super dealloc]; +} + +@end + +@implementation SPProcessListController (PrivateAPI) + +/** + * Gets the current process list form the database; + */ +- (void)_getDatabaseProcessList +{ + NSUInteger i = 0; + + // Get processes + MCPResult *processList = [connection queryString:@"SHOW PROCESSLIST"]; + + if ([processList numOfRows]) [processList dataSeek:0]; + + [processes removeAllObjects]; + + for (i = 0; i < [processList numOfRows]; i++) + { + [processes addObject:[processList fetchRowAsDictionary]]; + } +} + +/** + * Attempts to kill the query executing on the connection associate with the supplied ID. + */ +- (void)_killProcessQueryWithId:(NSUInteger)processId +{ + // Kill the query + [connection queryString:[NSString stringWithFormat:@"KILL QUERY %d", processId]]; + + // Check for errors + if (![[connection getLastErrorMessage] isEqualToString:@""]) { + NSBeginAlertSheet(NSLocalizedString(@"Unable to kill query", @"error killing query message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [self window], self, nil, nil, nil, + [NSString stringWithFormat:NSLocalizedString(@"An error occured while attempting to kill the query associated with connection %d.\n\nMySQL said: %@", @"error killing query informative message"), processId, [connection getLastErrorMessage]]); + } + + // Refresh the process list + [self refreshProcessList:self]; +} + +/** + * Attempts the kill the connection associated with the supplied ID. + */ +- (void)_killProcessConnectionWithId:(NSUInteger)processId +{ + // Kill the connection + [connection queryString:[NSString stringWithFormat:@"KILL CONNECTION %d", processId]]; + + // Check for errors + if (![[connection getLastErrorMessage] isEqualToString:@""]) { + NSBeginAlertSheet(NSLocalizedString(@"Unable to kill connection", @"error killing connection message"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [self window], self, nil, nil, nil, + [NSString stringWithFormat:NSLocalizedString(@"An error occured while attempting to kill connection %d.\n\nMySQL said: %@", @"error killing query informative message"), processId, [connection getLastErrorMessage]]); + } + + // Refresh the process list + [self refreshProcessList:self]; +} + +/** + * Filter the displayed server processes against the supplied filter string. + */ +- (void)_updateServerProcessesFilterForFilterString:(NSString *)filterString +{ + [saveProcessesButton setEnabled:NO]; + + filterString = [[filterString lowercaseString] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + + // If the filtered array is allocated and its not a reference to the processes array, + // relase it to prevent memory leaks upon the next allocation. + if ((processesFiltered) && (processesFiltered != processes)) { + [processesFiltered release], processesFiltered = nil; + } + + processesFiltered = [[NSMutableArray alloc] init]; + + if ([filterString length] == 0) { + [processesFiltered release]; + processesFiltered = processes; + + [saveProcessesButton setEnabled:YES]; + [saveProcessesButton setTitle:@"Save As..."]; + [processesCountTextField setStringValue:@""]; + + [processListTableView reloadData]; + + return; + } + + // Perform filtering + for (NSDictionary *process in processes) + { + if (([[process objectForKey:@"Id"] rangeOfString:filterString options:NSCaseInsensitiveSearch].location != NSNotFound) || + ([[process objectForKey:@"User"] rangeOfString:filterString options:NSCaseInsensitiveSearch].location != NSNotFound) || + ([[process objectForKey:@"Host"] rangeOfString:filterString options:NSCaseInsensitiveSearch].location != NSNotFound) || + ((![[process objectForKey:@"db"] isNSNull]) && ([[process objectForKey:@"db"] rangeOfString:filterString options:NSCaseInsensitiveSearch].location != NSNotFound)) || + ([[process objectForKey:@"Command"] rangeOfString:filterString options:NSCaseInsensitiveSearch].location != NSNotFound) || + ([[process objectForKey:@"Time"] rangeOfString:filterString options:NSCaseInsensitiveSearch].location != NSNotFound) || + ((![[process objectForKey:@"State"] isNSNull]) && ([[process objectForKey:@"State"] rangeOfString:filterString options:NSCaseInsensitiveSearch].location != NSNotFound)) || + ((![[process objectForKey:@"Info"] isNSNull]) && ([[process objectForKey:@"Info"] rangeOfString:filterString options:NSCaseInsensitiveSearch].location != NSNotFound))) + { + [processesFiltered addObject:process]; + } + } + + [processListTableView reloadData]; + + [processesCountTextField setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%d of %d", "filtered server processes count"), [processesFiltered count], [processes count]]]; + [processesCountTextField setHidden:NO]; + + if ([processesFiltered count] == 0) return; + + [saveProcessesButton setEnabled:YES]; + [saveProcessesButton setTitle:@"Save View As..."]; +} + +@end diff --git a/Source/TableDocument.h b/Source/TableDocument.h index 843bb9c3..ab36ffb3 100644 --- a/Source/TableDocument.h +++ b/Source/TableDocument.h @@ -29,7 +29,7 @@ #import <MCPKit/MCPKit.h> #import <WebKit/WebKit.h> -@class SPConnectionController, SPUserManager; +@class SPConnectionController, SPProcessListController, SPUserManager; enum sp_current_query_mode { @@ -120,6 +120,7 @@ enum sp_current_query_mode int passwordSheetReturnCode; SPConnectionController *connectionController; + SPProcessListController *processListController; MCPConnection *mySQLConnection; @@ -183,6 +184,7 @@ enum sp_current_query_mode - (IBAction)removeDatabase:(id)sender; - (IBAction)showMySQLHelp:(id)sender; - (IBAction)saveServerVariables:(id)sender; +- (IBAction)showDatabaseProcessList:(id)sender; - (IBAction)openCurrentConnectionInNewWindow:(id)sender; - (NSArray *)allDatabaseNames; diff --git a/Source/TableDocument.m b/Source/TableDocument.m index b8071060..683d6237 100644 --- a/Source/TableDocument.m +++ b/Source/TableDocument.m @@ -52,6 +52,7 @@ #import "SPEncodingPopupAccessory.h" #import "SPConstants.h" #import "YRKSpinningProgressIndicator.h" +#import "SPProcessListController.h" // Printing #import "MGTemplateEngine.h" @@ -166,8 +167,12 @@ // Set the connection controller's delegate [connectionController setDelegate:self]; + + // Set the server variables table view's vertical gridlines if required + [variablesTableView setGridStyleMask:([[NSUserDefaults standardUserDefaults] boolForKey:SPDisplayTableViewVerticalGridlines]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone]; // Register observers for when the DisplayTableViewVerticalGridlines preference changes + [prefs addObserver:self forKeyPath:SPDisplayTableViewVerticalGridlines options:NSKeyValueObservingOptionNew context:NULL]; [prefs addObserver:tableSourceInstance forKeyPath:SPDisplayTableViewVerticalGridlines options:NSKeyValueObservingOptionNew context:NULL]; [prefs addObserver:tableContentInstance forKeyPath:SPDisplayTableViewVerticalGridlines options:NSKeyValueObservingOptionNew context:NULL]; [prefs addObserver:customQueryInstance forKeyPath:SPDisplayTableViewVerticalGridlines options:NSKeyValueObservingOptionNew context:NULL]; @@ -1046,6 +1051,23 @@ } /** + * Displays the database process list sheet. + */ +- (IBAction)showDatabaseProcessList:(id)sender +{ + if (!processListController) { + processListController = [[SPProcessListController alloc] init]; + + [processListController setConnection:mySQLConnection]; + + // Register to obeserve table view vertical grid line pref changes + [prefs addObserver:processListController forKeyPath:SPDisplayTableViewVerticalGridlines options:NSKeyValueObservingOptionNew context:NULL]; + } + + [processListController displayProcessListSheetAttachedToWindow:tableWindow]; +} + +/** * Returns an array of all available database names */ - (NSArray *)allDatabaseNames @@ -2015,7 +2037,7 @@ // If it was the server variables sheet that was closed release the relevant arrays if necessary if ([sender window] == variablesSheet) { - // If the filtered array is allocated and its not a reference to the variables array get rid of it + // If the filtered array is allocated and it's not a reference to the variables array get rid of it if ((variablesFiltered) && (variablesFiltered != variables)) { [variablesFiltered release], variablesFiltered = nil; } @@ -2168,6 +2190,9 @@ if ([keyPath isEqualToString:SPConsoleEnableLogging]) { [mySQLConnection setDelegateQueryLogging:[[change objectForKey:NSKeyValueChangeNewKey] boolValue]]; } + else if ([keyPath isEqualToString:SPDisplayTableViewVerticalGridlines]) { + [variablesTableView setGridStyleMask:([[change objectForKey:NSKeyValueChangeNewKey] boolValue]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone]; + } } /* @@ -3599,7 +3624,7 @@ } #pragma mark - -#pragma mark +#pragma mark Connection controller delegate methods /** * Invoked by the connection controller when it starts the process of initiating a connection. @@ -3620,7 +3645,7 @@ } #pragma mark - -#pragma mark Database name field delegate methods +#pragma mark Text field delegate methods /** * When adding a database, enable the button only if the new name has a length. @@ -3717,12 +3742,15 @@ #pragma mark - +/** + * Dealloc + */ - (void)dealloc { - [_encoding release]; [printWebView release]; if (connectionController) [connectionController release]; + if (processListController) [processListController release]; if (mySQLConnection) [mySQLConnection release]; if (variables) [variables release]; if (selectedDatabase) [selectedDatabase release]; |