Skip to content

Commit

Permalink
Change CSV field mapper so that the first row is no longer displayed …
Browse files Browse the repository at this point in the history
…as content row when "First line contains field names" is enabled
  • Loading branch information
dmoagx committed Jan 31, 2016
1 parent 6e25cf7 commit c196132
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 34 deletions.
1 change: 1 addition & 0 deletions Source/SPFieldMapperController.h
Expand Up @@ -161,6 +161,7 @@
- (NSArray*)fieldMappingGlobalValueArray;
- (NSArray*)fieldMappingTableDefaultValues;
- (BOOL)importFieldNamesHeader;
- (BOOL)hasContentRows;
- (BOOL)insertRemainingRowsAfterUpdate;
- (BOOL)globalValuesInUsage;
- (BOOL)importIntoNewTable;
Expand Down
125 changes: 91 additions & 34 deletions Source/SPFieldMapperController.m
Expand Up @@ -37,11 +37,10 @@
#import "SPCategoryAdditions.h"
#import "RegexKitLite.h"
#import "SPDatabaseData.h"
#import "SPFunctions.h"

#import <SPMySQL/SPMySQL.h>

#define SP_NUMBER_OF_RECORDS_STRING NSLocalizedString(@"%ld of %@%lu records", @"Label showing the index of the selected CSV row")

// Constants
static NSString *SPTableViewImportValueColumnID = @"import_value";
static NSString *SPTableViewTypeColumnID = @"type";
Expand Down Expand Up @@ -204,8 +203,8 @@ - (void)awakeFromNib
[advancedUpdateView setHidden:YES];
[advancedInsertView setHidden:YES];

[self changeHasHeaderCheckbox:self];
[self changeTableTarget:self];
[self changeHasHeaderCheckbox:self];
[[self window] makeFirstResponder:fieldMapperTableView];
if([fieldMappingTableColumnNames count])
[fieldMapperTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
Expand All @@ -214,7 +213,8 @@ - (void)awakeFromNib
[insertNULLValueButton setEnabled:([globalValuesTableView numberOfSelectedRows] == 1)];

[self updateFieldNameAlignment];


[self validateImportButton];
}

- (void)dealloc
Expand Down Expand Up @@ -337,7 +337,18 @@ - (NSArray*)fieldMappingTableDefaultValues

- (BOOL)importFieldNamesHeader
{
return ([importFieldNamesHeaderSwitch state] == NSOnState)?YES:NO;
if(importFieldNamesHeaderSwitch) {
return ([importFieldNamesHeaderSwitch state] == NSOnState);
}
else {
//this is a provisional field for the initial value of the checkbox until the window is actually loaded
return importFieldNamesHeader;
}
}

- (BOOL)hasContentRows
{
return (([fieldMappingImportArray count] - ([self importFieldNamesHeader]? 1 : 0)) > 0);
}

- (BOOL)insertRemainingRowsAfterUpdate
Expand Down Expand Up @@ -607,9 +618,7 @@ - (IBAction)changeTableTarget:(id)sender
fieldMappingCurrentRow = 0;
if (fieldMappingArray) SPClear(fieldMappingArray);
[self setupFieldMappingArray];
[rowDownButton setEnabled:NO];
[rowUpButton setEnabled:([fieldMappingImportArray count] > 1)];
[recordCountLabel setStringValue:[NSString stringWithFormat:SP_NUMBER_OF_RECORDS_STRING, (long)(fieldMappingCurrentRow+1), fieldMappingImportArrayIsPreview?@"first ":@"", (unsigned long)[fieldMappingImportArray count]]];
[self updateRowNavigation];

[self updateFieldMappingButtonCell];
[self updateFieldMappingOperatorOptions];
Expand Down Expand Up @@ -714,7 +723,7 @@ - (IBAction)changeImportMethod:(id)sender
- (IBAction)changeFieldAlignment:(id)sender
{

if(![fieldMappingImportArray count]) return;
if(![self hasContentRows]) return;

NSUInteger i;
NSInteger j;
Expand Down Expand Up @@ -767,25 +776,21 @@ - (IBAction)stepRow:(id)sender
[self updateFieldMappingButtonCell];

[fieldMapperTableView reloadData];

[recordCountLabel setStringValue:[NSString stringWithFormat:SP_NUMBER_OF_RECORDS_STRING, (long)(fieldMappingCurrentRow+1), fieldMappingImportArrayIsPreview?@"first ":@"", (unsigned long)[fieldMappingImportArray count]]];

// enable/disable buttons
[rowDownButton setEnabled:(fieldMappingCurrentRow != 0)];
[rowUpButton setEnabled:(fieldMappingCurrentRow != (NSInteger)([fieldMappingImportArray count]-1))];

[self updateRowNavigation];
}

