aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPProcessListController.m
diff options
context:
space:
mode:
authorstuconnolly <stuart02@gmail.com>2010-04-24 17:10:55 +0000
committerstuconnolly <stuart02@gmail.com>2010-04-24 17:10:55 +0000
commit452e5fb8e8fd1f22be98b26ece0010af09fb3d7d (patch)
tree019ae19dd3395ea09e09e450393824a7204871b6 /Source/SPProcessListController.m
parentf8bfc9ff86a6b36de1f1223cf69cc82573f75bce (diff)
downloadsequelpro-452e5fb8e8fd1f22be98b26ece0010af09fb3d7d.tar.gz
sequelpro-452e5fb8e8fd1f22be98b26ece0010af09fb3d7d.tar.bz2
sequelpro-452e5fb8e8fd1f22be98b26ece0010af09fb3d7d.zip
Bunch of improvements to the serve processes panel, including:
- MCPKit's listProcesses (mysql_list_processes) method is now used, instead of running the query ourselves. - The ability to set whether or not the list is auto refreshed. - The ability to set the autorefresh interval, either via the presets or by entering a custom value (the interface for this might need updating). - Get the process list is now performed on a background thread. This completes the implementation of issue #607.
Diffstat (limited to 'Source/SPProcessListController.m')
-rw-r--r--Source/SPProcessListController.m277
1 files changed, 226 insertions, 51 deletions
diff --git a/Source/SPProcessListController.m b/Source/SPProcessListController.m
index 131b78d3..92744276 100644
--- a/Source/SPProcessListController.m
+++ b/Source/SPProcessListController.m
@@ -33,7 +33,13 @@
@interface SPProcessListController (PrivateAPI)
-- (void)_getDatabaseProcessList;
+- (void)_processListRefreshed;
+- (void)_startAutoRefreshTimer;
+- (void)_killAutoRefreshTimer;
+- (void)_fireAutoRefresh:(NSTimer *)timer;
+- (void)_updateSelectedAutoRefreshIntervalInterface;
+- (void)_startAutoRefreshTimerWithInterval:(NSTimeInterval)interval;
+- (void)_getDatabaseProcessListInBackground:(id)object;
- (void)_killProcessQueryWithId:(NSUInteger)processId;
- (void)_killProcessConnectionWithId:(NSUInteger)processId;
- (void)_updateServerProcessesFilterForFilterString:(NSString *)filterString;
@@ -44,18 +50,20 @@
@synthesize connection;
+#pragma mark -
+#pragma mark Initialisation
+
/**
* Initialisation
*/
- (id)init
{
if ((self = [super initWithWindowNibName:@"DatabaseProcessList"])) {
+
+ autoRefreshTimer = nil;
processes = [[NSMutableArray alloc] init];
prefs = [NSUserDefaults standardUserDefaults];
-
- // Default the process list comment to SHOW FULL PROCESSLIST
- showFullProcessList = [prefs boolForKey:SPProcessListShowFullProcessList];
}
return self;
@@ -88,6 +96,15 @@
[prefs addObserver:self forKeyPath:SPUseMonospacedFonts options:NSKeyValueObservingOptionNew context:NULL];
}
+/**
+ * Interface loading
+ */
+- (void)windowDidLoad
+{
+ // Update the selected auto refresh interval
+ [self _updateSelectedAutoRefreshIntervalInterface];
+}
+
#pragma mark -
#pragma mark IBAction methods
@@ -136,16 +153,27 @@
}
/**
- * Close the process list sheet.
+ * Close the current sheet
*/
-- (void)close
+- (IBAction)closeSheet:(id)sender
{
- // 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;
+ [NSApp endSheet:[sender window] returnCode:[sender tag]];
+ [[sender window] orderOut:self];
+}
+
+/**
+ * If required start the auto refresh timer.
+ */
+- (void)showWindow:(id)sender
+{
+ // If the auto refresh option is enable start the timer
+ if ([prefs boolForKey:SPProcessListEnableAutoRefresh]) {
+
+ // Start the auto refresh time but by pass the interface updates
+ [self _startAutoRefreshTimer];
}
- [super close];
+ [super showWindow:sender];
}
/**
@@ -165,24 +193,9 @@
[refreshProcessesButton 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];
- [refreshProcessesButton setEnabled:YES];
-
- // Stop progress Indicator
- [refreshProgressIndicator stopAnimation:self];
- [refreshProgressIndicator setHidden:YES];
+
+ // Get the processes list on a background thread
+ [NSThread detachNewThreadSelector:@selector(_getDatabaseProcessListInBackground:) toTarget:self withObject:nil];
}
/**
@@ -256,7 +269,7 @@
}
/**
- *
+ * Toggles the display of the process ID table column.
*/
- (IBAction)toggleShowProcessID:(id)sender
{
@@ -264,13 +277,38 @@
}
/**
+ * Toggles whether or not auto refresh is enabled.
+ */
+- (IBAction)toggleProcessListAutoRefresh:(id)sender
+{
+ BOOL enable = [sender state];
+
+ // Enable/Disable the refresh button
+ [refreshProcessesButton setEnabled:(!enable)];
+
+ (enable) ? [self _startAutoRefreshTimer] : [self _killAutoRefreshTimer];
+}
+
+/**
+ * Changes the auto refresh time interval based on the selected item
+ */
+- (IBAction)setAutoRefreshInterval:(id)sender
+{
+ [self _startAutoRefreshTimerWithInterval:[sender tag]];
+}
+
+/**
*
*/
-- (IBAction)toggeleShowFullProcessList:(id)sender
+- (IBAction)setCustomAutoRefreshInterval:(id)sender
{
- showFullProcessList = (!showFullProcessList);
-
- [self refreshProcessList:self];
+ [customIntervalTextField setStringValue:[prefs stringForKey:SPProcessListAutoRrefreshInterval]];
+
+ [NSApp beginSheet:customIntervalWindow
+ modalForWindow:[self window]
+ modalDelegate:self
+ didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
+ contextInfo:nil];
}
#pragma mark -
@@ -295,19 +333,29 @@
- (void)sheetDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo
{
// Order out current sheet to suppress overlapping of sheets
- if ([sheet respondsToSelector:@selector(orderOut:)])
+ if ([sheet respondsToSelector:@selector(orderOut:)]) {
[sheet orderOut:nil];
- else if ([sheet respondsToSelector:@selector(window)])
+ }
+ else if ([sheet respondsToSelector:@selector(window)]) {
[[sheet window] orderOut:nil];
+ }
if (returnCode == NSAlertDefaultReturn) {
- NSUInteger processId = [[[processes objectAtIndex:[processListTableView selectedRow]] valueForKey:@"Id"] integerValue];
- if ([contextInfo isEqualToString:SPKillProcessQueryMode]) {
- [self _killProcessQueryWithId:processId];
+ if (sheet == customIntervalWindow) {
+ NSLog(@"Set custom value to: %d", [customIntervalTextField integerValue]);
+
+ [self _startAutoRefreshTimerWithInterval:[customIntervalTextField integerValue]];
}
- else if ([contextInfo isEqualToString:SPKillProcessConnectionMode]) {
- [self _killProcessConnectionWithId:processId];
+ else {
+ NSUInteger processId = [[[processes objectAtIndex:[processListTableView selectedRow]] valueForKey:@"Id"] integerValue];
+
+ if ([contextInfo isEqualToString:SPKillProcessQueryMode]) {
+ [self _killProcessQueryWithId:processId];
+ }
+ else if ([contextInfo isEqualToString:SPKillProcessConnectionMode]) {
+ [self _killProcessConnectionWithId:processId];
+ }
}
}
}
@@ -357,6 +405,10 @@
return ([processListTableView numberOfSelectedRows] == 1);
}
+ if ((action == @selector(setAutoRefreshInterval:)) || (action == @selector(setCustomAutoRefreshInterval:))) {
+ return [prefs boolForKey:SPProcessListEnableAutoRefresh];
+ }
+
return YES;
}
@@ -425,6 +477,26 @@
if (object == filterProcessesSearchField) {
[self _updateServerProcessesFilterForFilterString:[object stringValue]];
}
+ else if (object == customIntervalTextField) {
+ [customIntervalButton setEnabled:(([[customIntervalTextField stringValue] length] > 0) && ([customIntervalTextField integerValue] > 0))];
+ }
+}
+
+#pragma mark -
+#pragma mark Window delegate methods
+
+/**
+ * Kill the auto refresh timer if it's running.
+ */
+- (void)windowWillClose:(NSNotification *)notification
+{
+ // 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;
+ }
+
+ // Kill the auto refresh timer if running
+ [self _killAutoRefreshTimer];
}
#pragma mark -
@@ -438,22 +510,120 @@
[processes release], processes = nil;
+ if (autoRefreshTimer) [autoRefreshTimer release], autoRefreshTimer = nil;
+
[super dealloc];
}
-@end
+#pragma mark -
+#pragma mark Private API
+
+/**
+ * Called by the background thread on the main thread once it has completed getting the list of processes.
+ */
+- (void)_processListRefreshed
+{
+ // Reapply any filters is required
+ if ([[filterProcessesSearchField stringValue] length] > 0) {
+ [self _updateServerProcessesFilterForFilterString:[filterProcessesSearchField stringValue]];
+ }
+
+ [processListTableView reloadData];
+
+ // Enable controls
+ [filterProcessesSearchField setEnabled:YES];
+ [saveProcessesButton setEnabled:YES];
+ [refreshProcessesButton setEnabled:(![autoRefreshButton state])];
+
+ // Stop progress Indicator
+ [refreshProgressIndicator stopAnimation:self];
+ [refreshProgressIndicator setHidden:YES];
+}
+
+/**
+ * Starts the auto refresh timer.
+ */
+- (void)_startAutoRefreshTimer
+{
+ autoRefreshTimer = [[NSTimer scheduledTimerWithTimeInterval:[prefs doubleForKey:SPProcessListAutoRrefreshInterval] target:self selector:@selector(_fireAutoRefresh:) userInfo:nil repeats:YES] retain];
+}
+
+/**
+ * Kills the auto refresh timer.
+ */
+- (void)_killAutoRefreshTimer
+{
+ // If the auto refresh timer is running, kill it
+ if (autoRefreshTimer && [autoRefreshTimer isValid]) {
+ [autoRefreshTimer invalidate];
+ [autoRefreshTimer release], autoRefreshTimer = nil;
+ }
+}
-@implementation SPProcessListController (PrivateAPI)
+/**
+ * Refreshes the process list when called by the auto refesh timer.
+ */
+- (void)_fireAutoRefresh:(NSTimer *)timer
+{
+ [self refreshProcessList:self];
+}
/**
- * Gets the current process list form the database;
+ *
*/
-- (void)_getDatabaseProcessList
+- (void)_updateSelectedAutoRefreshIntervalInterface
+{
+ BOOL found = NO;
+ NSUInteger interval = [prefs integerForKey:SPProcessListAutoRrefreshInterval];
+
+ NSArray *items = [[autoRefreshIntervalMenuItem submenu] itemArray];
+
+ // Uncheck all items
+ for (NSMenuItem *item in items)
+ {
+ [item setState:NSOffState];
+ }
+
+ // Check the selected item
+ for (NSMenuItem *item in items)
+ {
+ if (interval == [item tag]) {
+ found = YES;
+ [item setState:NSOnState];
+ break;
+ }
+ }
+
+ // If a match wasn't found then a custom value is set
+ if (!found) [[items objectAtIndex:([items count] - 1)] setState:NSOnState];
+}
+
+/**
+ * Starts the auto refresh time with the supplied time interval.
+ */
+- (void)_startAutoRefreshTimerWithInterval:(NSTimeInterval)interval
{
+ [prefs setDouble:interval forKey:SPProcessListAutoRrefreshInterval];
+
+ // Update the interface
+ [self _updateSelectedAutoRefreshIntervalInterface];
+
+ // Kill the timer and restart it with the new interval
+ [self _killAutoRefreshTimer];
+ [self _startAutoRefreshTimer];
+}
+
+/**
+ * Gets a list of current database processed on a background thread.
+ */
+- (void)_getDatabaseProcessListInBackground:(id)object;
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
NSUInteger i = 0;
// Get processes
- MCPResult *processList = [connection queryString:(showFullProcessList) ? @"SHOW FULL PROCESSLIST" : @"SHOW PROCESSLIST"];
+ MCPResult *processList = [connection listProcesses];
[processList setReturnDataAsStrings:YES];
@@ -465,6 +635,11 @@
{
[processes addObject:[processList fetchRowAsDictionary]];
}
+
+ // Update the UI on the main thread
+ [self performSelectorOnMainThread:@selector(_processListRefreshed) withObject:nil waitUntilDone:NO];
+
+ [pool release];
}
/**
@@ -536,13 +711,13 @@
// 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)) ||
+ 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:@"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];