From ca60d2e7bdec4763489e79ff4c457c32cd1f57db Mon Sep 17 00:00:00 2001 From: Bibiko Date: Fri, 3 Sep 2010 10:53:26 +0000 Subject: =?UTF-8?q?=E2=80=A2=20finished=20the=20first=20implementation=20o?= =?UTF-8?q?f=20CSV=20Import=20into=20new=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit note:What else is needed for such an import? table encoding settings? ... has to be discussed --- Interfaces/English.lproj/DataMigrationDialog.xib | 71 +++++---- Source/SPDataImport.h | 1 + Source/SPDataImport.m | 39 ++++- Source/SPFieldMapperController.h | 4 +- Source/SPFieldMapperController.m | 182 ++++++++++++++++++++++- Source/SPTableView.m | 10 ++ Source/SPTablesList.m | 2 +- 7 files changed, 259 insertions(+), 50 deletions(-) diff --git a/Interfaces/English.lproj/DataMigrationDialog.xib b/Interfaces/English.lproj/DataMigrationDialog.xib index 9306af15..97194022 100644 --- a/Interfaces/English.lproj/DataMigrationDialog.xib +++ b/Interfaces/English.lproj/DataMigrationDialog.xib @@ -12,7 +12,7 @@ YES - + YES @@ -280,7 +280,6 @@ 3 YES - YES @@ -332,7 +331,6 @@ YES YES - YES @@ -1859,30 +1857,6 @@ 69 - - - fieldMapperTableView - - - - 70 - - - - delegate - - - - 71 - - - - dataSource - - - - 72 - closeSheet: @@ -2363,6 +2337,30 @@ 409 + + + dataSource + + + + 410 + + + + delegate + + + + 411 + + + + fieldMapperTableView + + + + 413 + @@ -3471,6 +3469,7 @@ 405.IBPluginDependency 406.IBPluginDependency 41.IBPluginDependency + 42.CustomClassName 42.IBPluginDependency 42.ImportedFromIB2 43.IBPluginDependency @@ -3501,9 +3500,9 @@ YES com.apple.InterfaceBuilder.CocoaPlugin - {{827, 351}, {522, 348}} + {{749, 497}, {522, 348}} com.apple.InterfaceBuilder.CocoaPlugin - {{827, 351}, {522, 348}} + {{749, 497}, {522, 348}} {{387, 725}, {432, 282}} @@ -3730,6 +3729,7 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + SPTableView com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -3774,7 +3774,7 @@ - 409 + 413 @@ -4596,6 +4596,7 @@ rowUpButton skipexistingRowsCheckBox tableTargetPopup + tablesListInstance theDelegate @@ -4614,7 +4615,7 @@ id id id - NSTableView + id id NSPathControl id @@ -4643,6 +4644,7 @@ id NSPopUpButton id + id @@ -4691,6 +4693,7 @@ rowUpButton skipexistingRowsCheckBox tableTargetPopup + tablesListInstance theDelegate @@ -4753,7 +4756,7 @@ fieldMapperTableView - NSTableView + id fieldMappingImportArray @@ -4863,6 +4866,10 @@ tableTargetPopup NSPopUpButton + + tablesListInstance + id + theDelegate id diff --git a/Source/SPDataImport.h b/Source/SPDataImport.h index 9a9dedf5..97ba134f 100644 --- a/Source/SPDataImport.h +++ b/Source/SPDataImport.h @@ -94,6 +94,7 @@ BOOL csvImportMethodHasTail; BOOL insertRemainingRowsAfterUpdate; BOOL importMethodIsUpdate; + BOOL importIntoNewTable; NSUInteger exportMode; NSUserDefaults *prefs; diff --git a/Source/SPDataImport.m b/Source/SPDataImport.m index c9b5664b..efc85bbc 100644 --- a/Source/SPDataImport.m +++ b/Source/SPDataImport.m @@ -76,8 +76,10 @@ fieldMappingImportArrayIsPreview = NO; fieldMappingArrayHasGlobalVariables = NO; importMethodIsUpdate = NO; + importIntoNewTable = NO; insertRemainingRowsAfterUpdate = NO; numberOfImportDataColumns = 0; + selectedTableTarget = nil; prefs = nil; lastFilename = nil; @@ -1074,15 +1076,34 @@ document:tableDocumentInstance notificationName:@"Import Finished"]; - // 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] && [selectedTableTarget isEqualToString:[tablesListInstance tableName]]) { - if ([[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableContent]) { - [tableContentInstance performSelectorOnMainThread:@selector(reloadTable:) withObject:nil waitUntilDone:YES]; - } else { - [tablesListInstance setContentRequiresReload:YES]; + + if(importIntoNewTable) { + + // Select the new table + + // Update current database tables + [tablesListInstance performSelectorOnMainThread:@selector(updateTables:) withObject:self waitUntilDone:YES]; + + // Re-query the structure of all databases in the background + [NSThread detachNewThreadSelector:@selector(queryDbStructureWithUserInfo:) toTarget:mySQLConnection withObject:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], @"forceUpdate", nil]]; + + // Select the new table + [tablesListInstance selectItemWithName:selectedTableTarget]; + + } else { + + // If import was done into a new table or 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] && [selectedTableTarget isEqualToString:[tablesListInstance tableName]]) { + if ([[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableContent]) { + [tableContentInstance performSelectorOnMainThread:@selector(reloadTable:) withObject:nil waitUntilDone:YES]; + } else { + [tablesListInstance setContentRequiresReload:YES]; + } } + } + } /** @@ -1165,13 +1186,14 @@ // Get mapping settings and preset some global variables fieldMapperOperator = [[NSArray arrayWithArray:[fieldMapperController fieldMapperOperator]] retain]; fieldMappingArray = [[NSArray arrayWithArray:[fieldMapperController fieldMappingArray]] retain]; - selectedTableTarget = [NSString stringWithString:[fieldMapperController selectedTableTarget]]; + selectedTableTarget = [[NSString stringWithString:[fieldMapperController selectedTableTarget]] retain]; selectedImportMethod = [NSString stringWithString:[fieldMapperController selectedImportMethod]]; fieldMappingTableColumnNames = [[NSArray arrayWithArray:[fieldMapperController fieldMappingTableColumnNames]] retain]; fieldMappingGlobalValueArray = [[NSArray arrayWithArray:[fieldMapperController fieldMappingGlobalValueArray]] retain]; fieldMappingTableDefaultValues = [[NSArray arrayWithArray:[fieldMapperController fieldMappingTableDefaultValues]] retain]; csvImportHeaderString = [[NSString stringWithString:[fieldMapperController importHeaderString]] retain]; csvImportTailString = [[NSString stringWithString:[fieldMapperController onupdateString]] retain]; + importIntoNewTable = [fieldMapperController importIntoNewTable]; fieldMappingArrayHasGlobalVariables = [fieldMapperController globalValuesInUsage]; csvImportMethodHasTail = ([csvImportTailString length] == 0) ? NO : YES; insertRemainingRowsAfterUpdate = [fieldMapperController insertRemainingRowsAfterUpdate]; @@ -1475,6 +1497,7 @@ if (fieldMappingImportArray) [fieldMappingImportArray release]; if (lastFilename) [lastFilename release]; if (prefs) [prefs release]; + if(selectedTableTarget) [selectedTableTarget release]; for (id retainedObject in nibObjectsToRelease) [retainedObject release]; diff --git a/Source/SPFieldMapperController.h b/Source/SPFieldMapperController.h index 15efd595..da5b6ca2 100644 --- a/Source/SPFieldMapperController.h +++ b/Source/SPFieldMapperController.h @@ -24,12 +24,13 @@ #import #import +#import "SPTableView.h" @class SPTextView; @interface SPFieldMapperController : NSWindowController { - IBOutlet NSTableView *fieldMapperTableView; + IBOutlet id fieldMapperTableView; IBOutlet id fieldMapperTableScrollView; IBOutlet NSTableView *globalValuesTableView; IBOutlet NSPopUpButton *tableTargetPopup; @@ -138,6 +139,7 @@ - (BOOL)importFieldNamesHeader; - (BOOL)insertRemainingRowsAfterUpdate; - (BOOL)globalValuesInUsage; +- (BOOL)importIntoNewTable; - (NSString*)onupdateString; - (NSString*)importHeaderString; diff --git a/Source/SPFieldMapperController.m b/Source/SPFieldMapperController.m index 1018ff4e..b9f41935 100644 --- a/Source/SPFieldMapperController.m +++ b/Source/SPFieldMapperController.m @@ -77,6 +77,8 @@ prefs = [NSUserDefaults standardUserDefaults]; tablesListInstance = [theDelegate valueForKeyPath:@"tablesListInstance"]; + [fieldMapperTableView setDelegate:self]; + [fieldMapperTableView setDataSource:self]; } @@ -218,7 +220,11 @@ - (NSString*)selectedTableTarget { + + if(newTableMode) return [newTableNameTextField stringValue]; + return ([tableTargetPopup titleOfSelectedItem] == nil) ? @"" : [tableTargetPopup titleOfSelectedItem]; + } - (NSArray*)fieldMapperOperator @@ -259,6 +265,11 @@ return NO; } +- (BOOL)importIntoNewTable +{ + return newTableMode; +} + - (NSArray*)fieldMappingTableColumnNames { return fieldMappingTableColumnNames; @@ -318,6 +329,38 @@ - (IBAction)closeSheet:(id)sender { + + // Try to create the new TABLE + if(newTableMode && [sender tag] == 1) { + + [[self window] endEditingFor:nil]; + + NSMutableString *createString = [NSMutableString string]; + [createString appendFormat:@"CREATE TABLE %@ (\n", [[newTableNameTextField stringValue] backtickQuotedString]]; + NSInteger columnIndex = 0; + NSInteger numberOfColumns = [fieldMappingTableColumnNames count]; + for(columnIndex = 0; columnIndex < numberOfColumns; columnIndex++) { + [createString appendFormat:@"\t%@ %@", [[fieldMappingTableColumnNames objectAtIndex:columnIndex] backtickQuotedString], [fieldMappingTableTypes objectAtIndex:columnIndex]]; + if(columnIndex < numberOfColumns-1) [createString appendString:@", \n"]; + } + [createString appendString:@")"]; + [mySQLConnection queryString:createString]; + + if ([mySQLConnection queryErrored]) { + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error adding new table", @"error adding new table message") + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to add the new table '%@' by\n\n%@.\n\nMySQL said: %@", @"error adding new table informative message"), [newTableNameTextField stringValue], createString, [mySQLConnection getLastErrorMessage]]]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:nil contextInfo:nil]; + return; + } + + } + + [advancedReplaceView setHidden:YES]; [advancedUpdateView setHidden:YES]; [advancedInsertView setHidden:YES]; @@ -1026,13 +1069,22 @@ BOOL enableImportButton = YES; if(newTableMode) { - [importButton setTitle:@"Not Yet"]; - [importButton setEnabled:NO]; - return; if(![tablesListInstance isTableNameValid:[newTableNameTextField stringValue] forType:SPTableTypeTable ignoringSelectedTable:NO]) { [importButton setEnabled:NO]; return; } + for(NSString* fieldName in fieldMappingTableColumnNames) { + if(![fieldName length]) { + [importButton setEnabled:NO]; + return; + } + } + for(NSString* fieldType in fieldMappingTableTypes) { + if(![fieldType length]) { + [importButton setEnabled:NO]; + return; + } + } } if([[self selectedImportMethod] isEqualToString:@"UPDATE"]) { @@ -1316,7 +1368,7 @@ [self validateImportButton]; } // Refresh table - [aTableView performSelector:@selector(reloadData) withObject:nil afterDelay:0.01]; + // [aTableView performSelector:@selector(reloadData) withObject:nil afterDelay:0.01]; } else if(aTableView == globalValuesTableView) { if ([[aTableColumn identifier] isEqualToString:@"global_value"]) @@ -1337,17 +1389,131 @@ } + +/* + * Trap the enter, escape, tab and arrow keys, overriding default behaviour and continuing/ending editing, + * only within the current row of the tableView only in newTableMode. + */ +- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command +{ + + if(!newTableMode) return NO; + + NSUInteger row, column; + + row = [fieldMapperTableView editedRow]; + column = [fieldMapperTableView editedColumn]; + + // Trap tab key + // -- for handling of blob fields and to check if it's editable look at [[self delegate] control:textShouldBeginEditing:] + if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertTab:)] ) + { + [[control window] makeFirstResponder:control]; + + // Save the current line if it's the last field in the table + if ( [fieldMapperTableView numberOfColumns] - 1 == column) { + [fieldMapperTableView makeFirstResponder]; + } else { + // Select the next field for editing + [fieldMapperTableView editColumn:column+1 row:row withEvent:nil select:YES]; + } + + return YES; + } + + // Trap shift-tab key + else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertBacktab:)] ) + { + [[control window] makeFirstResponder:control]; + + // Save the current line if it's the last field in the table + if ( column < 1 ) { + [fieldMapperTableView makeFirstResponder]; + } else { + // Select the previous field for editing + [fieldMapperTableView editColumn:column-1 row:row withEvent:nil select:YES]; + } + + return YES; + } + + // Trap enter key + else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(insertNewline:)] ) + { + + // If newTableNameTextField is active enter key closes the sheet + if(control == newTableNameTextField) { + NSButton *b = [[[NSButton alloc] init] autorelease]; + [b setTag:1]; + [self closeSheet:b]; + return YES; + } + + [[self window] endEditingFor:nil]; + [[control window] makeFirstResponder:control]; + return YES; + + } + + // Trap down arrow key + else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveDown:)] ) + { + + NSUInteger newRow = row+1; + if (newRow>=[self numberOfRowsInTableView:fieldMapperTableView]) return YES; //check if we're already at the end of the list + + [[control window] makeFirstResponder:control]; + + [fieldMapperTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO]; + [fieldMapperTableView editColumn:column row:newRow withEvent:nil select:YES]; + return YES; + } + + // Trap up arrow key + else if ( [textView methodForSelector:command] == [textView methodForSelector:@selector(moveUp:)] ) + { + + if (row==0) return YES; //already at the beginning of the list + NSUInteger newRow = row-1; + + [[control window] makeFirstResponder:control]; + + [fieldMapperTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:newRow] byExtendingSelection:NO]; + [fieldMapperTableView editColumn:column row:newRow withEvent:nil select:YES]; + return YES; + } + + + // Trap the escape key + else if ( [[control window] methodForSelector:command] == [[control window] methodForSelector:@selector(cancelOperation:)] ) + { + + // Abort editing + [control abortEditing]; + + // Preserve the focus + [fieldMapperTableView makeFirstResponder]; + + return TRUE; + } + + return FALSE; + +} + #pragma mark - #pragma mark NSTextField delegates + +/* + * Validate some user input in newTableMode + */ - (void)controlTextDidChange:(NSNotification *)notification { - id object = [notification object]; + if(!newTableMode) return; - if (object == newTableNameTextField) { - [self validateImportButton]; - } + [self validateImportButton]; } diff --git a/Source/SPTableView.m b/Source/SPTableView.m index 8255f9c1..c19678db 100644 --- a/Source/SPTableView.m +++ b/Source/SPTableView.m @@ -87,9 +87,19 @@ - (void)keyDown:(NSEvent *)theEvent { + // Check if ENTER or RETURN is hit and edit the column. if([self numberOfSelectedRows] == 1 && ([theEvent keyCode] == 36 || [theEvent keyCode] == 76)) { + + // ENTER or RETURN closes the SPFieldMapperController sheet by sending an object with the tag 1 + if([[[[self delegate] class] description] isEqualToString:@"SPFieldMapperController"]) { + NSButton *b = [[[NSButton alloc] init] autorelease]; + [b setTag:1]; + [[self delegate] closeSheet:b]; + return; + } + if (![[[[self delegate] class] description] isEqualToString:@"SPCustomQuery"] && ![[[[self delegate] class] description] isEqualToString:@"SPQueryFavoriteManager"]){ diff --git a/Source/SPTablesList.m b/Source/SPTablesList.m index e3a5cdd3..8075f244 100644 --- a/Source/SPTablesList.m +++ b/Source/SPTablesList.m @@ -1656,7 +1656,7 @@ [mySQLConnection queryString:query]; if ([mySQLConnection queryErrored]) { - NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while importing table", @"rror while importing table message") + NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while importing table", @"error while importing table message") defaultButton:NSLocalizedString(@"OK", @"OK button") alternateButton:nil otherButton:nil -- cgit v1.2.3