- (IBAction)changeHasHeaderCheckbox:(id)sender
{
NSInteger i;
NSArray *headerRow;

[matchingNameMenuItem setEnabled:([importFieldNamesHeaderSwitch state] == NSOnState)?YES:NO];
[matchingNameMenuItem setEnabled:[self importFieldNamesHeader]];

// In New Table mode reset new field name according to importFieldNamesHeaderSwitch's state
if (newTableMode) {
[fieldMappingTableColumnNames removeAllObjects];
if([importFieldNamesHeaderSwitch state] == NSOnState) {
if([self importFieldNamesHeader]) {
headerRow = NSArrayObjectAtIndex(fieldMappingImportArray, 0);
for (i = 0; i < numberOfImportColumns; i++) {
id headerCol = NSArrayObjectAtIndex(headerRow, i);
Expand All @@ -800,6 +805,13 @@ - (IBAction)changeHasHeaderCheckbox:(id)sender
}
[fieldMapperTableView reloadData];
}

[self updateFieldMappingButtonCell];
[fieldMapperTableView reloadData];

[self updateRowNavigation];

[self validateImportButton];
}

- (IBAction)goBackToFileChooserFromPathControl:(id)sender
Expand Down Expand Up @@ -853,7 +865,7 @@ - (IBAction)newTable:(id)sender
}

// Step through the currently known data and get the types and values
NSUInteger i = (importFieldNamesHeader ? 1 : 0);
NSUInteger i = ([self importFieldNamesHeader] ? 1 : 0);
NSArray *row;
id col;
for ( ; i < [fieldMappingImportArray count]; i++) {
Expand All @@ -878,7 +890,7 @@ - (IBAction)newTable:(id)sender
[fieldMappingTableTypes removeAllObjects];

BOOL serverGreaterThanVersion4 = ([mySQLConnection serverMajorVersion] >= 5) ? YES : NO;
BOOL importFirstRowAsFieldNames = ([importFieldNamesHeaderSwitch state] == NSOnState);
BOOL importFirstRowAsFieldNames = [self importFieldNamesHeader];

NSArray *headerRow = NSArrayObjectAtIndex(fieldMappingImportArray, 0);
for (columnCounter = 0; columnCounter < numberOfImportColumns; columnCounter++) {
Expand Down Expand Up @@ -919,10 +931,8 @@ - (IBAction)newTable:(id)sender
fieldMappingCurrentRow = 0;
if (fieldMappingArray) SPClear(fieldMappingArray);
[self setupFieldMappingArray];
[rowDownButton setEnabled:NO];
[rowUpButton setEnabled:([fieldMappingImportArray count] > 1)];
[recordCountLabel setStringValue:[NSString stringWithFormat:SP_NUMBER_OF_RECORDS_STRING, (long)(fieldMappingCurrentRow+1), fieldMappingImportArrayIsPreview?@"first ":@"", (unsigned long)[fieldMappingImportArray count]]];

[self updateRowNavigation];

[self updateFieldMappingButtonCell];
[self updateFieldMappingOperatorOptions];

Expand Down Expand Up @@ -1105,8 +1115,8 @@ - (IBAction)addGlobalSourceVariable:(id)sender

// Add column placeholder
NSInteger i = 0;
if([fieldMappingImportArray count] && [[fieldMappingImportArray objectAtIndex:0] count]) {
for(id item in [fieldMappingImportArray objectAtIndex:0]) {
if([self hasContentRows]) {
for(id item in [fieldMappingImportArray objectAtIndex:([self importFieldNamesHeader]? 1 : 0)]) {
i++;
if ([item isNSNull]) {
[insertPullDownButton addItemWithTitle:[NSString stringWithFormat:@"%li. <%@>", (long)i, [prefs objectForKey:SPNullValue]]];
Expand Down Expand Up @@ -1388,7 +1398,7 @@ - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextIn

- (void)matchHeaderNames
{
if(![fieldMappingImportArray count]) return;
if(![self hasContentRows]) return;

NSMutableArray *fileHeaderNames = [NSMutableArray array];
[fileHeaderNames setArray:NSArrayObjectAtIndex(fieldMappingImportArray, 0)];
Expand Down Expand Up @@ -1502,7 +1512,7 @@ - (void)setupFieldMappingArray
- (void)updateFieldMappingButtonCell
{
NSUInteger i;
if([fieldMappingImportArray count] == 0) return;
if(![self hasContentRows]) return;
[fieldMappingButtonOptions setArray:[fieldMappingImportArray objectAtIndex:fieldMappingCurrentRow]];
for (i = 0; i < [fieldMappingButtonOptions count]; i++) {
if ([[fieldMappingButtonOptions objectAtIndex:i] isNSNull])
Expand Down Expand Up @@ -1555,42 +1565,89 @@ - (void)updateFieldNameAlignment
}
#endif

// Set matching names only if csv file has an header
if(importFieldNamesHeader && alignment == 2)
[alignByPopup selectItemWithTag:2];
else if(!importFieldNamesHeader && alignment == 2)
[alignByPopup selectItemWithTag:0];
else
if(alignment == 2) {
// Set matching names only if csv file has a header
if([self importFieldNamesHeader])
[alignByPopup selectItemWithTag:2];
else
[alignByPopup selectItemWithTag:0];
}
else {
[alignByPopup selectItemWithTag:alignment];
}

[self changeFieldAlignment:nil];

}

- (void)updateRowNavigation
{
int firstRowIsHeader = [self importFieldNamesHeader] ? 1 : 0;

// if the first row becomes a header row it can no longer be a content row
if(!fieldMappingCurrentRow && firstRowIsHeader && [self hasContentRows]) {
fieldMappingCurrentRow++;
[self updateFieldMappingButtonCell];
[fieldMapperTableView reloadData];
}

NSUInteger countRows = [fieldMappingImportArray count];
[rowDownButton setEnabled:(fieldMappingCurrentRow > firstRowIsHeader)];
[rowUpButton setEnabled:(SPIntS2U(fieldMappingCurrentRow) < (countRows - 1))];

long displayedCurrentRow = fieldMappingCurrentRow+1-firstRowIsHeader;
unsigned long displayedTotalRows = (countRows? (countRows - firstRowIsHeader) : 0); //avoid negative values on empty array

NSString *fmt;
if(fieldMappingImportArrayIsPreview)
fmt = NSLocalizedString(@"%ld of first %lu record(s)", @"Label showing the index of the selected CSV row (csv partially loaded)");
else
fmt = NSLocalizedString(@"%ld of %lu record(s)", @"Label showing the index of the selected CSV row");

[recordCountLabel setStringValue:[NSString stringWithFormat:fmt, displayedCurrentRow, displayedTotalRows]];
}

- (void)validateImportButton
{
BOOL enableImportButton = YES;

if (newTableMode) {
if (![tablesListInstance isTableNameValid:[newTableNameTextField stringValue] forType:SPTableTypeTable ignoringSelectedTable:NO]) {
[importButton setEnabled:NO];
return;
}

BOOL hasImportColumns = NO;
for (NSUInteger i = 0; i < [fieldMappingTableColumnNames count]; i++) {
NSString *colName = [fieldMappingTableColumnNames objectAtIndex:i];
BOOL shouldImport = [doImportKey isEqualToNumber:[fieldMappingOperatorArray objectAtIndex:i]];
if (shouldImport && ![colName length]) {
[importButton setEnabled:NO];
return;
}
if(!hasImportColumns && shouldImport) hasImportColumns = YES;
}

if(!hasImportColumns) {
// new table without any columns is not valid
[importButton setEnabled:NO];
return;
}

for (NSString* fieldType in fieldMappingTableTypes) {
if(![fieldType length]) {
[importButton setEnabled:NO];
return;
}
}
}
else {
// we don't want to create a new table and have no rows to import either => can't import nothing
if(![self hasContentRows]) {
[importButton setEnabled:NO];
return;
}
}

if ([[self selectedImportMethod] isEqualToString:@"UPDATE"]) {
enableImportButton = NO;
Expand Down
7 changes: 7 additions & 0 deletions Source/SPFunctions.h
Expand Up @@ -42,3 +42,10 @@ void SPMainQSync(void (^block)(void));
* @return 0 on success or -1 if something went wrong, check errno
*/
int SPBetterRandomBytes(uint8_t *buf, size_t count);

/**
* Convert a signed integer into an unsigned integer or throw an exception if the values don't fit.
* @param i a signed integer
* @return the same value, casted to unsigned integer
*/
NSUInteger SPIntS2U(NSInteger i);
7 changes: 7 additions & 0 deletions Source/SPFunctions.m
Expand Up @@ -69,3 +69,10 @@ int SPBetterRandomBytes(uint8_t *buf, size_t count)

return 0;
}

NSUInteger SPIntS2U(NSInteger i)
{
if(i < 0) [NSException raise:NSRangeException format:@"NSInteger %ld does not fit in NSUInteger",i];

return (NSUInteger)i;
}

0 comments on commit c196132

Please sign in to comment.