From 48d02b7080cadc507b1e7897c54ce2a8cf149acf Mon Sep 17 00:00:00 2001 From: rowanbeentje Date: Wed, 4 Nov 2009 01:15:53 +0000 Subject: - Add task support to all the main interface views - Improve task support on previously supported views - Use a threaded task load for all initial table loads - Support threaded task loads for table content loads, reloads, sorts, and filters - Improve upon previous threaded task loads by minimising view updates and supporting updates of the existing data arrays where valid --- Source/CustomQuery.m | 16 +- Source/SPArrayAdditions.h | 9 +- Source/SPConstants.h | 1 + Source/SPConstants.m | 1 + Source/SPExtendedTableInfo.h | 5 + Source/SPExtendedTableInfo.m | 77 +++++++- Source/SPTableInfo.m | 5 +- Source/SPTableRelations.h | 4 + Source/SPTableRelations.m | 69 ++++++- Source/TableContent.h | 2 +- Source/TableContent.m | 439 ++++++++++++++++++++++++----------------- Source/TableSource.m | 15 +- Source/TablesList.h | 3 +- Source/TablesList.m | 453 +++++++++++++++++++++++-------------------- 14 files changed, 666 insertions(+), 433 deletions(-) (limited to 'Source') diff --git a/Source/CustomQuery.m b/Source/CustomQuery.m index 25c90dba..c05d87f7 100644 --- a/Source/CustomQuery.m +++ b/Source/CustomQuery.m @@ -2567,10 +2567,8 @@ - (void) startDocumentTaskForTab:(NSNotification *)aNotification { - // Only proceed if the current document is the notifying document, and only if - // this view is selected. - if ([aNotification object] != tableDocumentInstance - || ![[[aNotification object] selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_CUSTOM_QUERY]) + // Only proceed if this view is selected. + if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_CUSTOM_QUERY]) return; [runSelectionButton setEnabled:NO]; @@ -2585,10 +2583,8 @@ - (void) endDocumentTaskForTab:(NSNotification *)aNotification { - // Only proceed if the current document is the notifying document, and only if - // this view is selected. - if ([aNotification object] != tableDocumentInstance - || ![[[aNotification object] selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_CUSTOM_QUERY]) + // Only proceed if this view is selected. + if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_CUSTOM_QUERY]) return; if (selectionButtonCanBeEnabled) { @@ -2780,11 +2776,11 @@ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startDocumentTaskForTab:) name:SPDocumentTaskStartNotification - object:nil]; + object:tableDocumentInstance]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endDocumentTaskForTab:) name:SPDocumentTaskEndNotification - object:nil]; + object:tableDocumentInstance]; } - (void)dealloc diff --git a/Source/SPArrayAdditions.h b/Source/SPArrayAdditions.h index 31493f22..eb11da02 100644 --- a/Source/SPArrayAdditions.h +++ b/Source/SPArrayAdditions.h @@ -27,12 +27,11 @@ static inline id NSArrayObjectAtIndex(NSArray* self, NSUInteger i) { return (id)CFArrayGetValueAtIndex((CFArrayRef)self, i); } - static inline void NSMutableArrayAddObject(NSArray* self, id anObject) { - typedef void (*SPMutableArrayAddObjectMethodPtr)(NSArray*, SEL, id); - static SPMutableArrayAddObjectMethodPtr SPNSMutableArrayAddObject; - if (!SPNSMutableArrayAddObject) SPNSMutableArrayAddObject = (SPMutableArrayAddObjectMethodPtr)[self methodForSelector:@selector(addObject:)]; - SPNSMutableArrayAddObject(self, @selector(addObject:), anObject); + CFArrayAppendValue((CFMutableArrayRef)self, anObject); +} +static inline void NSMutableArrayReplaceObject(NSArray* self, CFIndex idx, id anObject) { + CFArraySetValueAtIndex((CFMutableArrayRef)self, idx, anObject); } @interface NSArray (SPArrayAdditions) diff --git a/Source/SPConstants.h b/Source/SPConstants.h index d8d16adf..aafabd73 100644 --- a/Source/SPConstants.h +++ b/Source/SPConstants.h @@ -159,3 +159,4 @@ extern NSString *SPQueryFavoriteReplacesContent; extern NSString *SPQueryHistory; extern NSString *SPQueryHistoryReplacesContent; extern NSString *SPQuickLookTypes; +extern NSString *SPTableChangedNotification; diff --git a/Source/SPConstants.m b/Source/SPConstants.m index 5e88ab0d..21b9bfe7 100644 --- a/Source/SPConstants.m +++ b/Source/SPConstants.m @@ -117,3 +117,4 @@ NSString *SPQueryFavoriteReplacesContent = @"QueryFavoriteReplacesConten NSString *SPQueryHistory = @"queryHistory"; NSString *SPQueryHistoryReplacesContent = @"QueryHistoryReplacesContent"; NSString *SPQuickLookTypes = @"QuickLookTypes"; +NSString *SPTableChangedNotification = @"SPTableSelectionChanged"; diff --git a/Source/SPExtendedTableInfo.h b/Source/SPExtendedTableInfo.h index ac0f6096..e9c17b56 100644 --- a/Source/SPExtendedTableInfo.h +++ b/Source/SPExtendedTableInfo.h @@ -30,6 +30,7 @@ @interface SPExtendedTableInfo : NSObject { + IBOutlet id tableDocumentInstance; IBOutlet SPTableData *tableDataInstance; IBOutlet SPDatabaseData *databaseDataInstance; @@ -67,4 +68,8 @@ // Others - (void)loadTable:(NSString *)table; +// Task interaction +- (void) startDocumentTaskForTab:(NSNotification *)aNotification; +- (void) endDocumentTaskForTab:(NSNotification *)aNotification; + @end diff --git a/Source/SPExtendedTableInfo.m b/Source/SPExtendedTableInfo.m index 54830e9b..0976aa92 100644 --- a/Source/SPExtendedTableInfo.m +++ b/Source/SPExtendedTableInfo.m @@ -28,6 +28,8 @@ #import "RegexKitLite.h" #import "SPDatabaseData.h" #import "SPStringAdditions.h" +#import "SPConstants.h" +#import "TableDocument.h" @interface SPExtendedTableInfo (PrivateAPI) @@ -54,6 +56,16 @@ toObject:[NSUserDefaultsController sharedUserDefaultsController] withKeyPath:@"values.CustomQueryEditorBackgroundColor" options:bindingOptions]; + + // Add observers for document task activity + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(startDocumentTaskForTab:) + name:SPDocumentTaskStartNotification + object:tableDocumentInstance]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(endDocumentTaskForTab:) + name:SPDocumentTaskEndNotification + object:tableDocumentInstance]; } #pragma mark - @@ -163,10 +175,13 @@ /** * Load all the info for the supplied table by querying the table data instance and updaing the interface - * elements accordingly. + * elements accordingly. + * Note that interface elements are also toggled in start/endDocumentTaskForTab:, with similar logic. */ - (void)loadTable:(NSString *)table { + BOOL enableInteraction = ![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_INFO] || ![tableDocumentInstance isWorking]; + // Store the table name away for future use selectedTable = table; @@ -230,7 +245,7 @@ } [tableTypePopUpButton selectItemWithTitle:[statusFields objectForKey:@"Engine"]]; - [tableTypePopUpButton setEnabled:YES]; + [tableTypePopUpButton setEnabled:enableInteraction]; } else { [tableTypePopUpButton addItemWithTitle:@"Not available"]; @@ -252,7 +267,7 @@ } [tableEncodingPopUpButton selectItemWithTitle:selectedTitle]; - [tableEncodingPopUpButton setEnabled:YES]; + [tableEncodingPopUpButton setEnabled:enableInteraction]; } else { [tableEncodingPopUpButton addItemWithTitle:@"Not available"]; @@ -266,7 +281,7 @@ } [tableCollationPopUpButton selectItemWithTitle:[statusFields objectForKey:@"Collation"]]; - [tableCollationPopUpButton setEnabled:YES]; + [tableCollationPopUpButton setEnabled:enableInteraction]; } else { [tableCollationPopUpButton addItemWithTitle:@"Not available"]; @@ -288,7 +303,7 @@ [tableSizeFree setStringValue:[self _formatValueWithKey:@"Data_free" inDictionary:statusFields withLabel:@"Free data size"]]; // Set comments - [tableCommentsTextView setEditable:YES]; + [tableCommentsTextView setEditable:enableInteraction]; [tableCommentsTextView setString:[statusFields objectForKey:@"Comment"]]; // Set create syntax @@ -328,11 +343,63 @@ } } +#pragma mark - +#pragma mark Task interaction + +/** + * Disable all content interactive elements during an ongoing task. + */ +- (void) startDocumentTaskForTab:(NSNotification *)aNotification +{ + + // Only proceed if this view is selected. + if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_INFO]) + return; + + [tableTypePopUpButton setEnabled:NO]; + [tableEncodingPopUpButton setEnabled:NO]; + [tableCollationPopUpButton setEnabled:NO]; + [tableCommentsTextView setEditable:NO]; +} + +/** + * Enable all content interactive elements after an ongoing task. + */ +- (void) endDocumentTaskForTab:(NSNotification *)aNotification +{ + + // Only proceed if this view is selected. + if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_INFO]) + return; + + NSDictionary *statusFields = [tableDataInstance statusValues]; + if (!selectedTable || ![selectedTable length] || [[statusFields objectForKey:@"Engine"] isEqualToString:@"View"]) + return; + + if ([[databaseDataInstance getDatabaseStorageEngines] count] && [statusFields objectForKey:@"Engine"]) + [tableTypePopUpButton setEnabled:YES]; + + if ([[databaseDataInstance getDatabaseCharacterSetEncodings] count] && [tableDataInstance tableEncoding]) + [tableEncodingPopUpButton setEnabled:YES]; + + if ([[databaseDataInstance getDatabaseCollationsForEncoding:[tableDataInstance tableEncoding]] count] + && [statusFields objectForKey:@"Collation"]) + { + [tableCollationPopUpButton setEnabled:YES]; + } + + [tableCommentsTextView setEditable:YES]; +} + +#pragma mark - + /** * Release connection. */ - (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [connection release], connection = nil; [super dealloc]; diff --git a/Source/SPTableInfo.m b/Source/SPTableInfo.m index b3ff4946..166a7634 100644 --- a/Source/SPTableInfo.m +++ b/Source/SPTableInfo.m @@ -29,6 +29,7 @@ #import "TableDocument.h" #import "TablesList.h" #import "SPTableData.h" +#import "SPConstants.h" #import "SPStringAdditions.h" @interface SPTableInfo (PrivateAPI) @@ -52,8 +53,8 @@ { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tableChanged:) - name:NSTableViewSelectionDidChangeNotification - object:tableList]; + name:SPTableChangedNotification + object:tableDocumentInstance]; [info addObject:NSLocalizedString(@"TABLE INFORMATION", @"header for table info pane")]; [infoTable reloadData]; diff --git a/Source/SPTableRelations.h b/Source/SPTableRelations.h index 61328e59..6d4315e2 100644 --- a/Source/SPTableRelations.h +++ b/Source/SPTableRelations.h @@ -68,4 +68,8 @@ - (IBAction)selectReferenceTable:(id)sender; - (IBAction)refreshRelations:(id)sender; +// Task interaction +- (void) startDocumentTaskForTab:(NSNotification *)aNotification; +- (void) endDocumentTaskForTab:(NSNotification *)aNotification; + @end diff --git a/Source/SPTableRelations.m b/Source/SPTableRelations.m index 92eebfaf..bdc1c418 100644 --- a/Source/SPTableRelations.m +++ b/Source/SPTableRelations.m @@ -63,8 +63,18 @@ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tableSelectionChanged:) - name:NSTableViewSelectionDidChangeNotification - object:tableList]; + name:SPTableChangedNotification + object:tableDocumentInstance]; + + // Add observers for document task activity + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(startDocumentTaskForTab:) + name:SPDocumentTaskStartNotification + object:tableDocumentInstance]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(endDocumentTaskForTab:) + name:SPDocumentTaskEndNotification + object:tableDocumentInstance]; } #pragma mark - @@ -210,9 +220,11 @@ */ - (void)tableSelectionChanged:(NSNotification *)notification { + BOOL enableInteraction = ![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_RELATIONS] || ![tableDocumentInstance isWorking]; + // To begin enable all interface elements - [addRelationButton setEnabled:YES]; - [refreshRelationsButton setEnabled:YES]; + [addRelationButton setEnabled:enableInteraction]; + [refreshRelationsButton setEnabled:enableInteraction]; [relationsTableView setEnabled:YES]; // Get the current table's storage engine @@ -223,8 +235,8 @@ // Update the text label [labelTextField setStringValue:[NSString stringWithFormat:@"Relations for table: %@", [tablesListInstance tableName]]]; - [addRelationButton setEnabled:YES]; - [refreshRelationsButton setEnabled:YES]; + [addRelationButton setEnabled:enableInteraction]; + [refreshRelationsButton setEnabled:enableInteraction]; [relationsTableView setEnabled:YES]; } else { @@ -268,9 +280,54 @@ */ - (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex { + if ([tableDocumentInstance isWorking]) return NO; + return NO; } +/** + * Disable row selection while the document is working. + */ +- (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(NSInteger)rowIndex +{ + return ![tableDocumentInstance isWorking]; +} + +#pragma mark - +#pragma mark Task interaction + +/** + * Disable all content interactive elements during an ongoing task. + */ +- (void) startDocumentTaskForTab:(NSNotification *)aNotification +{ + + // Only proceed if this view is selected. + if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_RELATIONS]) + return; + + [addRelationButton setEnabled:NO]; + [refreshRelationsButton setEnabled:NO]; + [removeRelationButton setEnabled:NO]; +} + +/** + * Enable all content interactive elements after an ongoing task. + */ +- (void) endDocumentTaskForTab:(NSNotification *)aNotification +{ + + // Only proceed if this view is selected. + if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_RELATIONS]) + return; + + if ([relationsTableView isEnabled]) { + [addRelationButton setEnabled:YES]; + [refreshRelationsButton setEnabled:YES]; + } + [removeRelationButton setEnabled:([relationsTableView numberOfSelectedRows] > 0)]; +} + #pragma mark - #pragma mark Other diff --git a/Source/TableContent.h b/Source/TableContent.h index e37cb6f5..b15fb957 100644 --- a/Source/TableContent.h +++ b/Source/TableContent.h @@ -61,7 +61,7 @@ NSString *selectedTable, *usedQuery; NSMutableArray *tableValues, *dataColumns, *keys, *oldRow; - NSUInteger tableValuesCount; + NSUInteger tableRowsCount, previousTableRowsCount, tableColumnsCount; NSString *compareType; NSNumber *sortCol; BOOL isEditingRow, isEditingNewRow, isSavingRow, isDesc, setLimit; diff --git a/Source/TableContent.m b/Source/TableContent.m index 610cfa86..ccc82e5e 100644 --- a/Source/TableContent.m +++ b/Source/TableContent.m @@ -59,8 +59,10 @@ if ((self == [super init])) { tableValues = [[NSMutableArray alloc] init]; - tableValuesCount = 0; + tableRowsCount = 0; + previousTableRowsCount = 0; dataColumns = [[NSMutableArray alloc] init]; + tableColumnsCount = 0; oldRow = [[NSMutableArray alloc] init]; selectedTable = nil; @@ -125,11 +127,11 @@ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startDocumentTaskForTab:) name:SPDocumentTaskStartNotification - object:nil]; + object:tableDocumentInstance]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endDocumentTaskForTab:) name:SPDocumentTaskEndNotification - object:nil]; + object:tableDocumentInstance]; } #pragma mark - @@ -146,36 +148,50 @@ NSArray *columnNames; NSDictionary *columnDefinition; NSTableColumn *theCol; + BOOL enableInteraction = ![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_CONTENT] || ![tableDocumentInstance isWorking]; - // Clear the selection, and abort the reload if the user is still editing a row - [tableContentView deselectAll:self]; + // Abort the reload if the user is still editing a row if ( isEditingRow ) return; - // Store the newly selected table name - selectedTable = aTable; - - // Reset table key store for use in argumentForRow: - if (keys) [keys release], keys = nil; + // Check the supplied table name. If it matches the old one, a reload is being performed; + // reload the data in-place to maintain table state if possible. + if ([selectedTable isEqualToString:aTable]) { + previousTableRowsCount = tableRowsCount; + + // Otherwise store the newly selected table name and reset the data + } else { + selectedTable = aTable; + previousTableRowsCount = 0; - // Restore the table content view to the top left - [tableContentView scrollRowToVisible:0]; - [tableContentView scrollColumnToVisible:0]; + // Clear the selection + [tableContentView deselectAll:self]; - // Remove existing columns from the table - while ([[tableContentView tableColumns] count]) { - [tableContentView removeTableColumn:NSArrayObjectAtIndex([tableContentView tableColumns], 0)]; + // Restore the table content view to the top left + [tableContentView scrollRowToVisible:0]; + [tableContentView scrollColumnToVisible:0]; } + // Reset table key store for use in argumentForRow: + if (keys) [keys release], keys = nil; + // Reset data column store + tableColumnsCount = 0; [dataColumns removeAllObjects]; // If no table has been supplied, reset the view to a blank table and disabled elements. // [tableDataInstance tableEncoding] == nil indicates that an error occured while retrieving table data if ( [[[tableDataInstance statusValues] objectForKey:@"Rows"] isNSNull] || [aTable isEqualToString:@""] || !aTable || [tableDataInstance tableEncoding] == nil) { + + // Remove existing columns from the table + while ([[tableContentView tableColumns] count]) { + [tableContentView removeTableColumn:NSArrayObjectAtIndex([tableContentView tableColumns], 0)]; + } + // Empty the stored data arrays - tableValuesCount = 0; + tableRowsCount = 0; + previousTableRowsCount = 0; [tableValues removeAllObjects]; [tableContentView reloadData]; isFiltered = NO; @@ -250,7 +266,15 @@ } NSString *nullValue = [prefs objectForKey:SPNullValue]; - + + // Lock drawing in the window + [tableWindow disableFlushWindow]; + + // Remove existing columns from the table + while ([[tableContentView tableColumns] count]) { + [tableContentView removeTableColumn:NSArrayObjectAtIndex([tableContentView tableColumns], 0)]; + } + // Add the new columns to the table for ( i = 0 ; i < [dataColumns count] ; i++ ) { columnDefinition = NSArrayObjectAtIndex(dataColumns, i); @@ -316,6 +340,7 @@ // Add the column to the table [tableContentView addTableColumn:theCol]; + tableColumnsCount++; [theCol release]; } @@ -341,6 +366,9 @@ isDesc = NO; } + // Restore window drawing + [tableWindow enableFlushWindow]; + // Store the current first responder so filter field doesn't steal focus id currentFirstResponder = [tableWindow firstResponder]; @@ -355,7 +383,7 @@ [self setCompareTypes:self]; [argumentField setEnabled:YES]; [argumentField setStringValue:@""]; - [filterButton setEnabled:YES]; + [filterButton setEnabled:enableInteraction]; // Restore preserved filter settings if appropriate and valid if (filterFieldToRestore) { @@ -401,19 +429,22 @@ } // Set the state of the table buttons - [addButton setEnabled:YES]; + [addButton setEnabled:enableInteraction]; [copyButton setEnabled:NO]; [removeButton setEnabled:NO]; + // Reset the table store if required - basically if the table is being changed + if (!previousTableRowsCount) { + tableRowsCount = 0; + [tableValues removeAllObjects]; + } + // Trigger a data refresh [self loadTableValues]; // Restore the view origin if appropriate if (!NSEqualRects(selectionViewportToRestore, NSZeroRect)) { - // Let the table know the size of the newly available data - [tableContentView reloadData]; - // Scroll the viewport to the saved location selectionViewportToRestore.size = [tableContentView visibleRect].size; [tableContentView scrollRectToVisible:selectionViewportToRestore]; @@ -424,8 +455,8 @@ [tableContentView selectRowIndexes:selectionIndexToRestore byExtendingSelection:NO]; } - // Reload the table data display - [tableContentView reloadData]; + // Update display if necessary + [tableContentView displayIfNeeded]; // Init copyTable with necessary information for copying selected rows as SQL INSERT [tableContentView setTableInstance:self withTableData:tableValues withColumns:dataColumns withTableName:selectedTable withConnection:mySQLConnection]; @@ -441,6 +472,7 @@ * Reload the table data without reconfiguring the tableView, * using filters and limits as appropriate. * Will not refresh the table view itself. + * Note that this does not empty the table array - see use of previousTableRowsCount. */ - (void) loadTableValues { @@ -456,11 +488,6 @@ [countText setStringValue:NSLocalizedString(@"Loading table data...", @"Loading table data string")]; - // Remove all items from the table - tableValuesCount = 0; - [tableContentView noteNumberOfRowsChanged]; - [tableValues removeAllObjects]; - // Notify any listeners that a query has started [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryWillBePerformed" object:self]; @@ -506,13 +533,14 @@ } // Perform and process the query + [tableContentView performSelectorOnMainThread:@selector(noteNumberOfRowsChanged) withObject:nil waitUntilDone:YES]; [self setUsedQuery:queryString]; streamingResult = [mySQLConnection streamingQueryString:queryString]; [self processResultIntoDataStorage:streamingResult approximateRowCount:rowsToLoad]; [streamingResult release]; // If the result is empty, and a limit is active, reset the limit - if ([prefs boolForKey:SPLimitResults] && queryStringBeforeLimit && !tableValuesCount) { + if ([prefs boolForKey:SPLimitResults] && queryStringBeforeLimit && !tableRowsCount) { [limitRowsField setStringValue:@"1"]; queryString = [NSMutableString stringWithFormat:@"%@ LIMIT 0,%d", queryStringBeforeLimit, [prefs integerForKey:SPLimitResultsValue]]; [self setUsedQuery:queryString]; @@ -523,7 +551,7 @@ if ([prefs boolForKey:SPLimitResults] && ([limitRowsField intValue] > 1 - || tableValuesCount == [prefs integerForKey:SPLimitResultsValue])) + || tableRowsCount == [prefs integerForKey:SPLimitResultsValue])) { isLimited = YES; } else { @@ -540,6 +568,96 @@ [[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:self]; } +/* + * Processes a supplied streaming result set, loading it into the data array. + */ +- (void)processResultIntoDataStorage:(MCPStreamingResult *)theResult approximateRowCount:(long)targetRowCount +{ + NSArray *tempRow; + NSMutableArray *newRow; + NSMutableArray *columnBlobStatuses = [[NSMutableArray alloc] init]; + NSUInteger i; + + float relativeTargetRowCount = 100.0/targetRowCount; + NSUInteger nextTableDisplayBoundary = 50; + BOOL tableViewRedrawn = NO; + + long rowsProcessed = 0; + + NSAutoreleasePool *dataLoadingPool; + NSProgressIndicator *dataLoadingIndicator = [tableDocumentInstance valueForKey:@"queryProgressBar"]; + BOOL prefsLoadBlobsAsNeeded = [prefs boolForKey:SPLoadBlobsAsNeeded]; + + // Build up an array of which columns are blobs for faster iteration + for ( i = 0; i < tableColumnsCount ; i++ ) { + [columnBlobStatuses addObject:[NSNumber numberWithBool:[tableDataInstance columnIsBlobOrText:[NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"name"] ]]]; + } + + // Set up an autorelease pool for row processing + dataLoadingPool = [[NSAutoreleasePool alloc] init]; + + // Loop through the result rows as they become available + while (tempRow = [theResult fetchNextRowAsArray]) { + + if (rowsProcessed < previousTableRowsCount) { + NSMutableArrayReplaceObject(tableValues, rowsProcessed, [NSMutableArray arrayWithArray:tempRow]); + } else { + NSMutableArrayAddObject(tableValues, [NSMutableArray arrayWithArray:tempRow]); + } + + // Alter the values for hidden blob and text fields if appropriate + if ( prefsLoadBlobsAsNeeded ) { + newRow = NSArrayObjectAtIndex(tableValues, rowsProcessed); + for ( i = 0 ; i < tableColumnsCount ; i++ ) { + if ( [NSArrayObjectAtIndex(columnBlobStatuses, i) boolValue] ) { + NSMutableArrayReplaceObject(newRow, i, [SPNotLoaded notLoaded]); + } + } + } + rowsProcessed++; + + // Update the task interface as necessary + if (!isFiltered) { + if (rowsProcessed < targetRowCount) { + [tableDocumentInstance setTaskPercentage:(rowsProcessed*relativeTargetRowCount)]; + } else if (rowsProcessed == targetRowCount) { + [tableDocumentInstance performSelectorOnMainThread:@selector(setTaskProgressToIndeterminate) withObject:nil waitUntilDone:NO]; + } + } + + // Update the table view with new results every now and then + if (rowsProcessed > nextTableDisplayBoundary) { + if (rowsProcessed > tableRowsCount) tableRowsCount = rowsProcessed; + [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 + if (!(rowsProcessed % 1024)) { + [dataLoadingPool drain]; + dataLoadingPool = [[NSAutoreleasePool alloc] init]; + } + } + tableRowsCount = rowsProcessed; + + // If the reloaded table is shorter than the previous table, remove the extra values from the storage + if (tableRowsCount < [tableValues count]) { + [tableValues removeObjectsInRange:NSMakeRange(tableRowsCount, [tableValues count] - tableRowsCount)]; + } + + [tableContentView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO]; + + // Clean up the autorelease pool and reset the progress indicator + [dataLoadingPool drain]; + [dataLoadingIndicator setIndeterminate:YES]; + + [columnBlobStatuses release]; +} + /** * Returns the query string for the current filter settings, * ready to be dropped into a WHERE clause, or nil if no filtering @@ -703,25 +821,25 @@ // If no filter or limit is active, show just the count of rows in the table if (!isFiltered && !isLimited) { - if (tableValuesCount == 1) - [countString appendFormat:NSLocalizedString(@"%d row in table", @"text showing a single row in the result"), tableValuesCount]; + if (tableRowsCount == 1) + [countString appendFormat:NSLocalizedString(@"%d row in table", @"text showing a single row in the result"), tableRowsCount]; else - [countString appendFormat:NSLocalizedString(@"%d rows in table", @"text showing how many rows are in the result"), tableValuesCount]; + [countString appendFormat:NSLocalizedString(@"%d rows in table", @"text showing how many rows are in the result"), tableRowsCount]; // If a limit is active, display a string suggesting a limit is active } else if (!isFiltered && isLimited) { - [countString appendFormat:NSLocalizedString(@"Rows %d-%d of %@%d from table", @"text showing how many rows are in the limited result"), [limitRowsField intValue], [limitRowsField intValue]+tableValuesCount-1, maxNumRowsIsEstimate?@"~":@"", maxNumRows]; + [countString appendFormat:NSLocalizedString(@"Rows %d-%d of %@%d from table", @"text showing how many rows are in the limited result"), [limitRowsField intValue], [limitRowsField intValue]+tableRowsCount-1, maxNumRowsIsEstimate?@"~":@"", maxNumRows]; // If just a filter is active, show a count and an indication a filter is active } else if (isFiltered && !isLimited) { - if (tableValuesCount == 1) - [countString appendFormat:NSLocalizedString(@"%d row of %@%d matches filter", @"text showing how a single rows matched filter"), tableValuesCount, maxNumRowsIsEstimate?@"~":@"", maxNumRows]; + if (tableRowsCount == 1) + [countString appendFormat:NSLocalizedString(@"%d row of %@%d matches filter", @"text showing how a single rows matched filter"), tableRowsCount, maxNumRowsIsEstimate?@"~":@"", maxNumRows]; else - [countString appendFormat:NSLocalizedString(@"%d rows of %@%d match filter", @"text showing how many rows matched filter"), tableValuesCount, maxNumRowsIsEstimate?@"~":@"", maxNumRows]; + [countString appendFormat:NSLocalizedString(@"%d rows of %@%d match filter", @"text showing how many rows matched filter"), tableRowsCount, maxNumRowsIsEstimate?@"~":@"", maxNumRows]; // If both a filter and limit is active, display full string } else { - [countString appendFormat:NSLocalizedString(@"Rows %d-%d from filtered matches", @"text showing how many rows are in the limited filter match"), [limitRowsField intValue], [limitRowsField intValue]+tableValuesCount-1]; + [countString appendFormat:NSLocalizedString(@"Rows %d-%d from filtered matches", @"text showing how many rows are in the limited filter match"), [limitRowsField intValue], [limitRowsField intValue]+tableRowsCount-1]; } // If rows are selected, append selection count @@ -741,10 +859,18 @@ #pragma mark Table interface actions /* - * Reloads the current table data, performing a new SQL query. Now attempts to preserve sort order, filters, and viewport. + * Reloads the current table data, performing a new SQL query. Now attempts to preserve sort + * order, filters, and viewport. Performs the action in a new thread. */ - (IBAction)reloadTable:(id)sender { + [tableDocumentInstance startTaskWithDescription:NSLocalizedString(@"Reloading data...", @"Reloading data task description")]; + [NSThread detachNewThreadSelector:@selector(reloadTableTask) toTarget:self withObject:nil]; +} +- (void)reloadTableTask +{ + NSAutoreleasePool *reloadPool = [[NSAutoreleasePool alloc] init]; + // Check whether a save of the current row is required. if (![self saveRowOnDeselect]) return; @@ -756,14 +882,24 @@ // Load the table's data [self loadTable:selectedTable]; + + [tableDocumentInstance endTask]; + [reloadPool drain]; } /* - * Filter the table with arguments given by the user + * Filter the table with arguments given by the user. + * Performs the action in a new thread. */ - (IBAction)filterTable:(id)sender { if ([tableDocumentInstance isWorking]) return; + [tableDocumentInstance startTaskWithDescription:NSLocalizedString(@"Filtering table...", @"Filtering table task description")]; + [NSThread detachNewThreadSelector:@selector(filterTableTask) toTarget:self withObject:nil]; +} +- (void)filterTableTask +{ + NSAutoreleasePool *filterPool = [[NSAutoreleasePool alloc] init]; // Check whether a save of the current row is required. if (![self saveRowOnDeselect]) return; @@ -782,9 +918,15 @@ [limitRowsField setStringValue:[[NSNumber numberWithInt:(newLimit<1)?1:newLimit] stringValue]]; } - // Reload data using the new filter settings + // Reset and reload data using the new filter settings + previousTableRowsCount = 0; + tableRowsCount = 0; + [tableValues removeAllObjects]; [self loadTableValues]; [tableContentView scrollPoint:NSMakePoint(0.0, 0.0)]; + + [tableDocumentInstance endTask]; + [filterPool drain]; } /** @@ -876,7 +1018,7 @@ } } [tableValues addObject:newRow]; - tableValuesCount++; + tableRowsCount++; [tableContentView reloadData]; [tableContentView selectRowIndexes:[NSIndexSet indexSetWithIndex:[tableContentView numberOfRows]-1] byExtendingSelection:NO]; @@ -911,7 +1053,7 @@ //copy row tempRow = [NSMutableArray arrayWithArray:[tableValues objectAtIndex:[tableContentView selectedRow]]]; [tableValues insertObject:tempRow atIndex:[tableContentView selectedRow]+1]; - tableValuesCount++; + tableRowsCount++; //if we don't show blobs, read data for this duplicate column from db if ([prefs boolForKey:SPLoadBlobsAsNeeded]) { @@ -1330,95 +1472,6 @@ [limitRowsStepper setIntValue:0]; } -/* - * Processes a supplied streaming result set, loading it into the data array. - */ -- (void)processResultIntoDataStorage:(MCPStreamingResult *)theResult approximateRowCount:(long)targetRowCount -{ - NSArray *tempRow; - NSMutableArray *newRow; - NSMutableArray *columnBlobStatuses = [[NSMutableArray alloc] init]; - NSUInteger i; - - float relativeTargetRowCount = 100.0/targetRowCount; - NSUInteger nextTableDisplayBoundary = 50; - BOOL tableViewRedrawn = NO; - - long rowsProcessed = 0; - long columnsCount = [dataColumns count]; - - NSAutoreleasePool *dataLoadingPool; - NSProgressIndicator *dataLoadingIndicator = [tableDocumentInstance valueForKey:@"queryProgressBar"]; - BOOL prefsLoadBlobsAsNeeded = [prefs boolForKey:SPLoadBlobsAsNeeded]; - - // Build up an array of which columns are blobs for faster iteration - for ( i = 0; i < columnsCount ; i++ ) { - [columnBlobStatuses addObject:[NSNumber numberWithBool:[tableDataInstance columnIsBlobOrText:[NSArrayObjectAtIndex(dataColumns, i) objectForKey:@"name"] ]]]; - } - - // Set up an autorelease pool for row processing - dataLoadingPool = [[NSAutoreleasePool alloc] init]; - - // Loop through the result rows as they become available - while (tempRow = [theResult fetchNextRowAsArray]) { - - // Add values for hidden blob and text fields if appropriate - if ( prefsLoadBlobsAsNeeded ) { - NSMutableArrayAddObject(tableValues, [NSMutableArray arrayWithCapacity:columnsCount]); - tableValuesCount++; - newRow = NSArrayObjectAtIndex(tableValues, rowsProcessed); - for ( i = 0 ; i < columnsCount ; i++ ) { - if ( [NSArrayObjectAtIndex(columnBlobStatuses, i) boolValue] ) { - [newRow addObject:[SPNotLoaded notLoaded]]; - } else { - NSMutableArrayAddObject(newRow, NSArrayObjectAtIndex(tempRow, i)); - } - } - - // Otherwise just add the new row - } else { - NSMutableArrayAddObject(tableValues, [NSMutableArray arrayWithArray:tempRow]); - tableValuesCount++; - } - - // Update the task interface as necessary - rowsProcessed++; - /*if (!isFiltered) { - if (rowsProcessed < targetRowCount) { - [tableDocumentInstance setTaskPercentage:(rowsProcessed*relativeTargetRowCount)]; - } else if (rowsProcessed == targetRowCount) { - [tableDocumentInstance performSelectorOnMainThread:@selector(setTaskProgressToIndeterminate) withObject:nil waitUntilDone:NO]; - } - }*/ - - // 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 - if (!(rowsProcessed % 1024)) { - [dataLoadingPool drain]; - dataLoadingPool = [[NSAutoreleasePool alloc] init]; - } - } - - [tableContentView performSelectorOnMainThread:@selector(noteNumberOfRowsChanged) withObject:nil waitUntilDone:NO]; - [tableContentView setNeedsDisplay:YES]; - - // Clean up the autorelease pool and reset the progress indicator - [dataLoadingPool drain]; - [dataLoadingIndicator setIndeterminate:YES]; - - [columnBlobStatuses release]; -} - - /* * Tries to write a new row to the database. * Returns YES if row is written to database, otherwise NO; also returns YES if no row @@ -1548,6 +1601,7 @@ if ( isEditingNewRow ) { if ( [prefs boolForKey:SPReloadAfterAddingRow] ) { [tableWindow endEditingFor:nil]; + previousTableRowsCount = tableRowsCount; [self loadTableValues]; } else { @@ -1566,6 +1620,7 @@ // Reload table if set to - otherwise no action required. if ( [prefs boolForKey:SPReloadAfterEditingRow] ) { [tableWindow endEditingFor:nil]; + previousTableRowsCount = tableRowsCount; [self loadTableValues]; } } @@ -1774,7 +1829,7 @@ withObject:[NSMutableArray arrayWithArray:oldRow]]; isEditingRow = NO; } else { - tableValuesCount--; + tableRowsCount--; [tableValues removeObjectAtIndex:[tableContentView selectedRow]]; isEditingRow = NO; isEditingNewRow = NO; @@ -1989,13 +2044,14 @@ // Refresh table content if ( errors || reloadAfterRemovingRow ) { + previousTableRowsCount = tableRowsCount; [self loadTableValues]; } else { - for ( i = 0 ; i < tableValuesCount ; i++ ) { + for ( i = 0 ; i < tableRowsCount ; i++ ) { if ( ![selectedRows containsIndex:i] ) [tempResult addObject:NSArrayObjectAtIndex(tableValues, i)]; } - tableValuesCount = [tempResult count]; + tableRowsCount = [tempResult count]; [tableValues setArray:tempResult]; [tableContentView reloadData]; } @@ -2202,7 +2258,7 @@ // For unfiltered and non-limited tables, use the result count - and update the status count if (!isLimited && !isFiltered) { - maxNumRows = tableValuesCount; + maxNumRows = tableRowsCount; maxNumRowsIsEstimate = NO; [tableDataInstance setStatusValue:[NSString stringWithFormat:@"%d", maxNumRows] forKey:@"Rows"]; [tableDataInstance setStatusValue:@"y" forKey:@"RowsCountAccurate"]; @@ -2235,7 +2291,7 @@ if (checkStatusCount) { NSInteger foundMaxRows; if ([prefs boolForKey:SPLimitResults]) { - foundMaxRows = [limitRowsField intValue] - 1 + tableValuesCount; + foundMaxRows = [limitRowsField intValue] - 1 + tableRowsCount; if (foundMaxRows > maxNumRows) { if (foundMaxRows == [limitRowsField intValue] - 1 + [prefs integerForKey:SPLimitResultsValue]) { maxNumRows = foundMaxRows + 1; @@ -2245,8 +2301,8 @@ maxNumRowsIsEstimate = NO; } } - } else if (tableValuesCount > maxNumRows) { - maxNumRows = tableValuesCount; + } else if (tableRowsCount > maxNumRows) { + maxNumRows = tableRowsCount; maxNumRowsIsEstimate = YES; } [tableDataInstance setStatusValue:[NSString stringWithFormat:@"%d", maxNumRows] forKey:@"Rows"]; @@ -2310,21 +2366,26 @@ - (int)numberOfRowsInTableView:(NSTableView *)aTableView { - return tableValuesCount; + return tableRowsCount; } - (id)tableView:(CMCopyTable *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex { - if (rowIndex >= tableValuesCount) return nil; - id theValue = NSArrayObjectAtIndex(NSArrayObjectAtIndex(tableValues, rowIndex), [[aTableColumn identifier] intValue]); + // In some loading situations, where the table is being redrawn while a load operation is in process on a background + // thread, an index higher than the available rows/columns may be requested. Return "..." to indicate loading in these + // cases - when the load completes all table data will be redrawn. + int columnIndex = [[aTableColumn identifier] intValue]; + if (rowIndex >= tableRowsCount || columnIndex >= tableColumnsCount) return @"..."; - if ([theValue isKindOfClass:[NSData class]]) - return [theValue shortStringRepresentationUsingEncoding:[mySQLConnection encoding]]; + id theValue = NSArrayObjectAtIndex(NSArrayObjectAtIndex(tableValues, rowIndex), columnIndex); if ([theValue isNSNull]) return [prefs objectForKey:SPNullValue]; + if ([theValue isKindOfClass:[NSData class]]) + return [theValue shortStringRepresentationUsingEncoding:[mySQLConnection encoding]]; + if ([theValue isSPNotLoaded]) return NSLocalizedString(@"(not loaded)", @"value shown for hidden blob and text fields"); @@ -2334,21 +2395,32 @@ /** * This function changes the text color of text/blob fields which are null or not yet loaded to gray */ -- (void)tableView:(CMCopyTable *)aTableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)aTableColumn row:(int)row +- (void)tableView:(CMCopyTable *)aTableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)aTableColumn row:(int)rowIndex { - - if (row >= tableValuesCount) return; if (![cell respondsToSelector:@selector(setTextColor:)]) return; + // In some loading situations, where the table is being redrawn while a load operation is in process on a background + // thread, an index higher than the available rows/columns may be requested. Return gray to indicate loading in these + // cases - when the load completes all table data will be redrawn. + int columnIndex = [[aTableColumn identifier] intValue]; + if (rowIndex >= tableRowsCount || columnIndex >= tableColumnsCount) { + [cell setTextColor:[NSColor lightGrayColor]]; + return; + } + + id theValue = NSArrayObjectAtIndex(NSArrayObjectAtIndex(tableValues, rowIndex), columnIndex); + if (!theValue) { + [cell setTextColor:[NSColor lightGrayColor]]; + return; + } + // If user wants to edit 'cell' set text color to black and return to avoid // writing in gray if value was NULL - if ( [aTableView editedColumn] == [[aTableColumn identifier] intValue] && [aTableView editedRow] == row) { + if ( [aTableView editedColumn] == [[aTableColumn identifier] intValue] && [aTableView editedRow] == rowIndex) { [cell setTextColor:[NSColor blackColor]]; return; } - id theValue = NSArrayObjectAtIndex(NSArrayObjectAtIndex(tableValues, row), [[aTableColumn identifier] intValue]); - // For null cells and not loaded cells, display the contents in gray. if ([theValue isNSNull] || [theValue isSPNotLoaded]) { [cell setTextColor:[NSColor lightGrayColor]]; @@ -2386,29 +2458,37 @@ #pragma mark - #pragma mark TableView delegate methods -- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)tableColumn -/* - sorts the tableView by the clicked column - if clicked twice, order is descending +/** + * Sorts the tableView by the clicked column. + * If clicked twice, order is altered to descending. + * Performs the task in a new thread. */ +- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)tableColumn { if ( [selectedTable isEqualToString:@""] || !selectedTable ) return; - // Check whether a save of the current row is required. - if ( ![self saveRowOnDeselect] ) return; - // Prevent sorting while the table is still loading if ([tableDocumentInstance isWorking]) return; - - //sets order descending if a header is clicked twice - if ( [[tableColumn identifier] isEqualTo:sortCol] ) { - if ( isDesc ) { - isDesc = NO; - } else { - isDesc = YES; - } + + // Start the task + [tableDocumentInstance startTaskWithDescription:NSLocalizedString(@"Sorting table...", @"Sorting table task description")]; + [NSThread detachNewThreadSelector:@selector(sortTableTaskWithColumn:) toTarget:self withObject:tableColumn]; +} +- (void)sortTableTaskWithColumn:(NSTableColumn *)tableColumn +{ + NSAutoreleasePool *sortPool = [[NSAutoreleasePool alloc] init]; + + // Check whether a save of the current row is required. + if (![self saveRowOnDeselect]) { + [sortPool drain]; + return; + } + + // Sets order descending if a header is clicked twice + if ([[tableColumn identifier] isEqualTo:sortCol]) { + isDesc = !isDesc; } else { isDesc = NO; [tableContentView setIndicatorImage:nil inTableColumn:[tableContentView tableColumnWithIdentifier:sortCol]]; @@ -2417,21 +2497,26 @@ sortCol = [[NSNumber alloc] initWithInt:[[tableColumn identifier] intValue]]; // Update data using the new sort order + previousTableRowsCount = tableRowsCount; [self loadTableValues]; if ( ![[mySQLConnection getLastErrorMessage] isEqualToString:@""] ) { NSBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil, [NSString stringWithFormat:NSLocalizedString(@"Couldn't sort table. MySQL said: %@", @"message of panel when sorting of table failed"), [mySQLConnection getLastErrorMessage]]); + [sortPool drain]; return; } - - //sets highlight and indicatorImage + + // Set the highlight and indicatorImage [tableContentView setHighlightedTableColumn:tableColumn]; - if ( isDesc ) { + if (isDesc) { [tableContentView setIndicatorImage:[NSImage imageNamed:@"NSDescendingSortIndicator"] inTableColumn:tableColumn]; } else { [tableContentView setIndicatorImage:[NSImage imageNamed:@"NSAscendingSortIndicator"] inTableColumn:tableColumn]; } + + [tableDocumentInstance endTask]; + [sortPool drain]; } - (void)tableViewSelectionDidChange:(NSNotification *)aNotification @@ -2635,10 +2720,8 @@ - (void) startDocumentTaskForTab:(NSNotification *)aNotification { - // Only proceed if the current document is the notifying document, and only if - // this view is selected. - if ([aNotification object] != tableDocumentInstance - || ![[[aNotification object] selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_CONTENT]) + // Only proceed if this view is selected. + if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_CONTENT]) return; [addButton setEnabled:NO]; @@ -2654,10 +2737,8 @@ - (void) endDocumentTaskForTab:(NSNotification *)aNotification { - // Only proceed if the current document is the notifying document, and only if - // this view is selected. - if ([aNotification object] != tableDocumentInstance - || ![[[aNotification object] selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_CONTENT]) + // Only proceed if this view is selected. + if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_CONTENT]) return; if ( ![[[tableDataInstance statusValues] objectForKey:@"Rows"] isNSNull] && selectedTable && [selectedTable length] && [tableDataInstance tableEncoding]) [addButton setEnabled:YES]; @@ -2729,7 +2810,7 @@ } else if ( isEditingNewRow ) { isEditingRow = NO; isEditingNewRow = NO; - tableValuesCount--; + tableRowsCount--; [tableValues removeObjectAtIndex:row]; [tableContentView reloadData]; } diff --git a/Source/TableSource.m b/Source/TableSource.m index f5900bc5..2111a498 100644 --- a/Source/TableSource.m +++ b/Source/TableSource.m @@ -47,7 +47,7 @@ loads aTable, put it in an array, update the tableViewColumns and reload the tab id extra; int i; SPSQLParser *fieldParser; - BOOL enableInteraction = ![tableDocumentInstance isWorking]; + BOOL enableInteraction = ![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_STRUCTURE] || ![tableDocumentInstance isWorking]; // Check whether a save of the current row is required. if ( ![self saveRowOnDeselect] ) return; @@ -1057,10 +1057,8 @@ returns a dictionary containing enum/set field names as key and possible values - (void) startDocumentTaskForTab:(NSNotification *)aNotification { - // Only proceed if the current document is the notifying document, and only if - // this view is selected. - if ([aNotification object] != tableDocumentInstance - || ![[[aNotification object] selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_STRUCTURE]) + // Only proceed if this view is selected. + if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_STRUCTURE]) return; [tableSourceView setEnabled:NO]; @@ -1083,8 +1081,7 @@ returns a dictionary containing enum/set field names as key and possible values { // Only re-enable elements if the current tab is the structure view - if ([aNotification object] != tableDocumentInstance - || ![[[aNotification object] selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_STRUCTURE]) + if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:MAIN_TOOLBAR_TABLE_STRUCTURE]) return; BOOL editingEnabled = ([tablesListInstance tableType] == SP_TABLETYPE_TABLE); @@ -1471,11 +1468,11 @@ would result in a position change. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startDocumentTaskForTab:) name:SPDocumentTaskStartNotification - object:nil]; + object:tableDocumentInstance]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endDocumentTaskForTab:) name:SPDocumentTaskEndNotification - object:nil]; + object:tableDocumentInstance]; } - (void)dealloc diff --git a/Source/TablesList.h b/Source/TablesList.h index d0349531..e32ec789 100644 --- a/Source/TablesList.h +++ b/Source/TablesList.h @@ -122,7 +122,8 @@ enum sp_table_types // Additional methods - (void)setConnection:(MCPConnection *)theConnection; - (void)doPerformQueryService:(NSString *)query; -- (void)updateSelection; +- (void)updateSelectionWithTaskString:(NSString *)taskString; +- (void)updateSelectionTask; - (void)selectTableAtIndex:(NSNumber *)row; // Getters diff --git a/Source/TablesList.m b/Source/TablesList.m index bb5f80ec..9264b9f1 100644 --- a/Source/TablesList.m +++ b/Source/TablesList.m @@ -600,209 +600,11 @@ * Updates the current table selection. Triggered most times tableViewSelectionDidChange: * fires, and also as a result of certain table actions. */ -- (void)updateSelection +- (void)updateSelectionWithTaskString:(NSString *)taskString { - if ( [tablesListView numberOfSelectedRows] == 1 && [[filteredTables objectAtIndex:[tablesListView selectedRow]] length] ) { - // Update the selected table name and type - if (selectedTableName) [selectedTableName release]; - selectedTableName = [[NSString alloc] initWithString:[filteredTables objectAtIndex:[tablesListView selectedRow]]]; - selectedTableType = [[filteredTableTypes objectAtIndex:[tablesListView selectedRow]] intValue]; - - // Remove the "current selection" item for filtered lists if appropriate - if (isTableListFiltered && [tablesListView selectedRow] < [filteredTables count] - 2 && [filteredTables count] > 2 - && [[filteredTableTypes objectAtIndex:[filteredTableTypes count]-2] intValue] == SP_TABLETYPE_NONE - && [[filteredTables objectAtIndex:[filteredTables count]-2] isEqualToString:NSLocalizedString(@"CURRENT SELECTION",@"header for current selection in filtered list")]) - { - [filteredTables removeObjectsInRange:NSMakeRange([filteredTables count]-2, 2)]; - [filteredTableTypes removeObjectsInRange:NSMakeRange([filteredTableTypes count]-2, 2)]; - [tablesListView reloadData]; - } - - // Reset the table information caches - [tableDataInstance resetAllData]; - - [separatorTableMenuItem setHidden:NO]; - [separatorTableContextMenuItem setHidden:NO]; - - if( selectedTableType == SP_TABLETYPE_VIEW || selectedTableType == SP_TABLETYPE_TABLE) { - - // tableEncoding == nil indicates that there was an error while retrieving table data - NSString *tableEncoding = [tableDataInstance tableEncoding]; - - // If encoding is set to Autodetect, update the connection character set encoding - // based on the newly selected table's encoding - but only if it differs from the current encoding. - if ([[[NSUserDefaults standardUserDefaults] objectForKey:SPDefaultEncoding] isEqualToString:@"Autodetect"]) { - if (tableEncoding != nil && ![tableEncoding isEqualToString:[tableDocumentInstance connectionEncoding]]) { - [tableDocumentInstance setConnectionEncoding:tableEncoding reloadingViews:NO]; - [tableDataInstance resetAllData]; - } - } - - if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 0 ) { - [tableSourceInstance loadTable:selectedTableName]; - structureLoaded = YES; - contentLoaded = NO; - statusLoaded = NO; - } else if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 1 ) { - if(tableEncoding == nil) { - [tableContentInstance loadTable:nil]; - } else { - [tableContentInstance loadTable:selectedTableName]; - } - structureLoaded = NO; - contentLoaded = YES; - statusLoaded = NO; - } else if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 3 ) { - [extendedTableInfoInstance loadTable:selectedTableName]; - structureLoaded = NO; - contentLoaded = NO; - statusLoaded = YES; - } else { - structureLoaded = NO; - contentLoaded = NO; - statusLoaded = NO; - } - } else { - - // if we are not looking at a table or view, clear these - [tableSourceInstance loadTable:nil]; - [tableContentInstance loadTable:nil]; - [extendedTableInfoInstance loadTable:nil]; - structureLoaded = NO; - contentLoaded = NO; - statusLoaded = NO; - } - - // Set gear menu items Remove/Duplicate table/view and mainMenu > Table items - // according to the table types - NSMenu *tableSubMenu = [[[NSApp mainMenu] itemWithTitle:@"Table"] submenu]; - - if(selectedTableType == SP_TABLETYPE_VIEW) - { - // Change mainMenu > Table > ... according to table type - [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create View Syntax", @"copy create view syntax menu item")]; - [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create View Syntax", @"show create view syntax menu item")]; - [[tableSubMenu itemAtIndex:2] setHidden:NO]; // divider - [[tableSubMenu itemAtIndex:3] setHidden:NO]; - [[tableSubMenu itemAtIndex:3] setTitle:NSLocalizedString(@"Check View", @"check view menu item")]; - [[tableSubMenu itemAtIndex:4] setHidden:YES]; // repair - [[tableSubMenu itemAtIndex:5] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:6] setHidden:YES]; // analyse - [[tableSubMenu itemAtIndex:7] setHidden:YES]; // optimize - [[tableSubMenu itemAtIndex:8] setHidden:NO]; - [[tableSubMenu itemAtIndex:8] setTitle:NSLocalizedString(@"Flush View", @"flush view menu item")]; - [[tableSubMenu itemAtIndex:9] setHidden:YES]; // checksum - - [renameTableMenuItem setHidden:NO]; // we don't have to check the mysql version - [renameTableMenuItem setTitle:NSLocalizedString(@"Rename View...", @"rename view menu title")]; - [duplicateTableMenuItem setHidden:NO]; - [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate View...", @"duplicate view menu title")]; - [truncateTableButton setHidden:YES]; - [removeTableMenuItem setTitle:NSLocalizedString(@"Remove View", @"remove view menu title")]; - - [renameTableContextMenuItem setHidden:NO]; // we don't have to check the mysql version - [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename View...", @"rename view menu title")]; - [duplicateTableContextMenuItem setHidden:NO]; - [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate View...", @"duplicate view menu title")]; - [truncateTableContextButton setHidden:YES]; - [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove View", @"remove view menu title")]; - } - else if(selectedTableType == SP_TABLETYPE_TABLE) { - [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create Table Syntax", @"copy create table syntax menu item")]; - [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create Table Syntax", @"show create table syntax menu item")]; - [[tableSubMenu itemAtIndex:2] setHidden:NO]; // divider - [[tableSubMenu itemAtIndex:3] setHidden:NO]; - [[tableSubMenu itemAtIndex:3] setTitle:NSLocalizedString(@"Check Table", @"check table menu item")]; - [[tableSubMenu itemAtIndex:4] setHidden:NO]; - [[tableSubMenu itemAtIndex:5] setHidden:NO]; // divider - [[tableSubMenu itemAtIndex:6] setHidden:NO]; - [[tableSubMenu itemAtIndex:7] setHidden:NO]; - [[tableSubMenu itemAtIndex:8] setHidden:NO]; - [[tableSubMenu itemAtIndex:8] setTitle:NSLocalizedString(@"Flush Table", @"flush table menu item")]; - [[tableSubMenu itemAtIndex:9] setHidden:NO]; - - [renameTableMenuItem setHidden:NO]; - [renameTableMenuItem setTitle:NSLocalizedString(@"Rename Table...", @"rename table menu title")]; - [duplicateTableMenuItem setHidden:NO]; - [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate Table...", @"duplicate table menu title")]; - [truncateTableButton setHidden:NO]; - [truncateTableButton setTitle:NSLocalizedString(@"Truncate Table", @"truncate table menu title")]; - [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Table", @"remove table menu title")]; - - [renameTableContextMenuItem setHidden:NO]; - [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename Table...", @"rename table menu title")]; - [duplicateTableContextMenuItem setHidden:NO]; - [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate Table...", @"duplicate table menu title")]; - [truncateTableContextButton setHidden:NO]; - [truncateTableContextButton setTitle:NSLocalizedString(@"Truncate Table", @"truncate table menu title")]; - [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Table", @"remove table menu title")]; - - } - else if(selectedTableType == SP_TABLETYPE_PROC) { - [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create Procedure Syntax", @"copy create proc syntax menu item")]; - [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create Procedure Syntax", @"show create proc syntax menu item")]; - [[tableSubMenu itemAtIndex:2] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:3] setHidden:YES]; // copy columns - [[tableSubMenu itemAtIndex:4] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:5] setHidden:YES]; - [[tableSubMenu itemAtIndex:6] setHidden:YES]; - [[tableSubMenu itemAtIndex:7] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:8] setHidden:YES]; - [[tableSubMenu itemAtIndex:9] setHidden:YES]; - - [renameTableMenuItem setHidden:NO]; - [renameTableMenuItem setTitle:NSLocalizedString(@"Rename Procedure...", @"rename proc menu title")]; - [duplicateTableMenuItem setHidden:NO]; - [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate Procedure...", @"duplicate proc menu title")]; - [truncateTableButton setHidden:YES]; - [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Procedure", @"remove proc menu title")]; - - [renameTableContextMenuItem setHidden:NO]; - [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename Procedure...", @"rename proc menu title")]; - [duplicateTableContextMenuItem setHidden:NO]; - [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate Procedure...", @"duplicate proc menu title")]; - [truncateTableContextButton setHidden:YES]; - [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Procedure", @"remove proc menu title")]; - - } - else if(selectedTableType == SP_TABLETYPE_FUNC) { - [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create Function Syntax", @"copy create func syntax menu item")]; - [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create Function Syntax", @"show create func syntax menu item")]; - [[tableSubMenu itemAtIndex:2] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:3] setHidden:YES]; // copy columns - [[tableSubMenu itemAtIndex:4] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:5] setHidden:YES]; - [[tableSubMenu itemAtIndex:6] setHidden:YES]; - [[tableSubMenu itemAtIndex:7] setHidden:YES]; // divider - [[tableSubMenu itemAtIndex:8] setHidden:YES]; - [[tableSubMenu itemAtIndex:9] setHidden:YES]; - - [renameTableMenuItem setHidden:NO]; - [renameTableMenuItem setTitle:NSLocalizedString(@"Rename Function...", @"rename func menu title")]; - [duplicateTableMenuItem setHidden:NO]; - [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate Function...", @"duplicate func menu title")]; - [truncateTableButton setHidden:YES]; - [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Function", @"remove func menu title")]; - - [renameTableContextMenuItem setHidden:NO]; - [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename Function...", @"rename func menu title")]; - [duplicateTableContextMenuItem setHidden:NO]; - [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate Function...", @"duplicate func menu title")]; - [truncateTableContextButton setHidden:YES]; - [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Function", @"remove func menu title")]; - - } - - // set window title - [tableWindow setTitle:[tableDocumentInstance displaySPName]]; - - // Update the "Show Create Syntax" window if it's already opened - // according to the selected table/view/proc/func - if([[tableDocumentInstance getCreateTableSyntaxWindow] isVisible]) - [tableDocumentInstance showCreateTableSyntax:self]; - - } else { + // If there is a multiple or blank selection, clear all views directly. + if ( [tablesListView numberOfSelectedRows] != 1 || ![[filteredTables objectAtIndex:[tablesListView selectedRow]] length] ) { NSIndexSet *indexes = [tablesListView selectedRowIndexes]; // Update the selected table name and type @@ -885,10 +687,232 @@ // set window title [tableWindow setTitle:[tableDocumentInstance displaySPName]]; + + // Add a history entry + [spHistoryControllerInstance updateHistoryEntries]; + + // Notify listeners of the table change now that the state is fully set up + [[NSNotificationCenter defaultCenter] postNotificationName:SPTableChangedNotification object:tableDocumentInstance]; + return; } + // Otherwise, set up a task and fire up a thread to deal with view changes and data loading + [tableDocumentInstance startTaskWithDescription:taskString]; + [NSThread detachNewThreadSelector:@selector(updateSelectionTask) toTarget:self withObject:nil]; +} + +- (void) updateSelectionTask +{ + NSAutoreleasePool *selectionChangePool = [[NSAutoreleasePool alloc] init]; + + // Update the selected table name and type + if (selectedTableName) [selectedTableName release]; + selectedTableName = [[NSString alloc] initWithString:[filteredTables objectAtIndex:[tablesListView selectedRow]]]; + selectedTableType = [[filteredTableTypes objectAtIndex:[tablesListView selectedRow]] intValue]; + + // Remove the "current selection" item for filtered lists if appropriate + if (isTableListFiltered && [tablesListView selectedRow] < [filteredTables count] - 2 && [filteredTables count] > 2 + && [[filteredTableTypes objectAtIndex:[filteredTableTypes count]-2] intValue] == SP_TABLETYPE_NONE + && [[filteredTables objectAtIndex:[filteredTables count]-2] isEqualToString:NSLocalizedString(@"CURRENT SELECTION",@"header for current selection in filtered list")]) + { + [filteredTables removeObjectsInRange:NSMakeRange([filteredTables count]-2, 2)]; + [filteredTableTypes removeObjectsInRange:NSMakeRange([filteredTableTypes count]-2, 2)]; + [tablesListView reloadData]; + } + + // Reset the table information caches + [tableDataInstance resetAllData]; + + [separatorTableMenuItem setHidden:NO]; + [separatorTableContextMenuItem setHidden:NO]; + + if( selectedTableType == SP_TABLETYPE_VIEW || selectedTableType == SP_TABLETYPE_TABLE) { + + // tableEncoding == nil indicates that there was an error while retrieving table data + NSString *tableEncoding = [tableDataInstance tableEncoding]; + + // If encoding is set to Autodetect, update the connection character set encoding + // based on the newly selected table's encoding - but only if it differs from the current encoding. + if ([[[NSUserDefaults standardUserDefaults] objectForKey:SPDefaultEncoding] isEqualToString:@"Autodetect"]) { + if (tableEncoding != nil && ![tableEncoding isEqualToString:[tableDocumentInstance connectionEncoding]]) { + [tableDocumentInstance setConnectionEncoding:tableEncoding reloadingViews:NO]; + [tableDataInstance resetAllData]; + } + } + + if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 0 ) { + [tableSourceInstance loadTable:selectedTableName]; + structureLoaded = YES; + contentLoaded = NO; + statusLoaded = NO; + } else if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 1 ) { + if(tableEncoding == nil) { + [tableContentInstance loadTable:nil]; + } else { + [tableContentInstance loadTable:selectedTableName]; + } + structureLoaded = NO; + contentLoaded = YES; + statusLoaded = NO; + } else if ( [tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 3 ) { + [extendedTableInfoInstance loadTable:selectedTableName]; + structureLoaded = NO; + contentLoaded = NO; + statusLoaded = YES; + } else { + structureLoaded = NO; + contentLoaded = NO; + statusLoaded = NO; + } + } else { + + // if we are not looking at a table or view, clear these + [tableSourceInstance loadTable:nil]; + [tableContentInstance loadTable:nil]; + [extendedTableInfoInstance loadTable:nil]; + structureLoaded = NO; + contentLoaded = NO; + statusLoaded = NO; + } + + // Set gear menu items Remove/Duplicate table/view and mainMenu > Table items + // according to the table types + NSMenu *tableSubMenu = [[[NSApp mainMenu] itemWithTitle:@"Table"] submenu]; + + if(selectedTableType == SP_TABLETYPE_VIEW) + { + // Change mainMenu > Table > ... according to table type + [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create View Syntax", @"copy create view syntax menu item")]; + [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create View Syntax", @"show create view syntax menu item")]; + [[tableSubMenu itemAtIndex:2] setHidden:NO]; // divider + [[tableSubMenu itemAtIndex:3] setHidden:NO]; + [[tableSubMenu itemAtIndex:3] setTitle:NSLocalizedString(@"Check View", @"check view menu item")]; + [[tableSubMenu itemAtIndex:4] setHidden:YES]; // repair + [[tableSubMenu itemAtIndex:5] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:6] setHidden:YES]; // analyse + [[tableSubMenu itemAtIndex:7] setHidden:YES]; // optimize + [[tableSubMenu itemAtIndex:8] setHidden:NO]; + [[tableSubMenu itemAtIndex:8] setTitle:NSLocalizedString(@"Flush View", @"flush view menu item")]; + [[tableSubMenu itemAtIndex:9] setHidden:YES]; // checksum + + [renameTableMenuItem setHidden:NO]; // we don't have to check the mysql version + [renameTableMenuItem setTitle:NSLocalizedString(@"Rename View...", @"rename view menu title")]; + [duplicateTableMenuItem setHidden:NO]; + [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate View...", @"duplicate view menu title")]; + [truncateTableButton setHidden:YES]; + [removeTableMenuItem setTitle:NSLocalizedString(@"Remove View", @"remove view menu title")]; + + [renameTableContextMenuItem setHidden:NO]; // we don't have to check the mysql version + [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename View...", @"rename view menu title")]; + [duplicateTableContextMenuItem setHidden:NO]; + [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate View...", @"duplicate view menu title")]; + [truncateTableContextButton setHidden:YES]; + [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove View", @"remove view menu title")]; + } + else if(selectedTableType == SP_TABLETYPE_TABLE) { + [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create Table Syntax", @"copy create table syntax menu item")]; + [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create Table Syntax", @"show create table syntax menu item")]; + [[tableSubMenu itemAtIndex:2] setHidden:NO]; // divider + [[tableSubMenu itemAtIndex:3] setHidden:NO]; + [[tableSubMenu itemAtIndex:3] setTitle:NSLocalizedString(@"Check Table", @"check table menu item")]; + [[tableSubMenu itemAtIndex:4] setHidden:NO]; + [[tableSubMenu itemAtIndex:5] setHidden:NO]; // divider + [[tableSubMenu itemAtIndex:6] setHidden:NO]; + [[tableSubMenu itemAtIndex:7] setHidden:NO]; + [[tableSubMenu itemAtIndex:8] setHidden:NO]; + [[tableSubMenu itemAtIndex:8] setTitle:NSLocalizedString(@"Flush Table", @"flush table menu item")]; + [[tableSubMenu itemAtIndex:9] setHidden:NO]; + + [renameTableMenuItem setHidden:NO]; + [renameTableMenuItem setTitle:NSLocalizedString(@"Rename Table...", @"rename table menu title")]; + [duplicateTableMenuItem setHidden:NO]; + [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate Table...", @"duplicate table menu title")]; + [truncateTableButton setHidden:NO]; + [truncateTableButton setTitle:NSLocalizedString(@"Truncate Table", @"truncate table menu title")]; + [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Table", @"remove table menu title")]; + + [renameTableContextMenuItem setHidden:NO]; + [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename Table...", @"rename table menu title")]; + [duplicateTableContextMenuItem setHidden:NO]; + [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate Table...", @"duplicate table menu title")]; + [truncateTableContextButton setHidden:NO]; + [truncateTableContextButton setTitle:NSLocalizedString(@"Truncate Table", @"truncate table menu title")]; + [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Table", @"remove table menu title")]; + + } + else if(selectedTableType == SP_TABLETYPE_PROC) { + [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create Procedure Syntax", @"copy create proc syntax menu item")]; + [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create Procedure Syntax", @"show create proc syntax menu item")]; + [[tableSubMenu itemAtIndex:2] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:3] setHidden:YES]; // copy columns + [[tableSubMenu itemAtIndex:4] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:5] setHidden:YES]; + [[tableSubMenu itemAtIndex:6] setHidden:YES]; + [[tableSubMenu itemAtIndex:7] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:8] setHidden:YES]; + [[tableSubMenu itemAtIndex:9] setHidden:YES]; + + [renameTableMenuItem setHidden:NO]; + [renameTableMenuItem setTitle:NSLocalizedString(@"Rename Procedure...", @"rename proc menu title")]; + [duplicateTableMenuItem setHidden:NO]; + [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate Procedure...", @"duplicate proc menu title")]; + [truncateTableButton setHidden:YES]; + [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Procedure", @"remove proc menu title")]; + + [renameTableContextMenuItem setHidden:NO]; + [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename Procedure...", @"rename proc menu title")]; + [duplicateTableContextMenuItem setHidden:NO]; + [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate Procedure...", @"duplicate proc menu title")]; + [truncateTableContextButton setHidden:YES]; + [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Procedure", @"remove proc menu title")]; + + } + else if(selectedTableType == SP_TABLETYPE_FUNC) { + [[tableSubMenu itemAtIndex:0] setTitle:NSLocalizedString(@"Copy Create Function Syntax", @"copy create func syntax menu item")]; + [[tableSubMenu itemAtIndex:1] setTitle:NSLocalizedString(@"Show Create Function Syntax", @"show create func syntax menu item")]; + [[tableSubMenu itemAtIndex:2] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:3] setHidden:YES]; // copy columns + [[tableSubMenu itemAtIndex:4] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:5] setHidden:YES]; + [[tableSubMenu itemAtIndex:6] setHidden:YES]; + [[tableSubMenu itemAtIndex:7] setHidden:YES]; // divider + [[tableSubMenu itemAtIndex:8] setHidden:YES]; + [[tableSubMenu itemAtIndex:9] setHidden:YES]; + + [renameTableMenuItem setHidden:NO]; + [renameTableMenuItem setTitle:NSLocalizedString(@"Rename Function...", @"rename func menu title")]; + [duplicateTableMenuItem setHidden:NO]; + [duplicateTableMenuItem setTitle:NSLocalizedString(@"Duplicate Function...", @"duplicate func menu title")]; + [truncateTableButton setHidden:YES]; + [removeTableMenuItem setTitle:NSLocalizedString(@"Remove Function", @"remove func menu title")]; + + [renameTableContextMenuItem setHidden:NO]; + [renameTableContextMenuItem setTitle:NSLocalizedString(@"Rename Function...", @"rename func menu title")]; + [duplicateTableContextMenuItem setHidden:NO]; + [duplicateTableContextMenuItem setTitle:NSLocalizedString(@"Duplicate Function...", @"duplicate func menu title")]; + [truncateTableContextButton setHidden:YES]; + [removeTableContextMenuItem setTitle:NSLocalizedString(@"Remove Function", @"remove func menu title")]; + + } + + // set window title + [tableWindow setTitle:[tableDocumentInstance displaySPName]]; + + // Update the "Show Create Syntax" window if it's already opened + // according to the selected table/view/proc/func + if([[tableDocumentInstance getCreateTableSyntaxWindow] isVisible]) + [tableDocumentInstance showCreateTableSyntax:self]; + + // Add a history entry [spHistoryControllerInstance updateHistoryEntries]; + + // Notify listeners of the table change now that the state is fully set up + [[NSNotificationCenter defaultCenter] postNotificationName:SPTableChangedNotification object:tableDocumentInstance]; + + // Empty the loading pool and exit the thread + [tableDocumentInstance endTask]; + [selectionChangePool drain]; } #pragma mark - @@ -1082,7 +1106,7 @@ selectedTableName = [[NSString alloc] initWithString:[tables objectAtIndex:itemIndex]]; selectedTableType = [[tableTypes objectAtIndex:itemIndex] intValue]; [self updateFilter:self]; - [self updateSelection]; + [self updateSelectionWithTaskString:[NSString stringWithFormat:NSLocalizedString(@"Loading %@...", @"Loading table task string"), theName]]; } } return YES; @@ -1306,7 +1330,10 @@ // Save existing scroll position and details [spHistoryControllerInstance updateHistoryEntries]; - [self updateSelection]; + NSString *tableName = @"data"; + if ([tablesListView numberOfSelectedRows] == 1 && [[filteredTables objectAtIndex:[tablesListView selectedRow]] length]) + tableName = [filteredTables objectAtIndex:[tablesListView selectedRow]]; + [self updateSelectionWithTaskString:[NSString stringWithFormat:NSLocalizedString(@"Loading %@...", @"Loading table task string"), tableName]]; } /** @@ -1557,10 +1584,6 @@ */ - (void) startDocumentTaskForTab:(NSNotification *)aNotification { - - // Only proceed if the notification was received from the current document. - if ([aNotification object] != tableDocumentInstance) return; - [toolbarAddButton setEnabled:NO]; [toolbarActionsButton setEnabled:NO]; [toolbarReloadButton setEnabled:NO]; @@ -1571,8 +1594,6 @@ */ - (void) endDocumentTaskForTab:(NSNotification *)aNotification { - if ([aNotification object] != tableDocumentInstance) return; - [toolbarAddButton setEnabled:YES]; [toolbarActionsButton setEnabled:YES]; [toolbarReloadButton setEnabled:YES]; @@ -1642,11 +1663,11 @@ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startDocumentTaskForTab:) name:SPDocumentTaskStartNotification - object:nil]; + object:tableDocumentInstance]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endDocumentTaskForTab:) name:SPDocumentTaskEndNotification - object:nil]; + object:tableDocumentInstance]; } /** @@ -1836,8 +1857,8 @@ selectedTableName = [[NSString alloc] initWithString:tableName]; selectedTableType = SP_TABLETYPE_TABLE; [self updateFilter:self]; - [self updateSelection]; [tablesListView scrollRowToVisible:[tablesListView selectedRow]]; + [self updateSelectionWithTaskString:[NSString stringWithFormat:NSLocalizedString(@"Loading %@...", @"Loading table task string"), selectedTableName]]; } else { // Error while creating new table @@ -2028,8 +2049,8 @@ selectedTableName = [[NSString alloc] initWithString:[copyTableNameField stringValue]]; selectedTableType = tblType; [self updateFilter:self]; - [self updateSelection]; [tablesListView scrollRowToVisible:[tablesListView selectedRow]]; + [self updateSelectionWithTaskString:[NSString stringWithFormat:NSLocalizedString(@"Loading %@...", @"Loading table task string"), selectedTableName]]; } } } @@ -2056,7 +2077,8 @@ if (selectedTableName) [selectedTableName release]; selectedTableName = [[NSString alloc] initWithString:[tableRenameField stringValue]]; [tablesListView reloadData]; - [self updateSelection]; + [self updateSelectionWithTaskString:[NSString stringWithFormat:NSLocalizedString(@"Loading %@...", @"Loading table task string"), selectedTableName]]; + return; } } else { // procedures and functions can only be renamed if one creates the new one and delete the old one @@ -2120,7 +2142,8 @@ if (selectedTableName) [selectedTableName release]; selectedTableName = [[NSString alloc] initWithString:[tableRenameField stringValue]]; [tablesListView reloadData]; - [self updateSelection]; + [self updateSelectionWithTaskString:[NSString stringWithFormat:NSLocalizedString(@"Loading %@...", @"Loading table task string"), selectedTableName]]; + return; } } -- cgit v1.2.3