aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2010-03-22 23:07:03 +0000
committerrowanbeentje <rowan@beent.je>2010-03-22 23:07:03 +0000
commit9892a96b80073686b0dd1205d4f859b10d32336f (patch)
treef4f4caaa72f5983dfc23a1f686603b61baf0374c
parent6728ccd128a5320256ac51c0a617f0c76b331ea7 (diff)
downloadsequelpro-9892a96b80073686b0dd1205d4f859b10d32336f.tar.gz
sequelpro-9892a96b80073686b0dd1205d4f859b10d32336f.tar.bz2
sequelpro-9892a96b80073686b0dd1205d4f859b10d32336f.zip
- Simplify table source table setup and make thread safe. This should address http://log.sequelpro.com/view/43 , http://log.sequelpro.com/view/46
- Improve keepalive timer interaction - this should address http://log.sequelpro.com/view/74 and http://log.sequelpro.com/view/71 - Further thread safety improvements to Custom Query, Table Document, and the history controller
-rw-r--r--Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m6
-rw-r--r--Source/CustomQuery.m27
-rw-r--r--Source/SPHistoryController.m7
-rw-r--r--Source/TableDocument.m7
-rw-r--r--Source/TableSource.h1
-rw-r--r--Source/TableSource.m299
6 files changed, 169 insertions, 178 deletions
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m
index 1a4786ec..7f5c4365 100644
--- a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m
+++ b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m
@@ -689,6 +689,12 @@ void pingConnectionTask(void *ptr)
*/
- (void)stopKeepAliveTimer
{
+ // Stop keepalives on the main thread to avoid memory issues
+ if (![NSThread isMainThread]) {
+ [self performSelectorOnMainThread:@selector(stopKeepAliveTimer) withObject:nil waitUntilDone:NO];
+ return;
+ }
+
if (keepAliveThread != NULL) pthread_cancel(keepAliveThread), keepAliveThread = NULL;
if (!keepAliveTimer) return;
[keepAliveTimer invalidate];
diff --git a/Source/CustomQuery.m b/Source/CustomQuery.m
index 57d47b7b..f359f9d1 100644
--- a/Source/CustomQuery.m
+++ b/Source/CustomQuery.m
@@ -43,6 +43,7 @@
#import "SPEncodingPopupAccessory.h"
#import "SPDataStorage.h"
#import "SPAlertSheets.h"
+#import "SPMainThreadTrampoline.h"
@implementation CustomQuery
@@ -506,14 +507,14 @@
// Reset the current table view as necessary to avoid redraw and reload issues.
// Restore the view position to the top left to be within the results for all datasets.
if(editedRow == -1) {
- [customQueryView scrollRowToVisible:0];
- [customQueryView scrollColumnToVisible:0];
+ [[customQueryView onMainThread] scrollRowToVisible:0];
+ [[customQueryView onMainThread] scrollColumnToVisible:0];
}
// Remove all the columns if not reloading the table
if(!reloadingExistingResult) {
if (cqColumnDefinition) [cqColumnDefinition release], cqColumnDefinition = nil;
- [self performSelectorOnMainThread:@selector(updateTableView) withObject:nil waitUntilDone:YES];
+ [[self onMainThread] updateTableView];
}
// Disable automatic query retries on failure for the custom queries
@@ -535,7 +536,7 @@
if (i > 0) {
NSString *taskString = [NSString stringWithFormat:NSLocalizedString(@"Running query %ld of %lu...", @"Running multiple queries string"), (long)(i+1), (unsigned long)queryCount];
[tableDocumentInstance setTaskDescription:taskString];
- [errorText setStringValue:taskString];
+ [[errorText onMainThread] setStringValue:taskString];
}
NSString *query = [NSArrayObjectAtIndex(queries, i) stringByTrimmingCharactersInSet:whitespaceAndNewlineSet];
@@ -561,7 +562,7 @@
cqColumnDefinition = [[streamingResult fetchResultFieldsStructure] retain];
if(!reloadingExistingResult) {
- [self performSelectorOnMainThread:@selector(updateTableView) withObject:nil waitUntilDone:YES];
+ [[self onMainThread] updateTableView];
}
[self processResultIntoDataStorage:streamingResult];
@@ -601,7 +602,7 @@
[errors appendString:[NSString stringWithFormat:NSLocalizedString(@"[ERROR in query %ld] %@\n", @"error text when multiple custom query failed"),
(long)(i+1),
errorString]];
- [errorText setStringValue:errors];
+ [[errorText onMainThread] setStringValue:errors];
// ask the user to continue after detecting an error
if (![mySQLConnection queryCancelled]) {
@@ -612,7 +613,7 @@
[alert setMessageText:NSLocalizedString(@"MySQL Error", @"mysql error message")];
[alert setInformativeText:[mySQLConnection getLastErrorMessage]];
[alert setAlertStyle:NSWarningAlertStyle];
- NSInteger choice = [alert runModal];
+ NSInteger choice = [[alert onMainThread] runModal];
switch (choice){
case NSAlertFirstButtonReturn:
suppressErrorSheet = YES;
@@ -687,24 +688,24 @@
// Set up the status string
if ( [mySQLConnection queryCancelled] ) {
if (totalQueriesRun > 1) {
- [affectedRowsText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Cancelled in query %ld, after %@", @"text showing multiple queries were cancelled"),
+ [[affectedRowsText onMainThread] setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Cancelled in query %ld, after %@", @"text showing multiple queries were cancelled"),
(long)totalQueriesRun,
[NSString stringForTimeInterval:executionTime]
]];
} else {
- [affectedRowsText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Cancelled after %@", @"text showing a query was cancelled"),
+ [[affectedRowsText onMainThread] setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Cancelled after %@", @"text showing a query was cancelled"),
[NSString stringForTimeInterval:executionTime]
]];
}
} else if ( totalQueriesRun > 1 ) {
if (totalAffectedRows==1) {
- [affectedRowsText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"1 row affected in total, by %ld queries taking %@", @"text showing one row has been affected by multiple queries"),
+ [[affectedRowsText onMainThread] setStringValue:[NSString stringWithFormat:NSLocalizedString(@"1 row affected in total, by %ld queries taking %@", @"text showing one row has been affected by multiple queries"),
(long)totalQueriesRun,
[NSString stringForTimeInterval:executionTime]
]];
} else {
- [affectedRowsText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%ld rows affected in total, by %ld queries taking %@", @"text showing how many rows have been affected by multiple queries"),
+ [[affectedRowsText onMainThread] setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%ld rows affected in total, by %ld queries taking %@", @"text showing how many rows have been affected by multiple queries"),
(long)totalAffectedRows,
(long)totalQueriesRun,
[NSString stringForTimeInterval:executionTime]
@@ -713,11 +714,11 @@
}
} else {
if (totalAffectedRows==1) {
- [affectedRowsText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"1 row affected, taking %@", @"text showing one row has been affected by a single query"),
+ [[affectedRowsText onMainThread] setStringValue:[NSString stringWithFormat:NSLocalizedString(@"1 row affected, taking %@", @"text showing one row has been affected by a single query"),
[NSString stringForTimeInterval:executionTime]
]];
} else {
- [affectedRowsText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%ld rows affected, taking %@", @"text showing how many rows have been affected by a single query"),
+ [[affectedRowsText onMainThread] setStringValue:[NSString stringWithFormat:NSLocalizedString(@"%ld rows affected, taking %@", @"text showing how many rows have been affected by a single query"),
(long)totalAffectedRows,
[NSString stringForTimeInterval:executionTime]
]];
diff --git a/Source/SPHistoryController.m b/Source/SPHistoryController.m
index 04d8a765..991c6e1e 100644
--- a/Source/SPHistoryController.m
+++ b/Source/SPHistoryController.m
@@ -27,6 +27,7 @@
#import "TablesList.h"
#import "SPHistoryController.h"
#import "SPStringAdditions.h"
+#import "SPMainThreadTrampoline.h"
@implementation SPHistoryController
@@ -263,7 +264,7 @@
if ([history count] > 50) [history removeObjectAtIndex:0];
historyPosition = [history count] - 1;
- [self updateToolbarItem];
+ [[self onMainThread] updateToolbarItem];
}
#pragma mark -
@@ -318,7 +319,7 @@
{
[tableContentInstance loadTable:[historyEntry objectForKey:@"table"]];
modifyingState = NO;
- [self updateToolbarItem];
+ [[self onMainThread] updateToolbarItem];
[theDocument endTask];
[loadPool drain];
return;
@@ -380,7 +381,7 @@
}
modifyingState = NO;
- [self updateToolbarItem];
+ [[self onMainThread] updateToolbarItem];
// End the task
[theDocument endTask];
diff --git a/Source/TableDocument.m b/Source/TableDocument.m
index 763a444b..4580e392 100644
--- a/Source/TableDocument.m
+++ b/Source/TableDocument.m
@@ -54,6 +54,7 @@
#import "SPProcessListController.h"
#import "SPServerVariablesController.h"
#import "SPAlertSheets.h"
+#import "SPMainThreadTrampoline.h"
@interface TableDocument (PrivateAPI)
@@ -905,7 +906,7 @@
[tablesListInstance setConnection:mySQLConnection];
[tableDumpInstance setConnection:mySQLConnection];
- [tableWindow setTitle:[self displaySPName]];
+ [[tableWindow onMainThread] setTitle:[self displaySPName]];
// Add a history entry
if (!historyStateChanging) {
@@ -916,9 +917,9 @@
// Set focus to table list filter field if visible
// otherwise set focus to Table List view
if ( [[tablesListInstance tables] count] > 20 )
- [tableWindow makeFirstResponder:listFilterField];
+ [[tableWindow onMainThread] makeFirstResponder:listFilterField];
else
- [tableWindow makeFirstResponder:[tablesListInstance valueForKeyPath:@"tablesListView"]];
+ [[tableWindow onMainThread] makeFirstResponder:[tablesListInstance valueForKeyPath:@"tablesListView"]];
[self endTask];
[taskPool drain];
diff --git a/Source/TableSource.h b/Source/TableSource.h
index 54a0c492..1d5cbcc0 100644
--- a/Source/TableSource.h
+++ b/Source/TableSource.h
@@ -72,6 +72,7 @@
// Table methods
- (void)loadTable:(NSString *)aTable;
- (IBAction)reloadTable:(id)sender;
+- (void) setTableDetails:(NSDictionary *)tableDetails;
// Edit methods
- (IBAction)addField:(id)sender;
diff --git a/Source/TableSource.m b/Source/TableSource.m
index 5f5b0119..fa0e190d 100644
--- a/Source/TableSource.m
+++ b/Source/TableSource.m
@@ -33,6 +33,7 @@
#import "SPArrayAdditions.h"
#import "SPConstants.h"
#import "SPAlertSheets.h"
+#import "SPMainThreadTrampoline.h"
@interface TableSource (PrivateAPI)
@@ -49,71 +50,36 @@ loads aTable, put it in an array, update the tableViewColumns and reload the tab
*/
- (void)loadTable:(NSString *)aTable
{
- NSEnumerator *enumerator;
- id field;
+ NSArray *theTableFields, *theTableIndexes;
+ NSMutableDictionary *theTableEnumLists = [NSMutableDictionary dictionary];
NSArray *extrasArray;
NSMutableDictionary *tempDefaultValues;
- NSEnumerator *extrasEnumerator;
- id extra;
NSInteger i;
SPSQLParser *fieldParser;
- BOOL enableInteraction = ![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableStructure] || ![tableDocumentInstance isWorking];
// Check whether a save of the current row is required.
- if ( ![self saveRowOnDeselect] ) return;
-
- if (selectedTable) [selectedTable release];
- if (aTable == nil) {
- selectedTable = nil;
- } else {
- selectedTable = [[NSString alloc] initWithString:aTable];
- }
- [tableSourceView deselectAll:self];
- [indexView deselectAll:self];
-
- if ( isEditingRow )
- return;
-
- // empty variables
- [enumFields removeAllObjects];
-
- if ( [aTable isEqualToString:@""] || !aTable ) {
- [tableFields removeAllObjects];
- [indexes removeAllObjects];
- [tableSourceView reloadData];
- [indexView reloadData];
- [addFieldButton setEnabled:NO];
- [copyFieldButton setEnabled:NO];
- [removeFieldButton setEnabled:NO];
- [addIndexButton setEnabled:NO];
- [removeIndexButton setEnabled:NO];
- [editTableButton setEnabled:NO];
+ if ( ![[self onMainThread] saveRowOnDeselect] ) return;
+ // If no table is selected, reset the interface and return
+ if (!aTable || ![aTable length]) {
+ [[self onMainThread] setTableDetails:nil];
return;
}
- // Enable edit table button
- [editTableButton setEnabled:enableInteraction];
-
- //query started
+ // Send the query started/working notification
[[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryWillBePerformed" object:tableDocumentInstance];
- //perform queries and load results in array (each row as a dictionary)
- tableSourceResult = [[mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM %@", [selectedTable backtickQuotedString]]] retain];
+ // Retrieve the column information for this table.
+ // TODO: update this and indexes to use TableData at some point - tiny bit more parsing required...
+ tableSourceResult = [[mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM %@", [aTable backtickQuotedString]]] retain];
+
+ // If an error occurred, reset the interface and abort
if (![[mySQLConnection getLastErrorMessage] isEqualToString:@""]) {
NSString *errorMessage = [NSString stringWithString:[mySQLConnection getLastErrorMessage]];
- [tableFields removeAllObjects];
- [indexes removeAllObjects];
- [tableSourceView reloadData];
- [tablesListInstance updateTables:self];
- [indexView reloadData];
- [addFieldButton setEnabled:NO];
- [copyFieldButton setEnabled:NO];
- [removeFieldButton setEnabled:NO];
- [addIndexButton setEnabled:NO];
- [removeIndexButton setEnabled:NO];
- [editTableButton setEnabled:NO];
+
[[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance];
+ [[self onMainThread] setTableDetails:nil];
+
SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"),
nil, nil, [NSApp mainWindow], self, nil, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving information.\nMySQL said: %@", @"message of panel when retrieving information failed"),
@@ -122,29 +88,20 @@ loads aTable, put it in an array, update the tableViewColumns and reload the tab
return;
}
- [tableSourceResult setReturnDataAsStrings:YES];
-
- // listFieldsFromTable is broken in the current version of the framework (no back-ticks for table name)!
- // tableSourceResult = [[mySQLConnection listFieldsFromTable:selectedTable] retain];
- // [tableFields setArray:[[self fetchResultAsArray:tableSourceResult] retain]];
- [tableFields setArray:[self fetchResultAsArray:tableSourceResult]];
+ // Process the field names into a local array of dictionaries
+ theTableFields = [self fetchResultAsArray:tableSourceResult];
[tableSourceResult release];
- indexResult = [[mySQLConnection queryString:[NSString stringWithFormat:@"SHOW INDEX FROM %@", [selectedTable backtickQuotedString]]] retain];
+ // Retrieve the indexes for the table
+ indexResult = [[mySQLConnection queryString:[NSString stringWithFormat:@"SHOW INDEX FROM %@", [aTable backtickQuotedString]]] retain];
+
+ // If an error occurred, reset the interface and abort
if (![[mySQLConnection getLastErrorMessage] isEqualToString:@""]) {
NSString *errorMessage = [NSString stringWithString:[mySQLConnection getLastErrorMessage]];
- [tableFields removeAllObjects];
- [indexes removeAllObjects];
- [tableSourceView reloadData];
- [tablesListInstance updateTables:self];
- [indexView reloadData];
- [addFieldButton setEnabled:NO];
- [copyFieldButton setEnabled:NO];
- [removeFieldButton setEnabled:NO];
- [addIndexButton setEnabled:NO];
- [removeIndexButton setEnabled:NO];
- [editTableButton setEnabled:NO];
+
[[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance];
+ [[self onMainThread] setTableDetails:nil];
+
SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"),
nil, nil, [NSApp mainWindow], self, nil, nil, nil,
[NSString stringWithFormat:NSLocalizedString(@"An error occurred while retrieving information.\nMySQL said: %@", @"message of panel when retrieving information failed"),
@@ -152,33 +109,19 @@ loads aTable, put it in an array, update the tableViewColumns and reload the tab
if (indexResult) [indexResult release];
return;
}
- [indexResult setReturnDataAsStrings:YES];
- // [indexes setArray:[[self fetchResultAsArray:indexResult] retain]];
- [indexes setArray:[self fetchResultAsArray:indexResult]];
+
+ // Process the indexes into a local array of dictionaries
+ theTableIndexes = [self fetchResultAsArray:indexResult];
[indexResult release];
-
- //get table default values
- if ( defaultValues ) {
- [defaultValues release];
- defaultValues = nil;
- }
-
- tempDefaultValues = [NSMutableDictionary dictionary];
- for ( i = 0 ; i < [tableFields count] ; i++ ) {
- [tempDefaultValues setObject:[[tableFields objectAtIndex:i] objectForKey:@"Default"] forKey:[[tableFields objectAtIndex:i] objectForKey:@"Field"]];
- }
- defaultValues = [[NSDictionary dictionaryWithDictionary:tempDefaultValues] retain];
-
- //put field length and extras in separate key
- enumerator = [tableFields objectEnumerator];
- while ( (field = [enumerator nextObject]) ) {
+ // Process all the fields to normalise keys and add additional information
+ for (id theField in theTableFields) {
NSString *type;
NSString *length;
NSString *extras;
// Set up the field parser with the type definition
- fieldParser = [[SPSQLParser alloc] initWithString:[field objectForKey:@"Type"]];
+ fieldParser = [[SPSQLParser alloc] initWithString:[theField objectForKey:@"Type"]];
// Pull out the field type; if no brackets are found, this returns nil - in which case simple values can be used.
type = [fieldParser trimAndReturnStringToCharacter:'(' trimmingInclusively:YES returningInclusively:NO];
@@ -207,7 +150,7 @@ loads aTable, put it in an array, update the tableViewColumns and reload the tab
[valueParser setString:[possibleValues objectAtIndex:i]];
[possibleValues replaceObjectAtIndex:i withObject:[valueParser unquotedString]];
}
- [enumFields setObject:[NSArray arrayWithArray:possibleValues] forKey:[field objectForKey:@"Field"]];
+ [theTableEnumLists setObject:[NSArray arrayWithArray:possibleValues] forKey:[theField objectForKey:@"Field"]];
[possibleValues release];
[valueParser release];
}
@@ -215,72 +158,40 @@ loads aTable, put it in an array, update the tableViewColumns and reload the tab
// For timestamps check to see whether "on update CURRENT_TIMESTAMP" - not returned
// by SHOW COLUMNS - should be set from the table data store
if ([type isEqualToString:@"timestamp"]
- && [[[tableDataInstance columnWithName:[field objectForKey:@"Field"]] objectForKey:@"onupdatetimestamp"] integerValue])
+ && [[[tableDataInstance columnWithName:[theField objectForKey:@"Field"]] objectForKey:@"onupdatetimestamp"] integerValue])
{
- [field setObject:@"on update CURRENT_TIMESTAMP" forKey:@"Extra"];
+ [theField setObject:@"on update CURRENT_TIMESTAMP" forKey:@"Extra"];
}
- // scan extras for values like unsigned, zerofill, binary
+ // Scan extras for values like unsigned, zerofill, binary
extrasArray = [extras componentsSeparatedByString:@" "];
- extrasEnumerator = [extrasArray objectEnumerator];
-
- while ( (extra = [extrasEnumerator nextObject]) ) {
- if ( [extra isEqualToString:@"unsigned"] ) {
- [field setObject:@"1" forKey:@"unsigned"];
- } else if ( [extra isEqualToString:@"zerofill"] ) {
- [field setObject:@"1" forKey:@"zerofill"];
- } else if ( [extra isEqualToString:@"binary"] ) {
- [field setObject:@"1" forKey:@"binary"];
+ for (id extra in extrasArray) {
+ if ([extra isEqualToString:@"unsigned"]) {
+ [theField setObject:@"1" forKey:@"unsigned"];
+ } else if ([extra isEqualToString:@"zerofill"]) {
+ [theField setObject:@"1" forKey:@"zerofill"];
+ } else if ([extra isEqualToString:@"binary"]) {
+ [theField setObject:@"1" forKey:@"binary"];
} else {
- if ( ![extra isEqualToString:@""] )
+ if (![extra isEqualToString:@""])
NSLog(@"ERROR: unknown option in field definition: %@", extra);
}
}
-
- [field setObject:type forKey:@"Type"];
- [field setObject:length forKey:@"Length"];
- }
-
- // If a view is selected, disable the buttons; otherwise enable.
- BOOL editingEnabled = ([tablesListInstance tableType] == SP_TABLETYPE_TABLE) && enableInteraction;
- [addFieldButton setEnabled:editingEnabled];
- [addIndexButton setEnabled:editingEnabled];
-
- //the following three buttons will only be enabled if a row field/index is selected!
- [copyFieldButton setEnabled:NO];
- [removeFieldButton setEnabled:NO];
- [removeIndexButton setEnabled:NO];
-
- //add columns to indexedColumnsField
- [indexedColumnsField removeAllItems];
- enumerator = [tableFields objectEnumerator];
-
- while ( (field = [enumerator nextObject]) ) {
- [indexedColumnsField addItemWithObjectValue:[field objectForKey:@"Field"]];
- }
-
- if ( [tableFields count] < 10 ) {
- [indexedColumnsField setNumberOfVisibleItems:[tableFields count]];
- } else {
- [indexedColumnsField setNumberOfVisibleItems:10];
+
+ [theField setObject:type forKey:@"Type"];
+ [theField setObject:length forKey:@"Length"];
}
-
- [indexView reloadData];
- [tableSourceView reloadData];
-
- // display and *then* tile to force scroll bars to be in the correct position
- [[tableSourceView enclosingScrollView] display];
- [[tableSourceView enclosingScrollView] tile];
-
- // Enable 'Duplicate field' if at least one field is specified
- // if no field is selected 'Duplicate field' will copy the last field
- // Enable 'Duplicate field' only for tables!
- if ([tablesListInstance tableType] == SP_TABLETYPE_TABLE)
- [copyFieldButton setEnabled:enableInteraction && ([tableSourceView numberOfRows] > 0)];
- else
- [copyFieldButton setEnabled:NO];
- //query finished
+ // Set up the table details for the new table, and request an data/interface update
+ NSDictionary *tableDetails = [NSDictionary dictionaryWithObjectsAndKeys:
+ aTable, @"name",
+ theTableFields, @"tableFields",
+ theTableIndexes, @"tableIndexes",
+ theTableEnumLists, @"enumLists",
+ nil];
+ [[self onMainThread] setTableDetails:tableDetails];
+
+ // Send the query finished/work complete notification
[[NSNotificationCenter defaultCenter] postNotificationName:@"SMySQLQueryHasBeenPerformed" object:tableDocumentInstance];
}
@@ -294,6 +205,75 @@ loads aTable, put it in an array, update the tableViewColumns and reload the tab
[self loadTable:selectedTable];
}
+/**
+ * Update stored table details and update the interface to match the supplied
+ * table details.
+ * Should be called on the main thread.
+ */
+- (void) setTableDetails:(NSDictionary *)tableDetails
+{
+ NSString *newTableName = [tableDetails objectForKey:@"name"];
+ NSMutableDictionary *newDefaultValues;
+ BOOL enableInteraction = ![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableStructure] || ![tableDocumentInstance isWorking];
+
+ // Update the selected table name
+ if (selectedTable) [selectedTable release], selectedTable = nil;
+ if (newTableName) selectedTable = [[NSString alloc] initWithString:newTableName];
+
+ // Reset the table store and display
+ [enumFields removeAllObjects];
+ [tableSourceView deselectAll:self];
+ [indexView deselectAll:self];
+ [tableFields removeAllObjects];
+ [indexes removeAllObjects];
+ [addFieldButton setEnabled:NO];
+ [copyFieldButton setEnabled:NO];
+ [removeFieldButton setEnabled:NO];
+ [addIndexButton setEnabled:NO];
+ [removeIndexButton setEnabled:NO];
+ [editTableButton setEnabled:NO];
+
+ // If no table is selected, refresh the table display to blank and return
+ if (!selectedTable) {
+ [tableSourceView reloadData];
+ [indexView reloadData];
+ return;
+ }
+
+ // Update the fields and indexes stores
+ [tableFields setArray:[tableDetails objectForKey:@"tableFields"]];
+ [indexes setArray:[tableDetails objectForKey:@"tableIndexes"]];
+
+ // Update the default values array and the indexed column fields control
+ [indexedColumnsField removeAllItems];
+ if (defaultValues) [defaultValues release], defaultValues = nil;
+ newDefaultValues = [NSMutableDictionary dictionaryWithCapacity:[tableFields count]];
+ for (id theField in tableFields) {
+ [newDefaultValues setObject:[theField objectForKey:@"Default"] forKey:[theField objectForKey:@"Field"]];
+ [indexedColumnsField addItemWithObjectValue:[theField objectForKey:@"Field"]];
+ }
+ defaultValues = [[NSDictionary dictionaryWithDictionary:newDefaultValues] retain];
+
+ // Only show up to ten items in the indexed column fields control
+ if ([tableFields count] < 10) {
+ [indexedColumnsField setNumberOfVisibleItems:[tableFields count]];
+ } else {
+ [indexedColumnsField setNumberOfVisibleItems:10];
+ }
+
+ // Enable the edit table button
+ [editTableButton setEnabled:enableInteraction];
+
+ // If a view is selected, disable the buttons; otherwise enable.
+ BOOL editingEnabled = ([tablesListInstance tableType] == SP_TABLETYPE_TABLE) && enableInteraction;
+ [addFieldButton setEnabled:editingEnabled];
+ [addIndexButton setEnabled:editingEnabled];
+
+ // Reload the views
+ [indexView reloadData];
+ [tableSourceView reloadData];
+}
+
#pragma mark -
#pragma mark Edit methods
@@ -615,36 +595,37 @@ closes the keySheet
}
}
-/*
-fetches the result as an array with a dictionary for each row in it
-*/
+/**
+ * Converts the supplied result to an array containing a (mutable) dictionary for each row
+ */
- (NSArray *)fetchResultAsArray:(MCPResult *)theResult
{
NSUInteger numOfRows = [theResult numOfRows];
NSMutableArray *tempResult = [NSMutableArray arrayWithCapacity:numOfRows];
NSMutableDictionary *tempRow;
NSArray *keys;
- id key;
NSInteger i;
- Class nullClass = [NSNull class];
id prefsNullValue = [prefs objectForKey:SPNullValue];
+ // Ensure table information is returned as strings to avoid problems with some server versions
+ [theResult setReturnDataAsStrings:YES];
+
if (numOfRows) [theResult dataSeek:0];
for ( i = 0 ; i < numOfRows ; i++ ) {
tempRow = [NSMutableDictionary dictionaryWithDictionary:[theResult fetchRowAsDictionary]];
- //use NULL string from preferences instead of the NSNull oject returned by the framework
+ // Replace NSNull instances with the NULL string from preferences
keys = [tempRow allKeys];
- for (NSInteger j = 0; j < [keys count] ; j++) {
- key = NSArrayObjectAtIndex(keys, j);
- if ( [[tempRow objectForKey:key] isMemberOfClass:nullClass] )
- [tempRow setObject:prefsNullValue forKey:key];
+ for (id theKey in keys) {
+ if ([[tempRow objectForKey:theKey] isNSNull])
+ [tempRow setObject:prefsNullValue forKey:theKey];
}
- // change some fields to be more human-readable or GUI compatible
- if ( [[tempRow objectForKey:@"Extra"] isEqualToString:@""] ) {
+
+ // Update some fields to be more human-readable or GUI compatible
+ if ([[tempRow objectForKey:@"Extra"] isEqualToString:@""]) {
[tempRow setObject:@"None" forKey:@"Extra"];
}
- if ( [[tempRow objectForKey:@"Null"] isEqualToString:@"YES"] ) {
+ if ([[tempRow objectForKey:@"Null"] isEqualToString:@"YES"]) {
[tempRow setObject:@"1" forKey:@"Null"];
} else {
[tempRow setObject:@"0" forKey:@"Null"];
@@ -1690,7 +1671,7 @@ would result in a position change.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Check whether a save of the current fields row is required.
- if (![self saveRowOnDeselect]) return;
+ if (![[self onMainThread] saveRowOnDeselect]) return;
if (![[indexedColumnsField stringValue] isEqualToString:@""]) {