From 1ef653b918ddd53d6e54d4e1923b217f8b555080 Mon Sep 17 00:00:00 2001 From: Bibiko Date: Tue, 16 Nov 2010 19:22:17 +0000 Subject: =?UTF-8?q?=E2=80=A2=20Bundle=20Support=20-=20improved=20Data=20Ta?= =?UTF-8?q?ble=20input=20commands=20SelectedTableRowsAsTab/Csv/SqlInsert,?= =?UTF-8?q?=20TableRowsAsTab/Csv/SqlInsert=20=E2=80=A2=20fixed=20issue=20f?= =?UTF-8?q?or=20Copy=20with=20Column=20Names:=20removed=20=3F\020last=20ap?= =?UTF-8?q?pended=20tab=20in=20header=20line?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/SPCopyTable.h | 23 +++++-- Source/SPCopyTable.m | 170 +++++++++++++++++++++++++++++++++++++++++------- Source/SPTableContent.m | 2 +- 3 files changed, 165 insertions(+), 30 deletions(-) diff --git a/Source/SPCopyTable.h b/Source/SPCopyTable.h index 22e6f15c..d46caf02 100644 --- a/Source/SPCopyTable.h +++ b/Source/SPCopyTable.h @@ -82,21 +82,32 @@ - (NSUInteger)draggingSourceOperationMaskForLocal:(BOOL)isLocal; /*! - @method selectedRowsAsTabStringWithHeaders - @abstract getter of the selected rows of the table for copy - @discussion For the selected rows returns a single string with each row + @method rowsAsTabStringWithHeaders:onlySelectedRows: + @abstract getter of the selected rows or all of the table for copy + @discussion For the selected rows or all returns a single string with each row separated by a newline and then for each column value separated by a tab. Values are from the objects description method, so make sure it returns something meaningful. @result The above described string, or nil if nothing selected */ -- (NSString *)selectedRowsAsTabStringWithHeaders:(BOOL)withHeaders; +- (NSString *)rowsAsTabStringWithHeaders:(BOOL)withHeaders onlySelectedRows:(BOOL)onlySelected; + +/*! + @method rowsAsCsvStringWithHeaders:onlySelectedRows: + @abstract getter of the selected rows or all of the table csv formatted + @discussion For the selected rows or all returns a single string with each row + separated by a newline and then for each column value separated by a + , wherby each cell will be wrapped into quotes. Values are from the objects description method, so make sure it + returns something meaningful. + @result The above described string, or nil if nothing selected +*/ +- (NSString *)rowsAsCsvStringWithHeaders:(BOOL)withHeaders onlySelectedRows:(BOOL)onlySelected; /* * Generate a string in form of INSERT INTO VALUES () of - * currently selected rows. Support blob data as well. + * currently selected rows or all. Support blob data as well. */ -- (NSString *)selectedRowsAsSqlInserts; +- (NSString *)rowsAsSqlInsertsOnlySelectedRows:(BOOL)onlySelected; /* * Set all necessary data from the table content view. diff --git a/Source/SPCopyTable.m b/Source/SPCopyTable.m index 5574ff33..c54e0cee 100644 --- a/Source/SPCopyTable.m +++ b/Source/SPCopyTable.m @@ -81,7 +81,7 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; NSString *tmp = nil; if([sender tag] == MENU_EDIT_COPY_AS_SQL) { - tmp = [self selectedRowsAsSqlInserts]; + tmp = [self rowsAsSqlInsertsOnlySelectedRows:YES]; if ( nil != tmp ) { NSPasteboard *pb = [NSPasteboard generalPasteboard]; @@ -92,7 +92,7 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; [pb setString:tmp forType:NSStringPboardType]; } } else { - tmp = [self selectedRowsAsTabStringWithHeaders:([sender tag] == MENU_EDIT_COPY_WITH_COLUMN)]; + tmp = [self rowsAsTabStringWithHeaders:([sender tag] == MENU_EDIT_COPY_WITH_COLUMN) onlySelectedRows:YES]; if ( nil != tmp ) { NSPasteboard *pb = [NSPasteboard generalPasteboard]; @@ -113,11 +113,15 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; * Get selected rows a string of newline separated lines of tab separated fields * the value in each field is from the objects description method */ -- (NSString *) selectedRowsAsTabStringWithHeaders:(BOOL)withHeaders +- (NSString *) rowsAsTabStringWithHeaders:(BOOL)withHeaders onlySelectedRows:(BOOL)onlySelected { - if ([self numberOfSelectedRows] == 0) return nil; + if (onlySelected && [self numberOfSelectedRows] == 0) return nil; - NSIndexSet *selectedRows = [self selectedRowIndexes]; + NSIndexSet *selectedRows; + if(onlySelected) + selectedRows = [self selectedRowIndexes]; + else + selectedRows = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [tableStorage count])]; NSArray *columns = [self tableColumns]; NSUInteger numColumns = [columns count]; @@ -127,7 +131,9 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; if (withHeaders) { NSUInteger i; for( i = 0; i < numColumns; i++ ){ - [result appendFormat:@"%@\t", [[NSArrayObjectAtIndex(columns, i) headerCell] stringValue]]; + if([result length]) + [result appendString:@"\t"]; + [result appendString:[[NSArrayObjectAtIndex(columns, i) headerCell] stringValue]]; } [result appendString:@"\n"]; } @@ -196,19 +202,117 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; return result; } +/** + * Get selected rows a string of newline separated lines of , separated fields wrapped into quotes + * the value in each field is from the objects description method + */ +- (NSString *) rowsAsCsvStringWithHeaders:(BOOL)withHeaders onlySelectedRows:(BOOL)onlySelected +{ + if (onlySelected && [self numberOfSelectedRows] == 0) return nil; + + NSIndexSet *selectedRows; + if(onlySelected) + selectedRows = [self selectedRowIndexes]; + else + selectedRows = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [tableStorage count])]; + + NSArray *columns = [self tableColumns]; + NSUInteger numColumns = [columns count]; + NSMutableString *result = [NSMutableString stringWithCapacity:2000]; + + // Add the table headers if requested to do so + if (withHeaders) { + NSUInteger i; + for( i = 0; i < numColumns; i++ ){ + if([result length]) + [result appendString:@","]; + [result appendFormat:@"\"%@\"", [[[NSArrayObjectAtIndex(columns, i) headerCell] stringValue] stringByReplacingOccurrencesOfString:@"\"" withString:@"\"\""]]; + } + [result appendString:@"\n"]; + } + + NSUInteger c; + id cellData = nil; + + // Create an array of table column mappings for fast iteration + NSUInteger *columnMappings = malloc(numColumns * sizeof(NSUInteger)); + for ( c = 0; c < numColumns; c++ ) + columnMappings[c] = [[NSArrayObjectAtIndex(columns, c) identifier] unsignedIntValue]; + + // Loop through the rows, adding their descriptive contents + NSUInteger rowIndex = [selectedRows firstIndex]; + NSString *nullString = [prefs objectForKey:SPNullValue]; + NSStringEncoding connectionEncoding = [mySQLConnection encoding]; + Class mcpGeometryData = [MCPGeometryData class]; + + while ( rowIndex != NSNotFound ) + { + for ( c = 0; c < numColumns; c++ ) { + cellData = SPDataStorageObjectAtRowAndColumn(tableStorage, rowIndex, columnMappings[c]); + + // Copy the shown representation of the cell - custom NULL display strings, (not loaded), + // and the string representation of any blobs or binary texts. + if (cellData) { + if ([cellData isNSNull]) + [result appendFormat:@"\"%@\",", nullString]; + else if ([cellData isSPNotLoaded]) + [result appendFormat:@"\"%@\",", NSLocalizedString(@"(not loaded)", @"value shown for hidden blob and text fields")]; + else if ([cellData isKindOfClass:[NSData class]]) { + NSString *displayString = [[NSString alloc] initWithData:cellData encoding:[mySQLConnection stringEncoding]]; + if (!displayString) displayString = [[NSString alloc] initWithData:cellData encoding:NSASCIIStringEncoding]; + if (displayString) { + [result appendFormat:@"\"%@\",", [displayString stringByReplacingOccurrencesOfString:@"\"" withString:@"\"\""]]; + [displayString release]; + } + } + else if ([cellData isKindOfClass:mcpGeometryData]) { + [result appendFormat:@"\"%@\",", [cellData wktString]]; + } + else + [result appendFormat:@"\"%@\",", [[cellData description] stringByReplacingOccurrencesOfString:@"\"" withString:@"\"\""]]; + } else { + [result appendString:@","]; + } + } + + // Remove the trailing tab and add the linebreak + if ([result length]){ + [result deleteCharactersInRange:NSMakeRange([result length]-1, 1)]; + } + [result appendString:@"\n"]; + + // Select the next row index + rowIndex = [selectedRows indexGreaterThanIndex:rowIndex]; + } + + // Remove the trailing line end + if ([result length]) { + [result deleteCharactersInRange:NSMakeRange([result length]-1, 1)]; + } + + free(columnMappings); + + return result; +} + /* * Return selected rows as SQL INSERT INTO `foo` VALUES (baz) string. * If no selected table name is given `
` will be used instead. */ -- (NSString *) selectedRowsAsSqlInserts +- (NSString *) rowsAsSqlInsertsOnlySelectedRows:(BOOL)onlySelected { - if ( [self numberOfSelectedRows] < 1 ) return nil; + if (onlySelected && [self numberOfSelectedRows] == 0) return nil; + + NSIndexSet *selectedRows; + if(onlySelected) + selectedRows = [self selectedRowIndexes]; + else + selectedRows = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [tableStorage count])]; NSArray *columns = [self tableColumns]; NSUInteger numColumns = [columns count]; - NSIndexSet *selectedRows = [self selectedRowIndexes]; NSMutableString *value = [NSMutableString stringWithCapacity:10]; id cellData = nil; @@ -751,20 +855,40 @@ NSInteger MENU_EDIT_COPY_AS_SQL = 2003; if([[self delegate] respondsToSelector:@selector(usedQuery)] && [[self delegate] usedQuery]) [env setObject:[[self delegate] usedQuery] forKey:@"SP_USED_QUERY_FOR_TABLE"]; - // NSError *inputFileError = nil; - // NSString *input = [NSString stringWithString:[[self string] substringWithRange:replaceRange]]; - // [input writeToFile:SPBundleTaskInputFilePath - // atomically:YES - // encoding:NSUTF8StringEncoding - // error:&inputFileError]; - // - // if(inputFileError != nil) { - // NSString *errorMessage = [inputFileError localizedDescription]; - // SPBeginAlertSheet(NSLocalizedString(@"Bundle Error", @"bundle error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [self window], self, nil, nil, - // [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage]); - // if (cmdData) [cmdData release]; - // return; - // } + NSError *inputFileError = nil; + NSString *input = @""; + if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsTab]) { + input = [self rowsAsTabStringWithHeaders:YES onlySelectedRows:YES]; + } + else if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsCsv]) { + input = [self rowsAsCsvStringWithHeaders:YES onlySelectedRows:YES]; + } + else if([inputAction isEqualToString:SPBundleInputSourceSelectedTableRowsAsSqlInsert]) { + input = [self selectedRowsAsSqlInsertsOnlySelectedRows:YES]; + } + else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsTab]) { + input = [self rowsAsTabStringWithHeaders:YES onlySelectedRows:NO]; + } + else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsCsv]) { + input = [self rowsAsCsvStringWithHeaders:YES onlySelectedRows:NO]; + } + else if([inputAction isEqualToString:SPBundleInputSourceTableRowsAsSqlInsert]) { + input = [self rowsAsSqlInsertsOnlySelectedRows:NO]; + } + + if(input == nil) input = @""; + [input writeToFile:SPBundleTaskInputFilePath + atomically:YES + encoding:NSUTF8StringEncoding + error:&inputFileError]; + + if(inputFileError != nil) { + NSString *errorMessage = [inputFileError localizedDescription]; + SPBeginAlertSheet(NSLocalizedString(@"Bundle Error", @"bundle error"), NSLocalizedString(@"OK", @"OK button"), nil, nil, [self window], self, nil, nil, + [NSString stringWithFormat:@"%@ “%@”:\n%@", NSLocalizedString(@"Error for", @"error for message"), [cmdData objectForKey:@"name"], errorMessage]); + if (cmdData) [cmdData release]; + return; + } NSString *output = [cmd runBashCommandWithEnvironment:env atCurrentDirectoryPath:nil error:&err]; diff --git a/Source/SPTableContent.m b/Source/SPTableContent.m index fc879e6c..a1fe54c5 100644 --- a/Source/SPTableContent.m +++ b/Source/SPTableContent.m @@ -3997,7 +3997,7 @@ // By holding ⌘, ⇧, or/and ⌥ copies selected rows as SQL INSERTS // otherwise \t delimited lines if([[NSApp currentEvent] modifierFlags] & (NSCommandKeyMask|NSShiftKeyMask|NSAlternateKeyMask)) - tmp = [tableContentView selectedRowsAsSqlInserts]; + tmp = [tableContentView rowsAsSqlInsertsOnlySelectedRows:YES]; else tmp = [tableContentView draggedRowsAsTabString]; -- cgit v1.2.3