diff options
-rw-r--r-- | Source/SPCustomQuery.h | 1 | ||||
-rw-r--r-- | Source/SPCustomQuery.m | 364 | ||||
-rw-r--r-- | Source/SPExportController.m | 1 |
3 files changed, 204 insertions, 162 deletions
diff --git a/Source/SPCustomQuery.h b/Source/SPCustomQuery.h index 5c4a4186..aa78a250 100644 --- a/Source/SPCustomQuery.h +++ b/Source/SPCustomQuery.h @@ -238,6 +238,7 @@ // Accessors - (NSArray *)currentResult; +- (NSArray *)currentDataResultWithNULLs:(BOOL)includeNULLs; - (void)processResultIntoDataStorage:(MCPStreamingResult *)theResult; // Retrieving and setting table state diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m index 3cadaba5..40f73f58 100644 --- a/Source/SPCustomQuery.m +++ b/Source/SPCustomQuery.m @@ -52,6 +52,13 @@ #import <BWToolkitFramework/BWToolkitFramework.h> #endif +@interface SPCustomQuery (PrivateAPI) + +- (id)_resultDataItemAtRow:(NSInteger)row columnIndex:(NSUInteger)column; +- (id)_convertResultDataValueToDisplayableRepresentation:(id)value whilePreservingNULLs:(BOOL)preserveNULLs; + +@end + @implementation SPCustomQuery #ifdef SP_REFACTOR @@ -62,7 +69,6 @@ @synthesize tablesListInstance; #endif - @synthesize textViewWasChanged; #pragma mark IBAction methods @@ -122,9 +128,8 @@ [self performQueries:queries withCallback:@selector(runAllQueriesCallback)]; } -- (void) runAllQueriesCallback +- (void)runAllQueriesCallback { - // If no error was selected, reconstruct a given selection. This // may no longer be valid if the query text has changed in the // meantime, so error-checking is required. @@ -323,7 +328,7 @@ } } -/* +/** * Closes the sheet */ - (IBAction)closeSheet:(id)sender @@ -332,7 +337,7 @@ [[sender window] orderOut:self]; } -/* +/** * Perform simple actions (which don't require their own method), triggered by selecting the appropriate menu item * in the "gear" action menu displayed beneath the cusotm query view. */ @@ -479,7 +484,6 @@ - (IBAction)copyQueryHistory:(id)sender { - NSPasteboard *pb = [NSPasteboard generalPasteboard]; [pb declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]; @@ -487,10 +491,11 @@ } -// "Clear History" menu item - clear query history +/** + * 'Clear History' menu item - clear query history + */ - (IBAction)clearQueryHistory:(id)sender { - NSString *infoString; #ifndef SP_REFACTOR /* if ([tableDocumentInstance isUntitled]) */ @@ -524,7 +529,7 @@ } -/* +/* * * Set font panel's valid modes */ - (NSUInteger)validModesForFontPanel:(NSFontPanel *)fontPanel @@ -545,18 +550,21 @@ #pragma mark - #pragma mark Query actions -/* +/** * Performs the mysql-query given by the user * sets the tableView columns corresponding to the mysql-result */ - (void)performQueries:(NSArray *)queries withCallback:(SEL)customQueryCallbackMethod; { NSString *taskString; + if ([queries count] > 1) { taskString = [NSString stringWithFormat:NSLocalizedString(@"Running query %i of %lu...", @"Running multiple queries string"), 1, (unsigned long)[queries count]]; - } else { + } + else { taskString = NSLocalizedString(@"Running query...", @"Running single query string"); } + [tableDocumentInstance startTaskWithDescription:taskString]; [errorText setString:taskString]; [affectedRowsText setStringValue:@""]; @@ -569,7 +577,8 @@ // If a helper thread is already running, execute inline - otherwise detach a new thread for the queries if ([NSThread isMainThread]) { [NSThread detachNewThreadSelector:@selector(performQueriesTask:) toTarget:self withObject:taskArguments]; - } else { + } + else { [self performQueriesTask:taskArguments]; } } @@ -923,10 +932,9 @@ [[tableDocumentInstance parentWindow] makeFirstResponder:customQueryView]; [queryRunningPool release]; - } -/* +/** * Processes a supplied streaming result set, loading it into the data array. */ - (void)processResultIntoDataStorage:(MCPStreamingResult *)theResult @@ -979,7 +987,7 @@ [dataLoadingPool drain]; } -/* +/** * Retrieve the range of the query at a position specified * within the custom query text view. */ @@ -1104,7 +1112,7 @@ return queryRange; } -/* +/** * Retrieve the range of the query for the passed index seen from a start position * specified within the custom query text view. */ @@ -1145,7 +1153,7 @@ return theQueryRange; } -/* +/** * Retrieve the query at a position specified within the custom query * text view. This will return nil if the position specified is beyond * the available string or if an empty query would be returned. @@ -1168,13 +1176,12 @@ [textView setSelectedRange:currentQueryRange]; } -/* +/** * Add or remove "⁄* *⁄" for each line in the current query * a given selection */ - (void)commentOutCurrentQueryTakingSelection:(BOOL)takeSelection { - BOOL isUncomment = NO; NSRange oldRange = [textView selectedRange]; @@ -1217,10 +1224,9 @@ // something like /*!400000 or similar if(!isUncomment) [textView setSelectedRange:NSMakeRange(workingRange.location+2,0)]; - } -/* +/** * Add or remove "-- " for each line in the current query or selection, * if the selection is in-line wrap selection into ⁄* block comments and * place the caret after ⁄* to allow to enter !xxxxxx e.g. @@ -1270,12 +1276,10 @@ // allow a fast (un)commenting of lines [textView setSelectedRange:lineRange]; [textView insertText:n]; - } - } -/* +/** * Update the interface to reflect the query error state. * Should be performed on the main thread. */ @@ -1376,6 +1380,7 @@ - (void) initQueryLoadTimer { if (queryLoadTimer) [self clearQueryLoadTimer]; + queryLoadInterfaceUpdateInterval = 1; queryLoadLastRowCount = 0; queryLoadTimerTicksSinceLastUpdate = 0; @@ -1436,56 +1441,71 @@ queryLoadInterfaceUpdateInterval = 25; break; } + queryLoadTimerTicksSinceLastUpdate = 0; } #pragma mark - #pragma mark Accessors -/* - * Returns the current result (as shown in custom result view) as array, - * the first object containing the field names as array, - * the following objects containing the rows as array +/** + * Returns the current result (as shown in custom result view) as an array, the first object containing + * the field names as an array and the following objects containing the rows as arrays. */ - (NSArray *)currentResult +{ + return [self currentDataResultWithNULLs:NO]; +} + +/** + * Returns the current result (as shown in custom result view) as an array, the first object containing + * the field names as an array and the following objects containing the rows as arrays. + * + * @param includeNULLs Indicates whether to include NULLs as a native type + * or use the user's NULL string representation preference. + */ +- (NSArray *)currentDataResultWithNULLs:(BOOL)includeNULLs { - NSArray *tableColumns = [customQueryView tableColumns]; - NSEnumerator *enumerator = [tableColumns objectEnumerator]; + NSInteger i; id tableColumn; - NSMutableArray *currentResult = [NSMutableArray array]; - NSMutableArray *tempRow = [NSMutableArray array]; - NSInteger i; - + NSMutableArray *tempRow = [[NSMutableArray alloc] init]; + // Set field names as first line - while ((tableColumn = [enumerator nextObject])) + for (tableColumn in [customQueryView tableColumns]) { [tempRow addObject:[[tableColumn headerCell] stringValue]]; } + NSMutableArray *currentResult = [NSMutableArray array]; + [currentResult addObject:[NSArray arrayWithArray:tempRow]]; - + // Add rows for (i = 0; i < [self numberOfRowsInTableView:customQueryView]; i++) { [tempRow removeAllObjects]; - enumerator = [tableColumns objectEnumerator]; + NSEnumerator *enumerator = [[customQueryView tableColumns] objectEnumerator]; while ((tableColumn = [enumerator nextObject])) { - [tempRow addObject:[self tableView:customQueryView objectValueForTableColumn:tableColumn row:i]]; + id value = [self _resultDataItemAtRow:i columnIndex:[[tableColumn identifier] integerValue]]; + + [tempRow addObject:[self _convertResultDataValueToDisplayableRepresentation:value whilePreservingNULLs:YES]]; } [currentResult addObject:[NSArray arrayWithArray:tempRow]]; } + [tempRow release]; + return currentResult; } #pragma mark - #pragma mark Additional methods -/* +/** * Sets the connection (received from SPDatabaseDocument) and makes things that have to be done only once */ - (void)setConnection:(MCPConnection *)theConnection @@ -1520,7 +1540,7 @@ [runSelectionMenuItem setEnabled:NO]; } -/* +/** * Inserts the query in the textView and performs query */ - (void)doPerformQueryService:(NSString *)query @@ -1531,6 +1551,7 @@ [textView scrollRangeToVisible:NSMakeRange([query length], 0)]; [self runAllQueries:self]; } + - (void)doPerformLoadQueryService:(NSString *)query { [textView shouldChangeTextInRange:NSMakeRange(0, [[textView string] length]) replacementString:query]; @@ -1623,7 +1644,7 @@ /** * Provide a getter for the custom query result table's selected rows index set */ -- (NSIndexSet *) resultSelectedRowIndexes +- (NSIndexSet *)resultSelectedRowIndexes { return [customQueryView selectedRowIndexes]; } @@ -1631,7 +1652,7 @@ /** * Provide a getter for the custom query result table's current viewport */ -- (NSRect) resultViewport +- (NSRect)resultViewport { return [customQueryView visibleRect]; } @@ -1647,7 +1668,7 @@ /** * Set the selected row indexes to restore on next custom query result table load */ -- (void) setResultSelectedRowIndexesToRestore:(NSIndexSet *)theIndexSet +- (void)setResultSelectedRowIndexesToRestore:(NSIndexSet *)theIndexSet { if (selectionIndexToRestore) [selectionIndexToRestore release], selectionIndexToRestore = nil; @@ -1657,7 +1678,7 @@ /** * Set the viewport to restore on next table load */ -- (void) setResultViewportToRestore:(NSRect)theViewport +- (void)setResultViewportToRestore:(NSRect)theViewport { selectionViewportToRestore = theViewport; } @@ -1665,7 +1686,7 @@ /** * Convenience method for storing all current settings for restoration */ -- (void) storeCurrentResultViewForRestoration +- (void)storeCurrentResultViewForRestoration { [self setResultSelectedRowIndexesToRestore:[self resultSelectedRowIndexes]]; [self setResultViewportToRestore:[self resultViewport]]; @@ -1674,7 +1695,7 @@ /** * Convenience method for clearing any settings to restore */ -- (void) clearResultViewDetailsToRestore +- (void)clearResultViewDetailsToRestore { [self setResultSelectedRowIndexesToRestore:nil]; [self setResultViewportToRestore:NSZeroRect]; @@ -1702,13 +1723,14 @@ NSUInteger targetWidth = [[columnWidths objectForKey:[columnDefinition objectForKey:@"datacolumnindex"]] integerValue]; [aTableColumn setWidth:targetWidth]; } + [customQueryView setDelegate:self]; } #pragma mark - #pragma mark Field Editing -/* +/** * Check if table cell is editable * Returns as array the minimum number of possible changes or * -1 if no table name can be found or multiple table origins @@ -1778,7 +1800,6 @@ [tableDocumentInstance endTask]; return [NSArray arrayWithObjects:[NSNumber numberWithInteger:-1], @"", nil]; } - } [tableDocumentInstance endTask]; @@ -1787,10 +1808,9 @@ fieldIDQueryStr = @""; return [NSArray arrayWithObjects:[NSNumber numberWithInteger:[[tempRow objectAtIndex:0] integerValue]], fieldIDQueryStr, nil]; - } -/* +/** * Collect all columns for a given 'tableForColumn' table and * return a WHERE clause for identifying the field in question. */ @@ -1979,12 +1999,7 @@ */ - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView { - if (aTableView == customQueryView) { - return (resultData == nil) ? 0 : resultDataCount; - } - else { - return 0; - } + return (aTableView == customQueryView) ? (resultData == nil) ? 0 : resultDataCount : 0; } /** @@ -1996,28 +2011,32 @@ // For NULL cell's display the user's NULL value placeholder in grey to easily distinguish it from other values if ([cell respondsToSelector:@selector(setTextColor:)]) { + + id value = nil; NSUInteger columnIndex = [[aTableColumn identifier] integerValue]; - id theValue = nil; // While the table is being loaded, additional validation is required - data // locks must be used to avoid crashes, and indexes higher than the available // rows or columns may be requested. Use gray to show loading in these cases. if (isWorking) { pthread_mutex_lock(&resultDataLock); + if (rowIndex < resultDataCount && columnIndex < [resultData columnCount]) { - theValue = SPDataStorageObjectAtRowAndColumn(resultData, rowIndex, columnIndex); + value = SPDataStorageObjectAtRowAndColumn(resultData, rowIndex, columnIndex); } + pthread_mutex_unlock(&resultDataLock); - if (!theValue) { + if (!value) { [cell setTextColor:[NSColor lightGrayColor]]; return; } - } else { - theValue = SPDataStorageObjectAtRowAndColumn(resultData, rowIndex, columnIndex); + } + else { + value = SPDataStorageObjectAtRowAndColumn(resultData, rowIndex, columnIndex); } - [cell setTextColor:[theValue isNSNull] ? [NSColor lightGrayColor] : [NSColor blackColor]]; + [cell setTextColor:[value isNSNull] ? [NSColor lightGrayColor] : [NSColor blackColor]]; } } } @@ -2025,42 +2044,14 @@ /** * Returns the object for the requested column and row index. */ -- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex +- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex { if (aTableView == customQueryView) { - NSUInteger columnIndex = [[aTableColumn identifier] integerValue]; - id theValue = nil; - - // While the table is being loaded, additional validation is required - data - // locks must be used to avoid crashes, and indexes higher than the available - // rows or columns may be requested. Return "..." to indicate loading in these - // cases. - if (isWorking) { - pthread_mutex_lock(&resultDataLock); - if (rowIndex < resultDataCount && columnIndex < [resultData columnCount]) { - theValue = [[SPDataStorageObjectAtRowAndColumn(resultData, rowIndex, columnIndex) copy] autorelease]; - } - pthread_mutex_unlock(&resultDataLock); - - if (!theValue) return @"..."; - } else { - theValue = SPDataStorageObjectAtRowAndColumn(resultData, rowIndex, columnIndex); - } - - if ([theValue isKindOfClass:[NSData class]]) - return [theValue shortStringRepresentationUsingEncoding:[mySQLConnection stringEncoding]]; - - if ([theValue isNSNull]) - return [prefs objectForKey:SPNullValue]; - - if ([theValue isKindOfClass:[MCPGeometryData class]]) - return [theValue wktString]; - - return theValue; - } - else { - return @""; + + return [self _convertResultDataValueToDisplayableRepresentation:[self _resultDataItemAtRow:rowIndex columnIndex:[[tableColumn identifier] integerValue]] whilePreservingNULLs:NO]; } + + return @""; } - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex @@ -2078,12 +2069,11 @@ } } -/* +/** * Change the sort order by clicking at a column header */ - (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)tableColumn { - // Prevent sorting while a query is running if ([tableDocumentInstance isWorking]) return; if (!cqColumnDefinition || ![cqColumnDefinition count]) return; @@ -2218,7 +2208,6 @@ } - #pragma mark - #pragma mark TableView Drag & Drop datasource methods @@ -2303,7 +2292,6 @@ */ - (NSString *)tableView:(NSTableView *)aTableView toolTipForCell:(SPTextAndLinkCell *)aCell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)row mouseLocation:(NSPoint)mouseLocation { - if([[aCell stringValue] length] < 2 || [tableDocumentInstance isWorking]) return nil; // Suppress tooltip if another toolip is already visible, mainly displayed by a Bundle command @@ -2371,12 +2359,11 @@ return nil; } -/* +/** * Double-click action on a field */ - (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { - // Only allow editing if a task is not active if ([tableDocumentInstance isWorking]) return NO; @@ -2451,11 +2438,11 @@ nil]]; return NO; - } + return YES; - - } else { + } + else { return YES; } } @@ -2610,37 +2597,42 @@ // Return the width, while the delegate is empty to prevent column resize notifications [customQueryView setDelegate:nil]; [customQueryView performSelector:@selector(setDelegate:) withObject:self afterDelay:0.1]; + return targetWidth; } #pragma mark - #pragma mark TextView delegate methods -/* +/** * Traps enter key and performs query instead of inserting a line break if aTextView == textView * closes valueSheet if aTextView == valueTextField */ - (BOOL)textView:(NSTextView *)aTextView doCommandBySelector:(SEL)aSelector { - if ( aTextView == textView ) { - if ( [aTextView methodForSelector:aSelector] == [aTextView methodForSelector:@selector(insertNewline:)] && - [[[NSApp currentEvent] characters] isEqualToString:@"\003"] ) - { + if (aTextView == textView) { + if ([aTextView methodForSelector:aSelector] == [aTextView methodForSelector:@selector(insertNewline:)] && + [[[NSApp currentEvent] characters] isEqualToString:@"\003"]) { [self runAllQueries:self]; + return YES; - } else { + } + else { return NO; } - } else if ( aTextView == valueTextField ) { - if ( [aTextView methodForSelector:aSelector] == [aTextView methodForSelector:@selector(insertNewline:)] ) - { + } + else if (aTextView == valueTextField) { + if ([aTextView methodForSelector:aSelector] == [aTextView methodForSelector:@selector(insertNewline:)]) { [self closeSheet:self]; + return YES; - } else { + } + else { return NO; } } + return NO; } @@ -2650,18 +2642,17 @@ - (NSRange)textView:(NSTextView *)aTextView willChangeSelectionFromCharacterRange:(NSRange)oldSelectedCharRange toCharacterRange:(NSRange)newSelectedCharRange { // Check if snippet session is still valid - if(!newSelectedCharRange.length && [textView isSnippetMode]) [textView checkForCaretInsideSnippet]; + if (!newSelectedCharRange.length && [textView isSnippetMode]) [textView checkForCaretInsideSnippet]; return newSelectedCharRange; } -/* +/** * A notification posted when the selection changes within the text view; * used to control the run-currentrun-selection button state and action. */ - (void)textViewDidChangeSelection:(NSNotification *)aNotification { - // Ensure that the notification is from the custom query text view if ( [aNotification object] != textView ) return; @@ -2747,7 +2738,6 @@ else if ([notification object] == queryHistorySearchField) { [self filterQueryHistory:nil]; } - } #ifndef SP_REFACTOR @@ -2762,7 +2752,7 @@ #ifndef SP_REFACTOR /* splitview delegate methods */ -/* +/** * Tells the splitView that it can collapse views */ - (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subview @@ -2770,21 +2760,23 @@ return YES; } -/* +/** * Defines max position of splitView */ - (CGFloat)splitView:(NSSplitView *)sender constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)offset { if (sender != queryInfoPaneSplitView) return (offset == 0) ? (proposedMax - 100) : (proposedMax - 73); + return proposedMax; } -/* +/** * Defines min position of splitView */ - (CGFloat)splitView:(NSSplitView *)sender constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)offset { if (sender != queryInfoPaneSplitView) return proposedMin + 100; + return proposedMin; } @@ -2801,18 +2793,17 @@ #pragma mark - #pragma mark MySQL Help -/* +/** * Set the MySQL version as X.Y for Help window title and online search */ - (void)setMySQLversion:(NSString *)theVersion { mySQLversion = [[theVersion substringToIndex:3] retain]; [textView setConnection:mySQLConnection withVersion:[[[mySQLversion componentsSeparatedByString:@"."] objectAtIndex:0] integerValue]]; - } #ifndef SP_REFACTOR -/* +/** * Return the Help window. */ - (NSWindow *)helpWebViewWindow @@ -2820,12 +2811,11 @@ return helpWebViewWindow; } -/* +/** * Show the data for "HELP 'searchString'". */ - (void)showHelpFor:(NSString *)searchString addToHistory:(BOOL)addToHistory calledByAutoHelp:(BOOL)autoHelp { - if(![searchString length]) return; NSString *helpString = [self getHTMLformattedMySQLHelpFor:searchString calledByAutoHelp:autoHelp]; @@ -2859,7 +2849,6 @@ // order out Help window if Help is available if(![helpString isEqualToString:SP_HELP_NOT_AVAILABLE]) [helpWebViewWindow orderFront:helpWebView]; - } // close Help window if no Help available @@ -2882,11 +2871,9 @@ // load HTML formatted help into the webview [[helpWebView mainFrame] loadHTMLString:helpString baseURL:nil]; - } - -/* +/** * Show the data for "HELP 'search word'" according to helpTarget */ - (IBAction)showHelpForSearchString:(id)sender @@ -2909,7 +2896,7 @@ } } -/* +/** * Show the Help for the selected text in the webview */ - (IBAction)showHelpForWebViewSelection:(id)sender @@ -2932,7 +2919,7 @@ } -/* +/** * Show the data for "HELP 'currentWord'" */ - (IBAction)showHelpForCurrentWord:(id)sender @@ -2941,7 +2928,7 @@ [self showHelpFor:searchString addToHistory:YES calledByAutoHelp:NO]; } -/* +/** * Find Next/Previous in current page */ - (IBAction)helpSearchFindNextInPage:(id)sender @@ -2950,6 +2937,7 @@ if(![helpWebView searchFor:[[helpSearchField stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] direction:YES caseSensitive:NO wrap:YES]) NSBeep(); } + - (IBAction)helpSearchFindPreviousInPage:(id)sender { if(helpTarget == SP_HELP_SEARCH_IN_PAGE) @@ -2957,7 +2945,7 @@ NSBeep(); } -/* +/** * Navigation for back/TOC/forward */ - (IBAction)helpSegmentDispatcher:(id)sender @@ -2974,13 +2962,14 @@ [helpWebView goForward]; break; } + // validate goback and goforward buttons according history [helpNavigator setEnabled:[[helpWebView backForwardList] backListCount] forSegment:SP_HELP_GOBACK_BUTTON]; [helpNavigator setEnabled:[[helpWebView backForwardList] forwardListCount] forSegment:SP_HELP_GOFORWARD_BUTTON]; } -/* +/** * Set helpTarget according user choice via mouse and keyboard short-cuts. */ - (IBAction)helpSelectHelpTargetMySQL:(id)sender @@ -2989,18 +2978,21 @@ [helpTargetSelector setSelectedSegment:SP_HELP_SEARCH_IN_MYSQL]; [self helpTargetValidation]; } + - (IBAction)helpSelectHelpTargetPage:(id)sender { helpTarget = SP_HELP_SEARCH_IN_PAGE; [helpTargetSelector setSelectedSegment:SP_HELP_SEARCH_IN_PAGE]; [self helpTargetValidation]; } + - (IBAction)helpSelectHelpTargetWeb:(id)sender { helpTarget = SP_HELP_SEARCH_IN_WEB; [helpTargetSelector setSelectedSegment:SP_HELP_SEARCH_IN_WEB]; [self helpTargetValidation]; } + - (IBAction)helpTargetDispatcher:(id)sender { helpTarget = [helpTargetSelector selectedSegment]; @@ -3025,7 +3017,7 @@ } #ifndef SP_REFACTOR -/* +/** * Show the data for "HELP 'currentWord' invoked by autohelp" */ - (void)showAutoHelpForCurrentWord:(id)sender @@ -3034,7 +3026,7 @@ [self showHelpFor:searchString addToHistory:YES calledByAutoHelp:YES]; } -/* +/** * Control the help search field behaviour. */ - (void)helpTargetValidation @@ -3068,7 +3060,7 @@ stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]]]; } -/* +/** * Return the help string HTML formatted from executing "HELP 'searchString'". * If more than one help topic was found return a link list. */ @@ -3202,14 +3194,12 @@ [tableDetails release]; return [NSString stringWithFormat:helpHTMLTemplate, theHelp]; - } -////////////////////////////// -// WebView delegate methods // -////////////////////////////// +#pragma mark - +#pragma mark WebView delegate methods -/* +/** * Link detector: If user clicked at an http link open it in the default browser, * otherwise search for it in the MySQL help. Additionally handle back/forward events from * keyboard and context menu. @@ -3246,7 +3236,7 @@ } } -/* +/** * Manage contextual menu in helpWebView * Ignore "Reload", "Open Link", "Open Link in new Window", "Download link" etc. */ @@ -3358,6 +3348,7 @@ for(id historyMenuItem in [[SPQueryController sharedQueryController] historyMenuItemsForFileURL:[tableDocumentInstance fileURL]]) [historyMenu addItem:historyMenuItem]; } + /** * Called by the query favorites manager whenever the query favorites have been updated. */ @@ -3506,7 +3497,7 @@ [[SPQueryController sharedQueryController] addHistory:entryString forFileURL:[tableDocumentInstance fileURL]]; } -/* +/** * This method is called as part of Key Value Observing which is used to watch for prefernce changes which effect the interface. */ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context @@ -3529,7 +3520,6 @@ */ - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo { - if ([contextInfo isEqualToString:@"runAllContinueStopSheet"]) { runAllContinueStopSheetReturnCode = returnCode; return; @@ -3792,14 +3782,13 @@ } } -/* +/** * If user selected a table cell which is a blob field and tried to edit it * cancel the fieldEditor, display the field editor sheet instead for editing * and re-enable the fieldEditor after editing. */ - (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)aFieldEditor { - if(![control isKindOfClass:[SPCopyTable class]]) return YES; NSUInteger row, column; @@ -3869,7 +3858,6 @@ [aFieldEditor setTextColor:[NSColor blackColor]]; return shouldBeginEditing; - } /** @@ -3878,7 +3866,6 @@ */ - (BOOL)control:(NSControl*)control textView:(NSTextView*)aTextView doCommandBySelector:(SEL)command { - if(control == queryHistorySearchField || control == queryFavoritesSearchField) { if(command == @selector(moveDown:) || command == @selector(moveUp:)) { [queryHistorySearchField abortEditing]; @@ -3914,22 +3901,10 @@ return TRUE; } - - } return NO; } -// - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item -// { -// // Set the focus at the search field -// // TODO : but no way out; always selecting first/last menu item -// // because after setting focus to search field NSMenu selectedItemIndex is -1 -// if(item == queryHistorySearchMenuItem) { -// [queryHistorySearchField selectText:nil]; -// } -// -// } /** * Setup various interface controls. @@ -3977,6 +3952,71 @@ } } +#pragma mark - +#pragma mark Private API + +/** + * Retrieves the value from the underlying data storage at the supplied row and column indices. + * + * @param row The row index + * @param column The column index + * + * @return The value from the data storage + */ +- (id)_resultDataItemAtRow:(NSInteger)row columnIndex:(NSUInteger)column +{ + id value = nil; + + // While the table is being loaded, additional validation is required - data + // locks must be used to avoid crashes, and indexes higher than the available + // rows or columns may be requested. Return "..." to indicate loading in these + // cases. + if (isWorking) { + pthread_mutex_lock(&resultDataLock); + + if (row < resultDataCount && column < [resultData columnCount]) { + value = [[SPDataStorageObjectAtRowAndColumn(resultData, row, column) copy] autorelease]; + } + + pthread_mutex_unlock(&resultDataLock); + + if (!value) value = @"..."; + } + else { + value = SPDataStorageObjectAtRowAndColumn(resultData, row, column); + } + + return value; +} + +/** + * Converts the supplied value into it's displayable representation. + * + * @param value The value to convert + * @param preserveNULLs Whether or not NULLs should be preserved or converted to the + * user's NULL placeholder preference. + * + * @return The converted value + */ +- (id)_convertResultDataValueToDisplayableRepresentation:(id)value whilePreservingNULLs:(BOOL)preserveNULLs +{ + if ([value isKindOfClass:[NSData class]]) { + value = [value shortStringRepresentationUsingEncoding:[mySQLConnection stringEncoding]]; + } + + if ([value isNSNull] && !preserveNULLs) { + value = [prefs objectForKey:SPNullValue]; + } + + if ([value isKindOfClass:[MCPGeometryData class]]) { + value = [value wktString]; + } + + return value; +} + +#pragma mark - + /** * Dealloc. */ diff --git a/Source/SPExportController.m b/Source/SPExportController.m index c7a60f39..5b61d178 100644 --- a/Source/SPExportController.m +++ b/Source/SPExportController.m @@ -796,6 +796,7 @@ static const NSString *SPSQLExportDropEnabled = @"SQLExportDropEnabled"; if (isDot && serverLowerCaseTableNameValue == NSNotFound) { MCPResult *caseResult = [connection queryString:@"SHOW VARIABLES LIKE 'lower_case_table_names'"]; + [caseResult setReturnDataAsStrings:YES]; if ([caseResult numOfRows] == 1) { |