From 22ae0fa8c302d22071116abca27d2add3a0af991 Mon Sep 17 00:00:00 2001 From: Bibiko Date: Tue, 16 Feb 2010 11:23:45 +0000 Subject: =?UTF-8?q?=E2=80=A2=20re-factored=20and=20outsourced=20the=20enti?= =?UTF-8?q?re=20CSV=20import=20field=20mapper=20sheet=20-=20changed=20the?= =?UTF-8?q?=20way=20to=20choose=20whether=20a=20source=20field=20should=20?= =?UTF-8?q?be=20imported=20or=20not=20by=20introducing=20a=20new=20table?= =?UTF-8?q?=20column=20'operators'=20-=20clicking=20at=20the=20'operator's?= =?UTF-8?q?=20header=20toggles=20all=20operators=20to=20'Import'=20or=20'D?= =?UTF-8?q?o=20not=20import'=20-=20added=20tooltips=20for=20each=20table?= =?UTF-8?q?=20cell;=20if=20file's=20first=20line=20are=20the=20headers=20s?= =?UTF-8?q?how=20them=20in=20the=20tooltips=20as=20well=20-=20added=20chec?= =?UTF-8?q?kbox=20"First=20line=20contains=20fields=20names"=20since=20it'?= =?UTF-8?q?ll=20be=20clear=20in=20this=20pane=20whether=20a=20file=20has?= =?UTF-8?q?=20a=20header=20line=20or=20not=20(will=20be=20sync=20with=20pr?= =?UTF-8?q?efs)=20-=20added=20the=20possibility=20to=20choose=20the=20impo?= =?UTF-8?q?rt=20method:=20INSERT=20INTO=20or=20REPLACE=20INTO=20=E2=80=A2?= =?UTF-8?q?=20deleted=20all=20old=20field=20mapper=20stuff=20from=20TableD?= =?UTF-8?q?ump=20and=20DBView.xib?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Notes: - tests are needed to be sure that this change does not cause mismatches while importing - symbols for Do (not) import are tendative - maybe use images - a further import method UPDATE plus an operator '=' will be added soon - chance to add a new global source variable will come soon - displaying of source field types will come soon - semi-automatically matching of source field names and header names will come soon - the GUI needs some improvements afterwards --- Source/SPFieldMapperController.h | 36 ++++- Source/SPFieldMapperController.m | 285 ++++++++++++++++++++++++++++++++++----- Source/TableDump.h | 116 ++++++++-------- Source/TableDump.m | 220 ++++++------------------------ 4 files changed, 376 insertions(+), 281 deletions(-) (limited to 'Source') diff --git a/Source/SPFieldMapperController.h b/Source/SPFieldMapperController.h index d48585e0..19cf316a 100644 --- a/Source/SPFieldMapperController.h +++ b/Source/SPFieldMapperController.h @@ -1,7 +1,7 @@ // // $Id$ // -// SPQueryFavoriteManager.h +// SPFieldMapperController.h // sequel-pro // // Created by Hans-Jörg Bibiko on February 01, 2010 @@ -25,8 +25,6 @@ #import #import - - @interface SPFieldMapperController : NSWindowController { IBOutlet id fieldMapperTableView; @@ -36,19 +34,33 @@ IBOutlet id rowUpButton; IBOutlet id rowDownButton; IBOutlet id recordCountLabel; + IBOutlet id importFieldNamesHeaderSwitch; id theDelegate; + id fieldMappingImportArray; NSInteger fieldMappingCurrentRow; - NSArray *fieldMappingImportArray; - NSArray *fieldMappingArray; + NSMutableArray *fieldMappingArray; NSMutableArray *fieldMappingTableColumnNames; + NSMutableArray *fieldMappingButtonOptions; + NSMutableArray *fieldMappingOperatorOptions; + NSMutableArray *fieldMappingOperatorArray; + + NSNumber *doImport; + NSNumber *doNotImport; + NSNumber *isEqual; + NSString *doImportString; + NSString *doNotImportString; + NSString *isEqualString; BOOL fieldMappingImportArrayIsPreview; + BOOL importFieldNamesHeader; MCPConnection *mySQLConnection; NSString *sourcePath; + + NSUserDefaults *prefs; } @property(retain) NSString* sourcePath; @@ -56,6 +68,15 @@ - (id)initWithDelegate:(id)managerDelegate; - (void)setConnection:(MCPConnection *)theConnection; +- (void)setImportDataArray:(id)theFieldMappingImportArray hasHeader:(BOOL)hasHeader; + +// Getter methods +- (NSString*)selectedTableTarget; +- (NSArray*)fieldMapperOperator; +- (NSString*)selectedImportMethod; +- (NSArray*)fieldMappingArray; +- (NSArray*)fieldMappingTableColumnNames; +- (BOOL)importFieldNamesHeader; // IBAction methods - (IBAction)changeTableTarget:(id)sender; @@ -63,4 +84,9 @@ - (IBAction)stepRow:(id)sender; - (IBAction)closeSheet:(id)sender; +// Others +- (void)setupFieldMappingArray; +- (void)updateFieldMappingButtonCell; +- (void)updateFieldMappingOperatorOptions; + @end diff --git a/Source/SPFieldMapperController.m b/Source/SPFieldMapperController.m index 3ed30270..8dc06d87 100644 --- a/Source/SPFieldMapperController.m +++ b/Source/SPFieldMapperController.m @@ -1,7 +1,7 @@ // // $Id$ // -// SPQueryFavoriteManager.m +// SPFieldMapperController.m // sequel-pro // // Created by Hans-Jörg Bibiko on February 01, 2010 @@ -26,6 +26,8 @@ #import "SPFieldMapperController.h" #import "SPTableData.h" #import "TablesList.h" +#import "SPArrayAdditions.h" +#import "SPConstants.h" @implementation SPFieldMapperController @@ -34,7 +36,6 @@ #pragma mark - #pragma mark Initialization - /** * Initialize the field mapper */ @@ -49,7 +50,20 @@ return nil; } theDelegate = managerDelegate; - fieldMappingTableColumnNames = [[NSMutableArray alloc] initWithCapacity:1]; + fieldMappingTableColumnNames = [[NSMutableArray alloc] init]; + fieldMappingButtonOptions = [[NSMutableArray alloc] init]; + fieldMappingOperatorOptions = [[NSMutableArray alloc] init]; + fieldMappingOperatorArray = [[NSMutableArray alloc] init]; + fieldMappingArray = nil; + + doImport = [NSNumber numberWithInteger:0]; + doNotImport = [NSNumber numberWithInteger:1]; + isEqual = [NSNumber numberWithInteger:2]; + doImportString = @"→"; + doNotImportString = @"×"; + isEqualString = @"="; + + prefs = [NSUserDefaults standardUserDefaults]; } return self; @@ -57,27 +71,31 @@ - (void)awakeFromNib { + + // Set source path [fileSourcePath setURL:[NSURL URLWithString:sourcePath]]; + + // Init table target popup menu [tableTargetPopup removeAllItems]; - [tableTargetPopup addItemsWithTitles:[[theDelegate valueForKeyPath:@"tablesListInstance"] allTableNames]]; + if([[theDelegate valueForKeyPath:@"tablesListInstance"] allTableNames]) { + [tableTargetPopup addItemsWithTitles:[[theDelegate valueForKeyPath:@"tablesListInstance"] allTableNames]]; + + // Select either the currently selected table, or the first item in the list + if ([[theDelegate valueForKeyPath:@"tableDocumentInstance"] table] != nil && ![[[theDelegate valueForKeyPath:@"tablesListInstance"] tableName] isEqualToString:@""]) { + [tableTargetPopup selectItemWithTitle:[[theDelegate valueForKeyPath:@"tablesListInstance"] tableName]]; + } else { + [tableTargetPopup selectItemAtIndex:0]; + } - // Select either the currently selected table, or the first item in the list - if ([[theDelegate valueForKeyPath:@"tableDocumentInstance"] table] != nil && ![[[theDelegate valueForKeyPath:@"tablesListInstance"] tableName] isEqualToString:@""]) { - [tableTargetPopup selectItemWithTitle:[[theDelegate valueForKeyPath:@"tablesListInstance"] tableName]]; - } else { - [tableTargetPopup selectItemAtIndex:0]; } + [importFieldNamesHeaderSwitch setState:importFieldNamesHeader]; + [self changeTableTarget:self]; -} -/* - * Set the connection for use. - * Called by the connect sheet methods. - */ -- (void)setConnection:(MCPConnection *)theConnection -{ - mySQLConnection = theConnection; - [mySQLConnection retain]; + [[self window] makeFirstResponder:fieldMapperTableView]; + if([fieldMappingTableColumnNames count]) + [fieldMapperTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; + } - (void)dealloc @@ -85,9 +103,61 @@ if (mySQLConnection) [mySQLConnection release]; if (sourcePath) [sourcePath release]; if (fieldMappingTableColumnNames) [fieldMappingTableColumnNames release]; + if (fieldMappingArray) [fieldMappingArray release]; + if (fieldMappingButtonOptions) [fieldMappingButtonOptions release]; + if (fieldMappingOperatorOptions) [fieldMappingOperatorOptions release]; + if (fieldMappingOperatorArray) [fieldMappingOperatorArray release]; [super dealloc]; } +#pragma mark - +#pragma mark Setter methods + +- (void)setConnection:(MCPConnection *)theConnection +{ + mySQLConnection = theConnection; + [mySQLConnection retain]; +} + +- (void)setImportDataArray:(id)theFieldMappingImportArray hasHeader:(BOOL)hasHeader +{ + fieldMappingImportArray = theFieldMappingImportArray; + importFieldNamesHeader = hasHeader; +} + +#pragma mark - +#pragma mark Getter methods + +- (NSString*)selectedTableTarget +{ + return [tableTargetPopup titleOfSelectedItem]; +} + +- (NSArray*)fieldMapperOperator +{ + return [NSArray arrayWithArray:fieldMappingOperatorArray]; +} + +- (NSString*)selectedImportMethod +{ + return [importMethodPopup titleOfSelectedItem]; +} + +- (NSArray*)fieldMappingArray +{ + return fieldMappingArray; +} + +- (NSArray*)fieldMappingTableColumnNames +{ + return fieldMappingTableColumnNames; +} + +- (BOOL)importFieldNamesHeader +{ + return importFieldNamesHeader; +} + #pragma mark - #pragma mark IBAction methods @@ -98,7 +168,9 @@ - (IBAction)changeTableTarget:(id)sender { - + + NSInteger i; + // Remove all the current columns [fieldMappingTableColumnNames removeAllObjects]; @@ -111,24 +183,49 @@ [fieldMappingTableColumnNames addObject:[NSString stringWithString:[column objectForKey:@"name"]]]; } } - NSLog(@"f %@", [fieldMappingTableColumnNames description]); + [selectedTableData release]; // Update the table view fieldMappingCurrentRow = 0; if (fieldMappingArray) [fieldMappingArray release], fieldMappingArray = nil; - // [self setupFieldMappingArray]; + [self setupFieldMappingArray]; [rowDownButton setEnabled:NO]; [rowUpButton setEnabled:([fieldMappingImportArray count] > 1)]; [recordCountLabel setStringValue:[NSString stringWithFormat:@"%ld of %@%lu records", (long)(fieldMappingCurrentRow+1), fieldMappingImportArrayIsPreview?@"first ":@"", (unsigned long)[fieldMappingImportArray count]]]; - // [self updateFieldMappingButtonCell]; + [self updateFieldMappingButtonCell]; + [self updateFieldMappingOperatorOptions]; + + // Set all operators to doNotImport + [fieldMappingOperatorArray removeAllObjects]; + for(i=0; i < [fieldMappingTableColumnNames count]; i++) + [fieldMappingOperatorArray addObject:doNotImport]; + + // Set the first n operators to doImport + if([fieldMappingImportArray count]) { + NSInteger possibleImports = ([NSArrayObjectAtIndex(fieldMappingImportArray, 0) count] > [fieldMappingTableColumnNames count]) ? [fieldMappingTableColumnNames count] : [NSArrayObjectAtIndex(fieldMappingImportArray, 0) count]; + for(i=0; i < possibleImports; i++) + [fieldMappingOperatorArray replaceObjectAtIndex:i withObject:doImport]; + } + [fieldMapperTableView reloadData]; + } - (IBAction)changeImportMethod:(id)sender { - + NSInteger i; + // If operator is set to = for UPDATE method replace it by doNotImport + if(![[importMethodPopup titleOfSelectedItem] isEqualToString:@"UPDATE"]) { + for(i=0; i<[fieldMappingTableColumnNames count]; i++) { + if([fieldMappingOperatorArray objectAtIndex:i] == isEqual) + [fieldMappingOperatorArray replaceObjectAtIndex:i withObject:doNotImport]; + } + } + + [self updateFieldMappingOperatorOptions]; + [fieldMapperTableView reloadData]; } /* @@ -141,7 +238,7 @@ } else { fieldMappingCurrentRow++; } - // [self updateFieldMappingButtonCell]; + [self updateFieldMappingButtonCell]; [fieldMapperTableView reloadData]; @@ -152,6 +249,61 @@ [rowUpButton setEnabled:(fieldMappingCurrentRow != ([fieldMappingImportArray count]-1))]; } +/* + * Sets up the fieldMapping array to be shown in the tableView + */ +- (void)setupFieldMappingArray +{ + NSInteger i, value; + + if (!fieldMappingArray) { + fieldMappingArray = [[NSMutableArray alloc] init]; + + for (i = 0; i < [fieldMappingTableColumnNames count]; i++) { + if (i < [NSArrayObjectAtIndex(fieldMappingImportArray, fieldMappingCurrentRow) count] + && ![NSArrayObjectAtIndex(NSArrayObjectAtIndex(fieldMappingImportArray, fieldMappingCurrentRow), i) isKindOfClass:[NSNull class]]) { + value = i; + } else { + value = 0; + } + + [fieldMappingArray addObject:[NSNumber numberWithInteger:value]]; + } + } + + [fieldMapperTableView reloadData]; +} + +/* + * Update the NSButtonCell items for use in the import_value mapping display + */ +- (void)updateFieldMappingButtonCell +{ + NSInteger i; + + [fieldMappingButtonOptions setArray:[fieldMappingImportArray objectAtIndex:fieldMappingCurrentRow]]; + for (i = 0; i < [fieldMappingButtonOptions count]; i++) { + if ([[fieldMappingButtonOptions objectAtIndex:i] isNSNull]) { + [fieldMappingButtonOptions replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%i. %@", i+1, [prefs objectForKey:SPNullValue]]]; + } else { + [fieldMappingButtonOptions replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%i. %@", i+1, NSArrayObjectAtIndex(fieldMappingButtonOptions, i)]]; + } + } +} + +/* + * Update the NSButtonCell items for use in the operator mapping display + */ +- (void)updateFieldMappingOperatorOptions +{ + if(![[importMethodPopup titleOfSelectedItem] isEqualToString:@"UPDATE"]) { + [fieldMappingOperatorOptions setArray:[NSArray arrayWithObjects:doImportString, doNotImportString, nil]]; + } else { + [fieldMappingOperatorOptions setArray:[NSArray arrayWithObjects:doImportString, doNotImportString, isEqualString, nil]]; + } +} + + #pragma mark - #pragma mark Table view datasource methods @@ -162,30 +314,93 @@ - (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { + [aCell setFont:([prefs boolForKey:SPUseMonospacedFonts]) ? [NSFont fontWithName:SPDefaultMonospacedFontName size:[NSFont smallSystemFontSize]] : [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; +} + +- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)aTableColumn +{ + + // A click at the operator column's header toggles all operators + if ([[aTableColumn identifier] isEqualToString:@"operator"] + && [self numberOfRowsInTableView:tableView] + && [fieldMappingOperatorArray count] + && [fieldMappingTableColumnNames count]) { + NSInteger i; + NSNumber *globalValue = doImport; + if([fieldMappingOperatorArray objectAtIndex:0] == doImport) + globalValue = doNotImport; + [fieldMappingOperatorArray removeAllObjects]; + for(i=0; i < [fieldMappingTableColumnNames count]; i++) + [fieldMappingOperatorArray addObject:globalValue]; + [fieldMapperTableView reloadData]; + } } +- (NSString *)tableView:(NSTableView *)aTableView toolTipForCell:(NSCell *)aCell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex mouseLocation:(NSPoint)mouseLocation +{ + if([[aTableColumn identifier] isEqualToString:@"import_value"] && [importFieldNamesHeaderSwitch state] == NSOnState) + if(fieldMappingCurrentRow) + return [NSString stringWithFormat:@"%@: %@", + [NSArrayObjectAtIndex(NSArrayObjectAtIndex(fieldMappingImportArray, 0), [NSArrayObjectAtIndex(fieldMappingArray, rowIndex) integerValue]) description], + [NSArrayObjectAtIndex(NSArrayObjectAtIndex(fieldMappingImportArray, fieldMappingCurrentRow), [NSArrayObjectAtIndex(fieldMappingArray, rowIndex) integerValue]) description]]; + else + return [NSArrayObjectAtIndex(NSArrayObjectAtIndex(fieldMappingImportArray, 0), [NSArrayObjectAtIndex(fieldMappingArray, rowIndex) integerValue]) description]; + else if([[aTableColumn identifier] isEqualToString:@"import_value"] && [importFieldNamesHeaderSwitch state] == NSOffState) + return [NSArrayObjectAtIndex(NSArrayObjectAtIndex(fieldMappingImportArray, fieldMappingCurrentRow), [NSArrayObjectAtIndex(fieldMappingArray, rowIndex) integerValue]) description]; + else if([[aTableColumn identifier] isEqualToString:@"operator"]) { + if([aCell objectValue] == doImport) + return NSLocalizedString(@"Do import", @"import operator"); + else if([aCell objectValue] == doNotImport) + return NSLocalizedString(@"Do not import", @"do not import operator"); + else if([aCell objectValue] == isEqual) + return NSLocalizedString(@"Do UPDATE where field contents match", @"do update operator"); + else + return @""; + } + else if([[aTableColumn identifier] isEqualToString:@"target_field"]) + return [fieldMappingTableColumnNames objectAtIndex:rowIndex]; + + + return @""; +} + - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { if ([[aTableColumn identifier] isEqualToString:@"target_field"]) { + if ([[aTableColumn dataCell] isKindOfClass:[NSPopUpButtonCell class]]) { + [(NSPopUpButton *)[aTableColumn dataCell] removeAllItems]; + [(NSPopUpButtonCell *)[aTableColumn dataCell] addItemWithTitle:[fieldMappingTableColumnNames objectAtIndex:rowIndex]]; + } return [fieldMappingTableColumnNames objectAtIndex:rowIndex]; - } - // else if ([[aTableColumn identifier] isEqualToString:@"value"]) { - // if ([[[aTableColumn dataCell] class] isEqualTo:[NSPopUpButtonCell class]]) { - // [(NSPopUpButtonCell *)[aTableColumn dataCell] removeAllItems]; - // [(NSPopUpButtonCell *)[aTableColumn dataCell] addItemWithTitle:NSLocalizedString(@"Do not import", @"text for csv import drop downs")]; - // [(NSPopUpButtonCell *)[aTableColumn dataCell] addItemsWithTitles:fieldMappingButtonOptions]; - // } - // - // returnObject = [fieldMappingArray objectAtIndex:rowIndex]; - // } + else if ([[aTableColumn identifier] isEqualToString:@"import_value"]) { + if ([[aTableColumn dataCell] isKindOfClass:[NSPopUpButtonCell class]]) { + [(NSPopUpButtonCell *)[aTableColumn dataCell] removeAllItems]; + [(NSPopUpButtonCell *)[aTableColumn dataCell] addItemsWithTitles:fieldMappingButtonOptions]; + } + + return [fieldMappingArray objectAtIndex:rowIndex]; + } + else if ([[aTableColumn identifier] isEqualToString:@"operator"]) { + if ([[aTableColumn dataCell] isKindOfClass:[NSPopUpButtonCell class]]) { + [(NSPopUpButtonCell *)[aTableColumn dataCell] removeAllItems]; + [(NSPopUpButtonCell *)[aTableColumn dataCell] addItemsWithTitles:fieldMappingOperatorOptions]; + } + + return [fieldMappingOperatorArray objectAtIndex:rowIndex]; + } return nil; } - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { + if ([[aTableColumn identifier] isEqualToString:@"import_value"]) { + [fieldMappingArray replaceObjectAtIndex:rowIndex withObject:anObject]; + } + else if ([[aTableColumn identifier] isEqualToString:@"operator"]) { + [fieldMappingOperatorArray replaceObjectAtIndex:rowIndex withObject:anObject]; + } } - @end diff --git a/Source/TableDump.h b/Source/TableDump.h index 644057b6..001b1778 100644 --- a/Source/TableDump.h +++ b/Source/TableDump.h @@ -44,87 +44,82 @@ typedef enum _SPExportModes { IBOutlet id tableDataInstance; IBOutlet id customQueryInstance; - IBOutlet id tableWindow; - - IBOutlet id exportDumpView; - IBOutlet id exportCSVView; - IBOutlet id exportMultipleCSVView; - IBOutlet id exportMultipleXMLView; - IBOutlet id exportDumpTableView; - IBOutlet id exportMultipleCSVTableView; - IBOutlet id exportMultipleXMLTableView; - IBOutlet id exportFieldNamesSwitch; - IBOutlet id exportFieldsTerminatedField; - IBOutlet id exportFieldsEnclosedField; - IBOutlet id exportFieldsEscapedField; - IBOutlet id exportLinesTerminatedField; - IBOutlet id exportMultipleFieldNamesSwitch; - IBOutlet id exportMultipleFieldsTerminatedField; - IBOutlet id exportMultipleFieldsEnclosedField; - IBOutlet id exportMultipleFieldsEscapedField; - IBOutlet id exportMultipleLinesTerminatedField; - + IBOutlet id tableWindow; + + IBOutlet id exportDumpView; + IBOutlet id exportCSVView; + IBOutlet id exportMultipleCSVView; + IBOutlet id exportMultipleXMLView; + IBOutlet id exportDumpTableView; + IBOutlet id exportMultipleCSVTableView; + IBOutlet id exportMultipleXMLTableView; + IBOutlet id exportFieldNamesSwitch; + IBOutlet id exportFieldsTerminatedField; + IBOutlet id exportFieldsEnclosedField; + IBOutlet id exportFieldsEscapedField; + IBOutlet id exportLinesTerminatedField; + IBOutlet id exportMultipleFieldNamesSwitch; + IBOutlet id exportMultipleFieldsTerminatedField; + IBOutlet id exportMultipleFieldsEnclosedField; + IBOutlet id exportMultipleFieldsEscapedField; + IBOutlet id exportMultipleLinesTerminatedField; + // New Export Window IBOutlet id exportWindow; IBOutlet id exportTabBar; IBOutlet id exportToolbar; IBOutlet id exportTableList; - + IBOutlet id importCSVView; IBOutlet NSPopUpButton *importFormatPopup; IBOutlet id importCSVBox; - IBOutlet id importFieldNamesSwitch; - IBOutlet id importFieldsTerminatedField; - IBOutlet id importFieldsEnclosedField; - IBOutlet id importFieldsEscapedField; - IBOutlet id importLinesTerminatedField; - - IBOutlet id addDropTableSwitch; - IBOutlet id addCreateTableSwitch; - IBOutlet id addTableContentSwitch; - IBOutlet id addErrorsSwitch; - IBOutlet id sqlFullStreamingSwitch; - IBOutlet id csvFullStreamingSwitch; - IBOutlet id multiCSVFullStreamingSwitch; - IBOutlet id multiXMLFullStreamingSwitch; - IBOutlet id errorsSheet; - IBOutlet id errorsView; - IBOutlet id singleProgressSheet; - IBOutlet id singleProgressBar; - IBOutlet id singleProgressTitle; - IBOutlet id singleProgressText; - - IBOutlet id fieldMappingSheet; - IBOutlet id fieldMappingPopup; - IBOutlet id fieldMappingTableView; - - IBOutlet id rowUpButton; - IBOutlet id rowDownButton; - IBOutlet id recordCountLabel; + IBOutlet id importFieldNamesSwitch; + IBOutlet id importFieldsTerminatedField; + IBOutlet id importFieldsEnclosedField; + IBOutlet id importFieldsEscapedField; + IBOutlet id importLinesTerminatedField; + IBOutlet id importFieldMapperSheetWindow; + + IBOutlet id addDropTableSwitch; + IBOutlet id addCreateTableSwitch; + IBOutlet id addTableContentSwitch; + IBOutlet id addErrorsSwitch; + IBOutlet id sqlFullStreamingSwitch; + IBOutlet id csvFullStreamingSwitch; + IBOutlet id multiCSVFullStreamingSwitch; + IBOutlet id multiXMLFullStreamingSwitch; + IBOutlet id errorsSheet; + IBOutlet id errorsView; + IBOutlet id singleProgressSheet; + IBOutlet id singleProgressBar; + IBOutlet id singleProgressTitle; + IBOutlet id singleProgressText; MCPConnection *mySQLConnection; NSMutableArray *tables; + + // Field Mapper Controller + SPFieldMapperController *fieldMapperController; NSArray *fieldMappingImportArray; BOOL fieldMappingImportArrayIsPreview; - NSMutableArray *fieldMappingTableColumnNames; - NSMutableArray *fieldMappingArray; - NSMutableArray *fieldMappingButtonOptions; - NSInteger fieldMappingCurrentRow; + NSArray *fieldMappingTableColumnNames; + NSArray *fieldMappingArray; + NSArray *fieldMapperOperator; + NSString *selectedTableTarget; + NSString *selectedImportMethod; + NSInteger fieldMapperSheetStatus; + NSUInteger exportMode; NSUserDefaults *prefs; BOOL progressCancelled; - - NSInteger fieldMapperSheetStatus; - SPFieldMapperController *fieldMapperController; + } // IBAction methods - (IBAction)reloadTables:(id)sender; - (IBAction)selectTables:(id)sender; - (IBAction)closeSheet:(id)sender; -- (IBAction)closeFieldMapperSheet:(id)sender; -- (IBAction)stepRow:(id)sender; - (IBAction)cancelProgressBar:(id)sender; // Export methods @@ -139,11 +134,8 @@ typedef enum _SPExportModes { - (void)startSQLImportProcessWithFile:(NSString *)filename; - (void)importCSVFile:(NSString *)filename; - (IBAction)changeFormat:(id)sender; -- (IBAction)changeTable:(id)sender; - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo; -- (BOOL) buildFieldMappingArrayWithData:(NSArray *)importData isPreview:(BOOL)dataIsPreviewData; -- (void)setupFieldMappingArray; -- (void)updateFieldMappingButtonCell; +- (BOOL) buildFieldMappingArrayWithData:(NSArray *)importData isPreview:(BOOL)dataIsPreviewData ofSoureFile:(NSString*)filename; - (NSString *) mappedValueStringForRowArray:(NSArray *)csvRowArray; // Export methods diff --git a/Source/TableDump.m b/Source/TableDump.m index 2e055f94..33118738 100644 --- a/Source/TableDump.m +++ b/Source/TableDump.m @@ -108,11 +108,6 @@ [exportMultipleXMLTableView reloadData]; } -- (IBAction)closeFieldMapperSheet:(id)sender -{ - [NSApp endSheet:fieldMappingSheet returnCode:[sender tag]]; -} - /** * Common method for ending modal sessions */ @@ -513,39 +508,6 @@ [importCSVBox setHidden:![[[importFormatPopup selectedItem] title] isEqualToString:@"CSV"]]; } -/** - * When the table in the CSV field mapping sheet is changed, retrieve - * the columns from the new table and reset the field mapping array. - */ -- (IBAction)changeTable:(id)sender -{ - - // Remove all the current columns - [fieldMappingTableColumnNames removeAllObjects]; - - // Retrieve the information for the newly selected table using a SPTableData instance - SPTableData *selectedTableData = [[SPTableData alloc] init]; - [selectedTableData setConnection:mySQLConnection]; - NSDictionary *tableDetails = [selectedTableData informationForTable:[fieldMappingPopup titleOfSelectedItem]]; - if (tableDetails) { - for (NSDictionary *column in [tableDetails objectForKey:@"columns"]) { - [fieldMappingTableColumnNames addObject:[NSString stringWithString:[column objectForKey:@"name"]]]; - } - } - [selectedTableData release]; - - // Update the table view - fieldMappingCurrentRow = 0; - if (fieldMappingArray) [fieldMappingArray release], fieldMappingArray = nil; - [self setupFieldMappingArray]; - [rowDownButton setEnabled:NO]; - [rowUpButton setEnabled:([fieldMappingImportArray count] > 1)]; - [recordCountLabel setStringValue:[NSString stringWithFormat:@"%ld of %@%lu records", (long)(fieldMappingCurrentRow+1), fieldMappingImportArrayIsPreview?@"first ":@"", (unsigned long)[fieldMappingImportArray count]]]; - - [self updateFieldMappingButtonCell]; - [fieldMappingTableView reloadData]; -} - - (void)importBackgroundProcess:(NSString*)filename { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; @@ -822,7 +784,7 @@ BOOL allDataRead = NO; BOOL insertBaseStringHasEntries; NSStringEncoding csvEncoding = [MCPConnection encodingForMySQLEncoding:[[tableDocumentInstance connectionEncoding] UTF8String]]; - if (fieldMappingArray) [fieldMappingArray release], fieldMappingArray = nil; + fieldMappingArray = nil; // Start the notification timer to allow notifications to be shown even if frontmost for long queries [[SPGrowlController sharedGrowlController] setVisibilityForNotificationName:@"Import Finished"]; @@ -975,7 +937,7 @@ && ([parsedRows count] >= 100 || (!csvRowArray && allDataRead))) { [self closeAndStopProgressSheet]; - if (![self buildFieldMappingArrayWithData:parsedRows isPreview:!allDataRead]) { + if (![self buildFieldMappingArrayWithData:parsedRows isPreview:!allDataRead ofSoureFile:filename]) { [csvParser release]; [csvDataBuffer release]; [parsedRows release]; @@ -992,13 +954,13 @@ [NSApp beginSheet:singleProgressSheet modalForWindow:tableWindow modalDelegate:self didEndSelector:nil contextInfo:nil]; [singleProgressSheet makeKeyWindow]; - // Set up the field names import string - [insertBaseString appendString:@"INSERT INTO "]; - [insertBaseString appendString:[[fieldMappingPopup titleOfSelectedItem] backtickQuotedString]]; + // Set up the field names import string for INSERT or REPLACE INTO + [insertBaseString appendFormat:@"%@ INTO ", selectedImportMethod]; + [insertBaseString appendString:[selectedTableTarget backtickQuotedString]]; [insertBaseString appendString:@" ("]; insertBaseStringHasEntries = NO; for (i = 0; i < [fieldMappingArray count]; i++) { - if ([NSArrayObjectAtIndex(fieldMappingArray, i) integerValue] > 0) { + if ([NSArrayObjectAtIndex(fieldMapperOperator, i) integerValue] == 0) { if (insertBaseStringHasEntries) [insertBaseString appendString:@","]; else insertBaseStringHasEntries = YES; [insertBaseString appendString:[NSArrayObjectAtIndex(fieldMappingTableColumnNames, i) backtickQuotedString]]; @@ -1079,7 +1041,7 @@ [csvDataBuffer release]; [parsedRows release]; [parsePositions release]; - if (fieldMappingArray) [fieldMappingArray release], fieldMappingArray = nil; + fieldMappingArray = nil; [importPool drain]; [tableDocumentInstance setQueryMode:SPInterfaceQueryMode]; @@ -1103,7 +1065,7 @@ // If the table selected for import is also selected in the content view, // update the content view - on the main thread to avoid crashes. - if ([tablesListInstance tableName] && [[fieldMappingPopup titleOfSelectedItem] isEqualToString:[tablesListInstance tableName]]) { + if ([tablesListInstance tableName] && [selectedTableTarget isEqualToString:[tablesListInstance tableName]]) { if ([[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableContent]) { [tableContentInstance performSelectorOnMainThread:@selector(reloadTable:) withObject:nil waitUntilDone:YES]; } else { @@ -1142,7 +1104,7 @@ * Takes an array of data to show when selecting the field mapping, and an indicator of whether * that dataset is complete or a preview of the full data set. */ -- (BOOL) buildFieldMappingArrayWithData:(NSArray *)importData isPreview:(BOOL)dataIsPreviewData +- (BOOL) buildFieldMappingArrayWithData:(NSArray *)importData isPreview:(BOOL)dataIsPreviewData ofSoureFile:(NSString*)filename { // Ensure data was provided, or alert than an import error occurred and return false. @@ -1172,12 +1134,8 @@ } fieldMappingImportArrayIsPreview = dataIsPreviewData; - // Get the list of tables (not views) to display in the field mapping interface - [fieldMappingPopup removeAllItems]; - [fieldMappingPopup addItemsWithTitles:[tablesListInstance allTableNames]]; - // If there's no tables to select, error - if (![[fieldMappingPopup itemArray] count]) { + if (![[tablesListInstance allTableNames] count]) { [self closeAndStopProgressSheet]; SPBeginAlertSheet(NSLocalizedString(@"Error", @"error"), NSLocalizedString(@"OK", @"OK button"), @@ -1189,46 +1147,41 @@ return FALSE; } - // Set up tableView buttons - NSPopUpButtonCell *buttonCell = [[NSPopUpButtonCell alloc] init]; - [buttonCell setControlSize:NSSmallControlSize]; - [buttonCell setFont:[NSFont labelFontOfSize:[NSFont smallSystemFontSize]]]; - [buttonCell setBordered:NO]; - [[fieldMappingTableView tableColumnWithIdentifier:@"value"] setDataCell:buttonCell]; - [buttonCell release]; - - // Select either the currently selected table, or the first item in the list - if ([tableDocumentInstance table] != nil && ![[tablesListInstance tableName] isEqualToString:@""]) { - [fieldMappingPopup selectItemWithTitle:[tablesListInstance tableName]]; - } else { - [fieldMappingPopup selectItemAtIndex:0]; - } - // Set the import array if (fieldMappingImportArray) [fieldMappingImportArray release]; fieldMappingImportArray = [[NSArray alloc] initWithArray:importData]; - - // Trigger a table selection and setup - [self changeTable:self]; fieldMapperSheetStatus = 1; - // if(fieldMapperController) [fieldMapperController release]; - // fieldMapperController = [[SPFieldMapperController alloc] initWithDelegate:self]; + // Init the field mapper controller + fieldMapperController = [[SPFieldMapperController alloc] initWithDelegate:self]; + [fieldMapperController setConnection:mySQLConnection]; + [fieldMapperController setSourcePath:filename]; + [fieldMapperController setImportDataArray:fieldMappingImportArray hasHeader:[importFieldNamesSwitch state]]; - // Show fieldMapping sheet - // [NSApp beginSheet:[fieldMapperController window] - [NSApp beginSheet:fieldMappingSheet + // Show field mapper sheet and set the focus to it + [NSApp beginSheet:[fieldMapperController window] modalForWindow:tableWindow modalDelegate:self didEndSelector:@selector(fieldMapperDidEndSheet:returnCode:contextInfo:) contextInfo:nil]; - // Wait for fieldMappingSheet + [[fieldMapperController window] makeKeyWindow]; + + // Wait for field mapper sheet while (fieldMapperSheetStatus == 1) usleep(100000); - // if(fieldMapperController) [fieldMapperController release]; + // Get mapping settings + fieldMapperOperator = [NSArray arrayWithArray:[fieldMapperController fieldMapperOperator]]; + fieldMappingArray = [NSArray arrayWithArray:[fieldMapperController fieldMappingArray]]; + selectedTableTarget = [NSString stringWithString:[fieldMapperController selectedTableTarget]]; + selectedImportMethod = [NSString stringWithString:[fieldMapperController selectedImportMethod]]; + fieldMappingTableColumnNames = [NSArray arrayWithArray:[fieldMapperController fieldMappingTableColumnNames]]; + [importFieldNamesSwitch setState:[fieldMapperController importFieldNamesHeader]]; + [prefs setBool:[importFieldNamesSwitch state] forKey:SPCSVImportFirstLineIsHeader]; + + if(fieldMapperController) [fieldMapperController release]; if(fieldMapperSheetStatus == 2) return YES; @@ -1242,69 +1195,6 @@ fieldMapperSheetStatus = (returnCode) ? 2 : 3; } -/* - * Sets up the fieldMapping array to be shown in the tableView - */ -- (void)setupFieldMappingArray -{ - NSInteger i, value; - - if (!fieldMappingArray) { - fieldMappingArray = [[NSMutableArray alloc] init]; - - for (i = 0; i < [fieldMappingTableColumnNames count]; i++) { - if (i < [NSArrayObjectAtIndex(fieldMappingImportArray, fieldMappingCurrentRow) count] && ![NSArrayObjectAtIndex(NSArrayObjectAtIndex(fieldMappingImportArray, fieldMappingCurrentRow), i) isKindOfClass:[NSNull class]]) { - value = i + 1; - } else { - value = 0; - } - - [fieldMappingArray addObject:[NSNumber numberWithInteger:value]]; - } - } - - [fieldMappingTableView reloadData]; -} - -/* - * Update the NSButtonCell items for use in the field mapping display - */ -- (void)updateFieldMappingButtonCell -{ - int i; - - [fieldMappingButtonOptions setArray:[fieldMappingImportArray objectAtIndex:fieldMappingCurrentRow]]; - for (i = 0; i < [fieldMappingButtonOptions count]; i++) { - if ([[fieldMappingButtonOptions objectAtIndex:i] isNSNull]) { - [fieldMappingButtonOptions replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%i. %@", i+1, [prefs objectForKey:SPNullValue]]]; - } else { - [fieldMappingButtonOptions replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%i. %@", i+1, NSArrayObjectAtIndex(fieldMappingButtonOptions, i)]]; - } - } -} - -- (IBAction)stepRow:(id)sender -/* - displays next/previous row in fieldMapping tableView - */ -{ - if ( [sender tag] == 0 ) { - fieldMappingCurrentRow--; - } else { - fieldMappingCurrentRow++; - } - [self updateFieldMappingButtonCell]; - - //-----------[self setupFieldMappingArray]; - [fieldMappingTableView reloadData]; - - [recordCountLabel setStringValue:[NSString stringWithFormat:@"%ld of %@%lu records", (long)(fieldMappingCurrentRow+1), fieldMappingImportArrayIsPreview?@"first ":@"", (unsigned long)[fieldMappingImportArray count]]]; - - // enable/disable buttons - [rowDownButton setEnabled:(fieldMappingCurrentRow != 0)]; - [rowUpButton setEnabled:(fieldMappingCurrentRow != ([fieldMappingImportArray count]-1))]; -} - /* * Construct the VALUES string for a CSV row, based on the field mapping array - including * surrounding brackets but not including the VALUES keyword. @@ -1318,15 +1208,16 @@ NSInteger mappingArrayCount = [fieldMappingArray count]; for (i = 0; i < mappingArrayCount; i++) { - mapColumn = [NSArrayObjectAtIndex(fieldMappingArray, i) integerValue]; // Skip unmapped columns - if (!mapColumn) continue; + if ([NSArrayObjectAtIndex(fieldMapperOperator, i) integerValue] > 0) continue; + + mapColumn = [NSArrayObjectAtIndex(fieldMappingArray, i) integerValue]; if ([valueString length] > 1) [valueString appendString:@","]; // Append the data - cellData = NSArrayObjectAtIndex(csvRowArray, mapColumn - 1); + cellData = NSArrayObjectAtIndex(csvRowArray, mapColumn); if (cellData == [NSNull null]) { [valueString appendString:@"NULL"]; @@ -2794,8 +2685,6 @@ setFont:[NSFont fontWithName:SPDefaultMonospacedFontName size:[NSFont smallSystemFontSize]]]; [[[exportMultipleXMLTableView tableColumnWithIdentifier:@"tables"] dataCell] setFont:[NSFont fontWithName:SPDefaultMonospacedFontName size:[NSFont smallSystemFontSize]]]; - [[[fieldMappingTableView tableColumnWithIdentifier:@"0"] dataCell] - setFont:[NSFont fontWithName:SPDefaultMonospacedFontName size:[NSFont smallSystemFontSize]]]; [errorsView setFont:[NSFont fontWithName:SPDefaultMonospacedFontName size:[NSFont smallSystemFontSize]]]; } else { [[[exportDumpTableView tableColumnWithIdentifier:@"tables"] dataCell] @@ -2804,8 +2693,6 @@ setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; [[[exportMultipleXMLTableView tableColumnWithIdentifier:@"tables"] dataCell] setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; - [[[fieldMappingTableView tableColumnWithIdentifier:@"0"] dataCell] - setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; [errorsView setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; } } @@ -2815,7 +2702,7 @@ - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView; { - return (aTableView == fieldMappingTableView) ? [fieldMappingTableColumnNames count] : [tables count]; + return [tables count]; } - (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex @@ -2826,39 +2713,19 @@ - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { id returnObject = nil; - - if ( aTableView == fieldMappingTableView ) { - if ([[aTableColumn identifier] isEqualToString:@"field"]) { - returnObject = [fieldMappingTableColumnNames objectAtIndex:rowIndex]; - - } else if ([[aTableColumn identifier] isEqualToString:@"value"]) { - if ([[[aTableColumn dataCell] class] isEqualTo:[NSPopUpButtonCell class]]) { - [(NSPopUpButtonCell *)[aTableColumn dataCell] removeAllItems]; - [(NSPopUpButtonCell *)[aTableColumn dataCell] addItemWithTitle:NSLocalizedString(@"Do not import", @"text for csv import drop downs")]; - [(NSPopUpButtonCell *)[aTableColumn dataCell] addItemsWithTitles:fieldMappingButtonOptions]; - } - - returnObject = [fieldMappingArray objectAtIndex:rowIndex]; - } + + if ( [[aTableColumn identifier] isEqualToString:@"switch"] ) { + returnObject = [[tables objectAtIndex:rowIndex] objectAtIndex:0]; } else { - if ( [[aTableColumn identifier] isEqualToString:@"switch"] ) { - returnObject = [[tables objectAtIndex:rowIndex] objectAtIndex:0]; - } else { - returnObject = [[tables objectAtIndex:rowIndex] objectAtIndex:1]; - } + returnObject = [[tables objectAtIndex:rowIndex] objectAtIndex:1]; } - + return returnObject; } - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { - if ( aTableView == fieldMappingTableView ) { - [fieldMappingArray replaceObjectAtIndex:rowIndex withObject:anObject]; - } - else { - [[tables objectAtIndex:rowIndex] replaceObjectAtIndex:0 withObject:anObject]; - } + [[tables objectAtIndex:rowIndex] replaceObjectAtIndex:0 withObject:anObject]; } @@ -2925,8 +2792,6 @@ self = [super init]; tables = [[NSMutableArray alloc] init]; - fieldMappingTableColumnNames = [[NSMutableArray alloc] init]; - fieldMappingButtonOptions = [[NSMutableArray alloc] init]; fieldMappingArray = nil; fieldMappingImportArray = nil; fieldMappingImportArrayIsPreview = NO; @@ -2938,10 +2803,7 @@ - (void)dealloc { [tables release]; - [fieldMappingTableColumnNames release]; - [fieldMappingButtonOptions release]; if (fieldMappingImportArray) [fieldMappingImportArray release]; - if (fieldMappingArray) [fieldMappingArray release]; if (prefs) [prefs release]; [super dealloc]; -- cgit v1.2.3