From a5177fe6ec1107f97c326982a77100324532ccc0 Mon Sep 17 00:00:00 2001 From: rowanbeentje Date: Fri, 23 Oct 2009 23:35:58 +0000 Subject: - Apply new document task support to the Custom Query tab, and run all custom queries in a background thread with the task interface active. - Rework custom query result processing to allow display of results as they come in - Fix a memory leak --- Interfaces/English.lproj/DBView.xib | 113 ++++++++++----- Source/CustomQuery.h | 13 +- Source/CustomQuery.m | 282 +++++++++++++++++++++++++++--------- Source/TableContent.m | 17 ++- 4 files changed, 308 insertions(+), 117 deletions(-) diff --git a/Interfaces/English.lproj/DBView.xib b/Interfaces/English.lproj/DBView.xib index cc66fb2b..b8da8f5b 100644 --- a/Interfaces/English.lproj/DBView.xib +++ b/Interfaces/English.lproj/DBView.xib @@ -3,7 +3,7 @@ 1050 10B504 - 740 + 732 1038.2 437.00 @@ -16,20 +16,20 @@ YES - 740 - 740 + 732 + 732 1.2.1 YES - + YES com.brandonwalkin.BWToolkit - com.apple.WebKitIBPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin YES @@ -59,7 +59,7 @@ Connecting... NSWindow View - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} {780, 480} @@ -237,7 +237,7 @@ controlColor 3 - MC42NjY2NjY2ODY1AA + MC42NjY2NjY2NjY3AA @@ -871,7 +871,7 @@ source - + 256 YES @@ -1009,7 +1009,7 @@ 274 - {13, 504} + {13, 558} YES @@ -2132,7 +2132,6 @@ {{10, 7}, {700, 544}} - Structure @@ -2927,7 +2926,7 @@ customQuery - + 256 YES @@ -2954,6 +2953,29 @@ 6418 + + YES + + YES + Apple HTML pasteboard type + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + Apple URL pasteboard type + CorePasteboardFlavorType 0x6D6F6F76 + NSColor pasteboard type + NSFilenamesPboardType + NSStringPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT RTFD pasteboard type + NeXT Rich Text Format v1.0 pasteboard type + NeXT TIFF v4.0 pasteboard type + NeXT font pasteboard type + NeXT ruler pasteboard type + WebURLsWithTitlesPboardType + public.url + + {688, 14} @@ -3630,7 +3652,7 @@ YES - 18 + 1 YES 1 YES @@ -3776,6 +3798,7 @@ {{10, 7}, {700, 544}} + Custom Query @@ -4820,14 +4843,14 @@ - + 134217731 YES YES YES - + @@ -4847,7 +4870,7 @@ {{0, 0}, {1920, 1178}} {780, 502} - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} @@ -6018,7 +6041,7 @@ View - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} {213, 107} @@ -6297,7 +6320,7 @@ {{0, 0}, {1440, 878}} {213, 129} - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} 1 @@ -6309,7 +6332,7 @@ View - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} {213, 107} @@ -6465,7 +6488,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 {{0, 0}, {1440, 878}} {213, 129} - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} 1 @@ -6475,7 +6498,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 New Relation NSPanel - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} 256 @@ -7076,7 +7099,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 {302, 307} {{0, 0}, {1440, 878}} - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} 3 @@ -7088,7 +7111,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 View - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} {213, 50} @@ -7208,7 +7231,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 {{0, 0}, {1920, 1178}} {213, 72} - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} 9 @@ -7220,7 +7243,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 View - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} {213, 107} @@ -7355,7 +7378,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 {{0, 0}, {1440, 878}} {213, 129} - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} 15 @@ -7367,7 +7390,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 View - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} {350, 200} @@ -7671,7 +7694,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 {{0, 0}, {1440, 878}} {350, 222} - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} 15 @@ -7683,7 +7706,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 View - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} {350, 200} @@ -7885,7 +7908,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 {{0, 0}, {1680, 1028}} {350, 222} - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} 9 @@ -7897,7 +7920,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 View - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} {213, 107} @@ -8046,7 +8069,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 {{0, 0}, {1440, 878}} {213, 129} - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} 31 @@ -8056,7 +8079,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 MySQL Help NSPanel - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} {351, 120} @@ -8450,7 +8473,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 {{0, 0}, {1280, 1002}} {351, 136} - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} MYSQL_HELP_WINDOW @@ -8463,7 +8486,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 View - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} {350, 250} @@ -8854,7 +8877,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 {{0, 0}, {1920, 1178}} {350, 272} - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} 9 @@ -8987,7 +9010,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 Secure Text Input Sheet NSPanel - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} 256 @@ -9091,7 +9114,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 {338, 138} {{0, 0}, {1280, 778}} - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} @@ -10957,7 +10980,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 disabledControlTextColor 3 - MC4zMzMzMzMzNDMzAA + MC4zMzMzMzMzMzMzAA @@ -15180,6 +15203,14 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 6628 + + + runAllMenuItem + + + + 6629 + @@ -23816,7 +23847,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{350, 236}, {259, 349}} + {{247, 228}, {256, 357}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -24767,7 +24798,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 - 6628 + 6629 @@ -24913,6 +24944,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 queryHistorySearchFieldView queryHistorySearchMenuItem runAllButton + runAllMenuItem runSelectionButton runSelectionMenuItem saveQueryFavoriteButton @@ -24959,6 +24991,7 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8 id NSMenuItem id + NSMenuItem id NSMenuItem NSButton diff --git a/Source/CustomQuery.h b/Source/CustomQuery.h index a9d4f670..374cfc0d 100644 --- a/Source/CustomQuery.h +++ b/Source/CustomQuery.h @@ -82,6 +82,7 @@ IBOutlet id multipleLineEditingButton; IBOutlet NSMenuItem *runSelectionMenuItem; + IBOutlet NSMenuItem *runAllMenuItem; IBOutlet NSMenuItem *clearHistoryMenuItem; IBOutlet NSMenuItem *shiftLeftMenuItem; IBOutlet NSMenuItem *shiftRightMenuItem; @@ -109,8 +110,11 @@ NSString *usedQuery; NSRange currentQueryRange; NSArray *currentQueryRanges; + NSRange oldThreadedQueryRange; BOOL hasBackgroundAttribute; + BOOL selectionButtonCanBeEnabled; NSString *mySQLversion; + NSTableColumn *sortColumn; int queryStartPosition; @@ -119,6 +123,7 @@ NSString *helpHTMLTemplate; NSMutableArray *fullResult; + NSInteger fullResultCount; NSArray *cqColumnDefinition; NSString *lastExecutedQuery; @@ -135,6 +140,7 @@ // IBAction methods - (IBAction)runAllQueries:(id)sender; +- (void) runAllQueriesCallback; - (IBAction)runSelectedQueries:(id)sender; - (IBAction)chooseQueryFavorite:(id)sender; - (IBAction)chooseQueryHistory:(id)sender; @@ -153,7 +159,8 @@ - (IBAction)filterQueryHistory:(id)sender; // Query actions -- (void)performQueries:(NSArray *)queries; +- (void)performQueries:(NSArray *)queries withCallback:(SEL)customQueryCallbackMethod; +- (void)performQueriesTask:(NSDictionary *)taskArguments; - (NSString *)queryAtPosition:(long)position lookBehind:(BOOL *)doLookBehind; - (NSRange)queryRangeAtPosition:(long)position lookBehind:(BOOL *)doLookBehind; - (NSRange)queryTextRangeForQuery:(int)anIndex startPosition:(long)position; @@ -170,6 +177,10 @@ - (NSWindow *)helpWebViewWindow; - (void)setMySQLversion:(NSString *)theVersion; +// Task interaction +- (void) startDocumentTaskForTab:(NSNotification *)aNotification; +- (void) endDocumentTaskForTab:(NSNotification *)aNotification; + // Other - (void)setConnection:(MCPConnection *)theConnection; - (void)doPerformQueryService:(NSString *)query; diff --git a/Source/CustomQuery.m b/Source/CustomQuery.m index 3fffaa7a..b1e49f68 100644 --- a/Source/CustomQuery.m +++ b/Source/CustomQuery.m @@ -64,23 +64,27 @@ queries = [queryParser splitSqlStringByCharacter:';']; [queryParser release]; - NSRange curRange = [textView selectedRange]; + oldThreadedQueryRange = [textView selectedRange]; // Unselect a selection if given to avoid interferring with error highlighting - [textView setSelectedRange:NSMakeRange(curRange.location, 0)]; + [textView setSelectedRange:NSMakeRange(oldThreadedQueryRange.location, 0)]; // Reset queryStartPosition queryStartPosition = 0; tableReloadAfterEditing = NO; - [self performQueries:queries]; + [self performQueries:queries withCallback:@selector(runAllQueriesCallback)]; +} + +- (void) runAllQueriesCallback +{ // If no error was selected reconstruct a given selection if([textView selectedRange].length == 0) - [textView setSelectedRange:curRange]; + [textView setSelectedRange:oldThreadedQueryRange]; // Invoke textStorageDidProcessEditing: for syntax highlighting and auto-uppercase NSRange oldRange = [textView selectedRange]; - [textView setSelectedRange:NSMakeRange(oldRange.location,0)]; + [textView setSelectedRange:NSMakeRange(oldThreadedQueryRange.location,0)]; [textView insertText:@""]; [textView setSelectedRange:oldRange]; } @@ -123,7 +127,7 @@ tableReloadAfterEditing = NO; - [self performQueries:queries]; + [self performQueries:queries withCallback:NULL]; } /** @@ -330,12 +334,34 @@ * Performs the mysql-query given by the user * sets the tableView columns corresponding to the mysql-result */ -- (void)performQueries:(NSArray *)queries; -{ +- (void)performQueries:(NSArray *)queries withCallback:(SEL)customQueryCallbackMethod; +{ + NSString *taskString; + if ([queries count] > 1) { + taskString = [NSString stringWithFormat:NSLocalizedString(@"Running query %i of %i...", @"Running multiple queries string"), 1, [queries count]]; + } else { + taskString = NSLocalizedString(@"Running query...", @"Running single query string"); + } + [tableDocumentInstance startTaskWithDescription:taskString]; + [errorText setStringValue:taskString]; + [affectedRowsText setStringValue:@""]; + + NSValue *encodedCallbackMethod = nil; + if (customQueryCallbackMethod) + encodedCallbackMethod = [NSValue valueWithBytes:&customQueryCallbackMethod objCType:@encode(SEL)]; + NSDictionary *taskArguments = [NSDictionary dictionaryWithObjectsAndKeys:queries, @"queries", encodedCallbackMethod, @"callback", nil]; + [NSThread detachNewThreadSelector:@selector(performQueriesTask:) toTarget:self withObject:taskArguments]; +} + +- (void)performQueriesTask:(NSDictionary *)taskArguments +{ + NSAutoreleasePool *queryRunningPool = [[NSAutoreleasePool alloc] init]; + NSArray *queries = [taskArguments objectForKey:@"queries"]; NSArray *theColumns; NSTableColumn *theCol; MCPStreamingResult *streamingResult = nil; NSMutableString *errors = [NSMutableString string]; + SEL callbackMethod = NULL; int i, totalQueriesRun = 0, totalAffectedRows = 0; double executionTime = 0; @@ -376,6 +402,12 @@ // Perform the supplied queries in series for ( i = 0 ; i < queryCount ; i++ ) { + if (i > 0) { + NSString *taskString = [NSString stringWithFormat:NSLocalizedString(@"Running query %i of %i...", @"Running multiple queries string"), i+1, queryCount]; + [tableDocumentInstance setTaskDescription:taskString]; + [errorText setStringValue:taskString]; + } + NSString *query = [NSArrayObjectAtIndex(queries, i) stringByTrimmingCharactersInSet:whitespaceAndNewlineSet]; // Don't run blank queries, or queries which only contain whitespace. @@ -392,10 +424,59 @@ // If this is the last query, retrieve and store the result; otherwise, // discard the result without fully loading. - if (totalQueriesRun == queryCount) + if (totalQueriesRun == queryCount) { + + // get column definitions for the result array + if (cqColumnDefinition) [cqColumnDefinition release]; + cqColumnDefinition = [[streamingResult fetchResultFieldsStructure] retain]; + + // Add columns corresponding to the query result + theColumns = [streamingResult fetchFieldNames]; + + if(!tableReloadAfterEditing) { + for ( i = 0 ; i < [streamingResult numOfFields] ; i++) { + NSDictionary *columnDefinition = NSArrayObjectAtIndex(cqColumnDefinition,i); + theCol = [[NSTableColumn alloc] initWithIdentifier:[columnDefinition objectForKey:@"datacolumnindex"]]; + [theCol setResizingMask:NSTableColumnUserResizingMask]; + [theCol setEditable:YES]; + SPTextAndLinkCell *dataCell = [[[SPTextAndLinkCell alloc] initTextCell:@""] autorelease]; + [dataCell setEditable:YES]; + [dataCell setFormatter:[[SPDataCellFormatter new] autorelease]]; + if ( [prefs boolForKey:SPUseMonospacedFonts] ) { + [dataCell setFont:[NSFont fontWithName:@"Monaco" size:10]]; + } else { + [dataCell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; + } + [dataCell setLineBreakMode:NSLineBreakByTruncatingTail]; + [theCol setDataCell:dataCell]; + [[theCol headerCell] setStringValue:NSArrayObjectAtIndex(theColumns, i)]; + + // Set the width of this column to saved value if exists and maps to a real column + if ([columnDefinition objectForKey:@"org_name"] && [[columnDefinition objectForKey:@"org_name"] length]) { + NSNumber *colWidth = [[[[prefs objectForKey:SPTableColumnWidths] objectForKey:[NSString stringWithFormat:@"%@@%@", [columnDefinition objectForKey:@"db"], [tableDocumentInstance host]]] objectForKey:[columnDefinition objectForKey:@"org_table"]] objectForKey:[columnDefinition objectForKey:@"org_name"]]; + if ( colWidth ) { + [theCol setWidth:[colWidth floatValue]]; + } + } + + [customQueryView addTableColumn:theCol]; + [theCol release]; + } + + [customQueryView sizeLastColumnToFit]; + + //tries to fix problem with last row (otherwise to small) + //sets last column to width of the first if smaller than 30 + //problem not fixed for resizing window + if ( [[customQueryView tableColumnWithIdentifier:[NSNumber numberWithInt:[theColumns count]-1]] width] < 30 ) + [[customQueryView tableColumnWithIdentifier:[NSNumber numberWithInt:[theColumns count]-1]] + setWidth:[[customQueryView tableColumnWithIdentifier:[NSNumber numberWithInt:0]] width]]; + } + [self processResultIntoDataStorage:streamingResult]; - else + } else { [streamingResult cancelResultLoad]; + } // Record any affected rows if ( [mySQLConnection affectedRows] != -1 ) @@ -587,7 +668,7 @@ [tableDocumentInstance setQueryMode:SP_QUERYMODE_INTERFACE]; // If no results were returned, redraw the empty table and post notifications before returning. - if ( ![fullResult count] ) { + if ( !fullResultCount ) { [customQueryView reloadData]; [streamingResult release]; @@ -599,12 +680,19 @@ description:[NSString stringWithFormat:NSLocalizedString(@"%@",@"description for query finished growl notification"), [errorText stringValue]] window:tableWindow notificationName:@"Query Finished"]; + + // Set up the callback if present + if ([taskArguments objectForKey:@"callback"]) { + [[taskArguments objectForKey:@"callback"] getValue:&callbackMethod]; + [self performSelectorOnMainThread:callbackMethod withObject:nil waitUntilDone:NO]; + } + + [tableDocumentInstance endTask]; + [queryRunningPool release]; + return; } - // get column definitions for the result array - cqColumnDefinition = [[streamingResult fetchResultFieldsStructure] retain]; - // Find result table name for copying as SQL INSERT. // If more than one table name is found set resultTableName to nil. // resultTableName will be set to the original table name (not defined via AS) provided by mysql return @@ -619,48 +707,7 @@ } } - // Add columns corresponding to the query result - theColumns = [streamingResult fetchFieldNames]; - - if(!tableReloadAfterEditing) { - for ( i = 0 ; i < [streamingResult numOfFields] ; i++) { - NSDictionary *columnDefinition = NSArrayObjectAtIndex(cqColumnDefinition,i); - theCol = [[NSTableColumn alloc] initWithIdentifier:[columnDefinition objectForKey:@"datacolumnindex"]]; - [theCol setResizingMask:NSTableColumnUserResizingMask]; - [theCol setEditable:YES]; - SPTextAndLinkCell *dataCell = [[[SPTextAndLinkCell alloc] initTextCell:@""] autorelease]; - [dataCell setEditable:YES]; - [dataCell setFormatter:[[SPDataCellFormatter new] autorelease]]; - if ( [prefs boolForKey:SPUseMonospacedFonts] ) { - [dataCell setFont:[NSFont fontWithName:@"Monaco" size:10]]; - } else { - [dataCell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; - } - [dataCell setLineBreakMode:NSLineBreakByTruncatingTail]; - [theCol setDataCell:dataCell]; - [[theCol headerCell] setStringValue:NSArrayObjectAtIndex(theColumns, i)]; - - // Set the width of this column to saved value if exists and maps to a real column - if ([columnDefinition objectForKey:@"org_name"] && [[columnDefinition objectForKey:@"org_name"] length]) { - NSNumber *colWidth = [[[[prefs objectForKey:SPTableColumnWidths] objectForKey:[NSString stringWithFormat:@"%@@%@", [columnDefinition objectForKey:@"db"], [tableDocumentInstance host]]] objectForKey:[columnDefinition objectForKey:@"org_table"]] objectForKey:[columnDefinition objectForKey:@"org_name"]]; - if ( colWidth ) { - [theCol setWidth:[colWidth floatValue]]; - } - } - - [customQueryView addTableColumn:theCol]; - [theCol release]; - } - - [customQueryView sizeLastColumnToFit]; - //tries to fix problem with last row (otherwise to small) - //sets last column to width of the first if smaller than 30 - //problem not fixed for resizing window - if ( [[customQueryView tableColumnWithIdentifier:[NSNumber numberWithInt:[theColumns count]-1]] width] < 30 ) - [[customQueryView tableColumnWithIdentifier:[NSNumber numberWithInt:[theColumns count]-1]] - setWidth:[[customQueryView tableColumnWithIdentifier:[NSNumber numberWithInt:0]] width]]; - - } else { + if(tableReloadAfterEditing) { // scroll to last edited row after refreshing data // TODO: should be improved [customQueryView scrollRowToVisible:[customQueryView selectedRow]]; @@ -679,6 +726,15 @@ description:[NSString stringWithFormat:NSLocalizedString(@"%@",@"description for query finished growl notification"), [errorText stringValue]] window:tableWindow notificationName:@"Query Finished"]; + + // Set up the callback if present + if ([taskArguments objectForKey:@"callback"]) { + [[taskArguments objectForKey:@"callback"] getValue:&callbackMethod]; + [self performSelectorOnMainThread:callbackMethod withObject:nil waitUntilDone:NO]; + } + + [tableDocumentInstance endTask]; + [queryRunningPool release]; } /* @@ -688,9 +744,13 @@ { NSArray *tempRow; long rowsProcessed = 0; + NSUInteger nextTableDisplayBoundary = 50; NSAutoreleasePool *dataLoadingPool; + BOOL tableViewRedrawn = NO; // Remove all items from the table + fullResultCount = 0; + [customQueryView performSelectorOnMainThread:@selector(noteNumberOfRowsChanged) withObject:nil waitUntilDone:YES]; [fullResult removeAllObjects]; // Set up an autorelease pool for row processing @@ -700,16 +760,30 @@ while (tempRow = [theResult fetchNextRowAsArray]) { NSMutableArrayAddObject(fullResult, [NSMutableArray arrayWithArray:tempRow]); + fullResultCount++; // Update the count of rows processed rowsProcessed++; + // Update the table view with new results every now and then + if (rowsProcessed > nextTableDisplayBoundary) { + [customQueryView performSelectorOnMainThread:@selector(noteNumberOfRowsChanged) withObject:nil waitUntilDone:NO]; + if (!tableViewRedrawn) { + [customQueryView performSelectorOnMainThread:@selector(displayIfNeeded) withObject:nil waitUntilDone:NO]; + tableViewRedrawn = YES; + } + nextTableDisplayBoundary *= 2; + } + // Drain and reset the autorelease pool every ~1024 rows if (!(rowsProcessed % 1024)) { [dataLoadingPool drain]; dataLoadingPool = [[NSAutoreleasePool alloc] init]; } } + + [customQueryView performSelectorOnMainThread:@selector(noteNumberOfRowsChanged) withObject:nil waitUntilDone:NO]; + [customQueryView setNeedsDisplay:YES]; // Clean up the autorelease pool [dataLoadingPool drain]; @@ -1202,7 +1276,7 @@ if ( nil == fullResult ) { return 0; } else { - return [fullResult count]; + return fullResultCount; } } else { return 0; @@ -1214,8 +1288,8 @@ */ - (void)tableView:(CMCopyTable *)aTableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)aTableColumn row:(int)row { - if ( aTableView == customQueryView ) { + if (row > fullResultCount) return; // For NULL cell's display the user's NULL value placeholder in grey to easily distinguish it from other values if ([cell respondsToSelector:@selector(setTextColor:)]) { @@ -1233,6 +1307,7 @@ { if ( aTableView == customQueryView ) { + if (rowIndex > fullResultCount) return nil; id theValue = NSArrayObjectAtIndex(NSArrayObjectAtIndex(fullResult, rowIndex), [[aTableColumn identifier] intValue]); @@ -1339,7 +1414,7 @@ // On success reload table data by executing the last query tableReloadAfterEditing = YES; - [self performQueries:[NSArray arrayWithObject:lastExecutedQuery]]; + [self performQueries:[NSArray arrayWithObject:lastExecutedQuery] withCallback:NULL]; } else { NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil, @@ -1439,17 +1514,25 @@ tableReloadAfterEditing = YES; queryIsTableSorter = YES; - [self performQueries:[NSArray arrayWithObject:queryString]]; + sortColumn = tableColumn; + [self performQueries:[NSArray arrayWithObject:queryString] withCallback:@selector(tableSortCallback)]; +} + +- (void) tableSortCallback +{ queryIsTableSorter = NO; - if(![[mySQLConnection getLastErrorMessage] isEqualToString:@""]) return; + if(![[mySQLConnection getLastErrorMessage] isEqualToString:@""]) { + sortColumn = nil; + return; + } //sets highlight and indicatorImage - [customQueryView setHighlightedTableColumn:tableColumn]; + [customQueryView setHighlightedTableColumn:sortColumn]; if ( isDesc ) - [customQueryView setIndicatorImage:[NSImage imageNamed:@"NSDescendingSortIndicator"] inTableColumn:tableColumn]; + [customQueryView setIndicatorImage:[NSImage imageNamed:@"NSDescendingSortIndicator"] inTableColumn:sortColumn]; else - [customQueryView setIndicatorImage:[NSImage imageNamed:@"NSAscendingSortIndicator"] inTableColumn:tableColumn]; + [customQueryView setIndicatorImage:[NSImage imageNamed:@"NSAscendingSortIndicator"] inTableColumn:sortColumn]; } @@ -1804,6 +1887,7 @@ // If no text is selected, disable the button and action menu. if ( caretPosition == NSNotFound ) { + selectionButtonCanBeEnabled = NO; [runSelectionButton setEnabled:NO]; [runSelectionMenuItem setEnabled:NO]; return; @@ -1821,9 +1905,13 @@ [runSelectionButton setTitle:NSLocalizedString(@"Run Previous", @"Title of button to run query just before text caret in custom query view")]; [runSelectionMenuItem setTitle:NSLocalizedString(@"Run Previous Query", @"Title of action menu item to run query just before text caret in custom query view")]; } - [runSelectionButton setEnabled:YES]; - [runSelectionMenuItem setEnabled:YES]; + selectionButtonCanBeEnabled = YES; + if (![tableDocumentInstance isWorking]) { + [runSelectionButton setEnabled:YES]; + [runSelectionMenuItem setEnabled:YES]; + } } else { + selectionButtonCanBeEnabled = NO; [runSelectionButton setEnabled:NO]; [runSelectionMenuItem setEnabled:NO]; } @@ -1831,11 +1919,14 @@ // For selection ranges, enable the button. } else { + selectionButtonCanBeEnabled = YES; [runSelectionButton setTitle:NSLocalizedString(@"Run Selection", @"Title of button to run selected text in custom query view")]; - [runSelectionButton setEnabled:YES]; [runSelectionMenuItem setTitle:NSLocalizedString(@"Run Selected Text", @"Title of action menu item to run selected text in custom query view")]; - [runSelectionMenuItem setEnabled:YES]; [commentLineOrSelectionMenuItem setTitle:NSLocalizedString(@"Comment Selection", @"Title of action menu item to comment selection")]; + if (![tableDocumentInstance isWorking]) { + [runSelectionButton setEnabled:YES]; + [runSelectionMenuItem setEnabled:YES]; + } } } @@ -2438,6 +2529,44 @@ } +#pragma mark - +#pragma mark Task interaction + +/** + * Disable all content interactive elements during an ongoing task. + */ +- (void) startDocumentTaskForTab:(NSNotification *)aNotification +{ + + // Only disable elements if the current tab is the content view + if (![[aNotification object] isEqualToString:@"SwitchToRunQueryToolbarItemIdentifier"]) return; + + [customQueryView setEnabled:NO]; + [runSelectionButton setEnabled:NO]; + [runSelectionMenuItem setEnabled:NO]; + [runAllButton setEnabled:NO]; + [runAllMenuItem setEnabled:NO]; +} + +/** + * Enable all content interactive elements after an ongoing task. + */ +- (void) endDocumentTaskForTab:(NSNotification *)aNotification +{ + + // Only enable elements if the current tab is the content view + if (![[aNotification object] isEqualToString:@"SwitchToRunQueryToolbarItemIdentifier"]) return; + + if (selectionButtonCanBeEnabled) { + [runSelectionButton setEnabled:YES]; + [runSelectionMenuItem setEnabled:YES]; + } + [runAllButton setEnabled:YES]; + [runAllMenuItem setEnabled:YES]; + [customQueryView setEnabled:YES]; + [customQueryView displayIfNeeded]; +} + #pragma mark - #pragma mark Other @@ -2552,6 +2681,9 @@ sortField = nil; isDesc = NO; + sortColumn = nil; + selectionButtonCanBeEnabled = NO; + cqColumnDefinition = nil; // init helpHTMLTemplate NSError *error; @@ -2572,6 +2704,7 @@ [[helpWebView backForwardList] setCapacity:20]; // init tableView's data source + fullResultCount = 0; fullResult = [[NSMutableArray alloc] init]; prefs = [NSUserDefaults standardUserDefaults]; @@ -2610,16 +2743,29 @@ // Set the structure and index view's vertical gridlines if required [customQueryView setGridStyleMask:([prefs boolForKey:SPDisplayTableViewVerticalGridlines]) ? NSTableViewSolidVerticalGridLineMask : NSTableViewGridNone]; + + // Add observers for document task activity + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(startDocumentTaskForTab:) + name:SPDocumentTaskStartNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(endDocumentTaskForTab:) + name:SPDocumentTaskEndNotification + object:nil]; } - (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [usedQuery release]; [fullResult release]; [favoritesManager release]; if (helpHTMLTemplate) [helpHTMLTemplate release]; if (mySQLversion) [mySQLversion release]; if (sortField) [sortField release]; + if (cqColumnDefinition) [cqColumnDefinition release]; [super dealloc]; } diff --git a/Source/TableContent.m b/Source/TableContent.m index d038dfef..4286723a 100644 --- a/Source/TableContent.m +++ b/Source/TableContent.m @@ -1418,15 +1418,16 @@ } else if (rowsProcessed == targetRowCount) { [tableDocumentInstance performSelectorOnMainThread:@selector(setTaskProgressToIndeterminate) withObject:nil waitUntilDone:NO]; } - - if (rowsProcessed > nextTableDisplayBoundary) { - [tableContentView performSelectorOnMainThread:@selector(noteNumberOfRowsChanged) withObject:nil waitUntilDone:NO]; - if (!tableViewRedrawn) { - [tableContentView performSelectorOnMainThread:@selector(displayIfNeeded) withObject:nil waitUntilDone:NO]; - tableViewRedrawn = YES; - } - nextTableDisplayBoundary *= 2; + } + + // Update the table view with new results every now and then + if (rowsProcessed > nextTableDisplayBoundary) { + [tableContentView performSelectorOnMainThread:@selector(noteNumberOfRowsChanged) withObject:nil waitUntilDone:NO]; + if (!tableViewRedrawn) { + [tableContentView performSelectorOnMainThread:@selector(displayIfNeeded) withObject:nil waitUntilDone:NO]; + tableViewRedrawn = YES; } + nextTableDisplayBoundary *= 2; } // Drain and reset the autorelease pool every ~1024 rows -- cgit v1.2.3