Skip to content

Commit

Permalink
Possibility to add columns. Multiple improvements. New Toolbar Icons.
Browse files Browse the repository at this point in the history
  • Loading branch information
svnuser committed Feb 25, 2010
1 parent 181e346 commit 11c8ef5
Show file tree
Hide file tree
Showing 36 changed files with 7,403 additions and 17,958 deletions.
2 changes: 1 addition & 1 deletion AppController.m
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ - (IBAction) exportDocument:(id)sender

// format selection error
else {
NSString *errorString = @"";
NSString *errorString = @"Something went wrong with the export format exporter";
NSDictionary *errorDict = [NSDictionary dictionaryWithObject:errorString forKey:NSLocalizedDescriptionKey];
error = [NSError errorWithDomain:NSCocoaErrorDomain code:667 userInfo:errorDict];
}
Expand Down
18 changes: 12 additions & 6 deletions CSVDocument/CSVDocument.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#endif

#import "CSVDocumentDelegate.h"

#define kColumnKeyMask @"col_%i" // must containt one integer placeholder (%i or %d) !

@class CSVRow;
@class CSVColumn;
@class PPStringFormat;
Expand All @@ -32,9 +35,8 @@
CSVRowController *rowController;
#endif

NSArray *columns; // needs to be an array to preserve column order
NSDictionary *columnDict; // readonly to allow fast access to columns by key
NSArray *activeColumns; // readonly to allow fast access to active columns
NSMutableArray *columns; // needs to be an array to preserve column order
NSMutableDictionary *columnDict; // readonly to allow fast access to columns by key

BOOL parseSuccessful;
BOOL autoDetectSeparator; // if YES will check for other separators (";" and TAB) than the comma
Expand All @@ -54,8 +56,8 @@
@property (nonatomic, retain) CSVRowController *rowController;
#endif

@property (nonatomic, retain) NSArray *columns;
@property (nonatomic, readonly, retain) NSDictionary *columnDict;
@property (nonatomic, retain) NSMutableArray *columns;
@property (nonatomic, readonly, retain) NSMutableDictionary *columnDict;
@property (nonatomic, readonly) NSArray *activeColumns;

@property (nonatomic, assign) BOOL parseSuccessful;
Expand All @@ -82,7 +84,8 @@
#endif

// column handling
- (void) addColumn:(CSVColumn *) newColumn;
- (BOOL) addColumn:(CSVColumn *)newColumn;
- (BOOL) removeColumn:(CSVColumn *)oldColumn;
- (CSVColumn *) columnWithKey:(NSString *)columnKey;
- (void) setColumnOrderByKeys:(NSArray *)newOrderKeys;
- (void) setColumnActive:(BOOL)active forColumnKey:(NSString *)columnKey;
Expand All @@ -93,5 +96,8 @@
- (void) rearrangeRows;
- (void) row:(CSVRow *)thisRow didBecomeHeaderRow:(BOOL)itDid;

// utils
- (NSString *) nextAvailableColumnKey;


@end
92 changes: 64 additions & 28 deletions CSVDocument/CSVDocument.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@

@interface CSVDocument ()

@property (nonatomic, readwrite, retain) NSDictionary *columnDict;
@property (nonatomic, readwrite, retain) NSMutableDictionary *columnDict;

- (void) setColumnDict:(NSDictionary *)newColumnDict;
- (void) updateColumnNames;
- (void) notifyDelegateOfParsedRow:(CSVRow *)newRow;

Expand Down Expand Up @@ -51,8 +50,11 @@ - (id) init
self = [super init];
if (nil != self) {
self.separator = @",";
[self addColumn:[CSVColumn columnWithKey:@"col_0"]];
self.rows = [NSMutableArray array];
self.columns = [NSMutableArray array];
self.columnDict = [NSMutableDictionary dictionary];
[self addColumn:[CSVColumn columnWithKey:[NSString stringWithFormat:kColumnKeyMask, 0]]];

#ifndef IPHONE
self.rowController = [[[CSVRowController alloc] initWithContent:rows] autorelease];
rowController.document = self;
Expand All @@ -74,7 +76,7 @@ - (void) dealloc
self.rows = nil;
self.numRows = nil;
self.columns = nil;
[self setColumnDict:nil];
self.columnDict = nil;
#ifndef IPHONE
self.rowController = nil;
#endif
Expand Down Expand Up @@ -108,7 +110,8 @@ - (BOOL) parseCSVString:(NSString *)string maxRows:(NSUInteger)maxRows error:(NS
// String is non-empty
if ([string length] > 0) {
[rows removeAllObjects];
self.columns = nil;
[self.columns removeAllObjects];
[self.columnDict removeAllObjects];
BOOL sendRowUpdateToDelegate = reportEveryRowParsed && [delegate respondsToSelector:@selector(csvDocument:didParseRow:)];
BOOL sendStatusUpdateToDelegate = (nil != delegate) && [delegate respondsToSelector:@selector(csvDocument:didParseNumRows:)];

Expand All @@ -128,19 +131,21 @@ - (BOOL) parseCSVString:(NSString *)string maxRows:(NSUInteger)maxRows error:(NS
}

// Get newline character set
NSCharacterSet *whiteSpaceChars = [NSCharacterSet whitespaceCharacterSet];
NSMutableCharacterSet *newlineCharacterSet = [NSMutableCharacterSet whitespaceAndNewlineCharacterSet];
[newlineCharacterSet formIntersectionWithCharacterSet:[[NSCharacterSet whitespaceCharacterSet] invertedSet]];
[newlineCharacterSet formIntersectionWithCharacterSet:[whiteSpaceChars invertedSet]];

// Characters where the parser should stop
NSMutableCharacterSet *importantCharactersSet = [NSMutableCharacterSet characterSetWithCharactersInString:[NSString stringWithFormat:@"%@\"", separator]];
[importantCharactersSet formUnionWithCharacterSet:newlineCharacterSet];



// Create scanner and scan the string
// ideas for the following block from Drew McCormack >> http://www.macresearch.org/cocoa-scientists-part-xxvi-parsing-csv-data
BOOL insideQuotes = NO; // needed to determine whether we're inside doublequotes
BOOL finishedRow = NO; // used for the inner while loop
BOOL skipWhitespace = (NSNotFound == [separator rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet]].location);
BOOL skipWhitespace = (NSNotFound == [separator rangeOfCharacterFromSet:whiteSpaceChars].location);
BOOL isNewColumn = NO; // will be YES when a new column is created
BOOL columnHasName = NO; // we use a BOOL here to avoid calling [column hasName] all too often
NSMutableString *currentCellString = [[NSMutableString alloc] init];
Expand All @@ -165,7 +170,6 @@ - (BOOL) parseCSVString:(NSString *)string maxRows:(NSUInteger)maxRows error:(NS
[currentCellString setString:@""];
colIndex = 0;
isNewColumn = NO;
columnHasName = NO;

CSVRow *newRow = [CSVRow rowForDocument:self];

Expand All @@ -179,7 +183,7 @@ - (BOOL) parseCSVString:(NSString *)string maxRows:(NSUInteger)maxRows error:(NS
columnHasName = [column hasName];
}
else {
column = [CSVColumn columnWithKey:[NSString stringWithFormat:@"col_%i", colIndex]];
column = [CSVColumn columnWithKey:[NSString stringWithFormat:kColumnKeyMask, colIndex]];
column.active = YES;
isNewColumn = YES;
columnHasName = NO;
Expand All @@ -194,7 +198,7 @@ - (BOOL) parseCSVString:(NSString *)string maxRows:(NSUInteger)maxRows error:(NS

// found a doublequote (")
if ([scanner scanString:@"\"" intoString:NULL]) {
if (insideQuotes && [scanner scanString:@"\"" intoString:NULL]) { // Replace double - doublequotes with a single doublequote
if (insideQuotes && [scanner scanString:@"\"" intoString:NULL]) { // Replace double-doublequotes with a single doublequote
[currentCellString appendString:@"\""];
}
else { // Start or end of a quoted string.
Expand Down Expand Up @@ -226,7 +230,7 @@ - (BOOL) parseCSVString:(NSString *)string maxRows:(NSUInteger)maxRows error:(NS
// on to the next column/cell!
[currentCellString setString:@""];
if (skipWhitespace) {
[scanner scanCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:NULL];
[scanner scanCharactersFromSet:whiteSpaceChars intoString:NULL];
}
colIndex++;
}
Expand Down Expand Up @@ -292,8 +296,10 @@ - (BOOL) parseCSVString:(NSString *)string maxRows:(NSUInteger)maxRows error:(NS

// empty string
else {
NSDictionary *errorDict = [NSDictionary dictionaryWithObject:@"Cannot parse a nil string" forKey:NSLocalizedDescriptionKey];
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:1 userInfo:errorDict];
if (error) {
NSDictionary *errorDict = [NSDictionary dictionaryWithObject:@"Cannot parse a nil string" forKey:NSLocalizedDescriptionKey];
*error = [NSError errorWithDomain:NSCocoaErrorDomain code:1 userInfo:errorDict];
}
success = NO;
}

Expand Down Expand Up @@ -324,9 +330,11 @@ - (NSString *) stringInFormat:(PPStringFormat *)format
error:(NSError **)outError
{
if ([rows count] < 1 || [columnArray count] < 1) {
NSString *errorString = ([rows count] < 1) ? @"The document contains no rows" : @"The document has no active columns";
NSDictionary *userErrorDict = [NSDictionary dictionaryWithObject:errorString forKey:NSLocalizedDescriptionKey];
*outError = [NSError errorWithDomain:NSCocoaErrorDomain code:666 userInfo:userErrorDict];
if (outError) {
NSString *errorString = ([rows count] < 1) ? @"The document contains no rows" : @"The document has no active columns";
NSDictionary *userErrorDict = [NSDictionary dictionaryWithObject:errorString forKey:NSLocalizedDescriptionKey];
*outError = [NSError errorWithDomain:NSCocoaErrorDomain code:666 userInfo:userErrorDict];
}
return @"";
}

Expand Down Expand Up @@ -366,26 +374,39 @@ - (NSString *) stringInFormat:(PPStringFormat *)format


#pragma mark Column Handling
- (void) addColumn:(CSVColumn *) newColumn
- (BOOL) addColumn:(CSVColumn *)newColumn
{
if (newColumn) {
NSUInteger capacity = [columns count] + 1;
NSMutableArray *columnArray = [NSMutableArray arrayWithCapacity:capacity];
NSMutableDictionary *columnHash = [NSMutableDictionary dictionaryWithCapacity:capacity];

// add existing columns
for (CSVColumn *column in columns) {
[columnArray addObject:column];
[columnHash setObject:column forKey:column.key];
// check if the key is free
if (nil != [columnDict objectForKey:newColumn.key]) {
NSLog(@"Column with key '%@' is already present, we would replace that one!");
return NO;
}

// add the new column
[columnArray addObject:newColumn];
[columnHash setObject:newColumn forKey:newColumn.key];
[columns addObject:newColumn];
[columnDict setObject:newColumn forKey:newColumn.key];

self.columns = columnArray;
[self setColumnDict:columnHash];
return YES;
}
return NO;
}

- (BOOL) removeColumn:(CSVColumn *)oldColumn
{
if (nil != oldColumn) {
NSUInteger i = 0;
for (CSVColumn *column in columns) {
if (column == oldColumn) {
[columns removeObjectAtIndex:i];
[columnDict removeObjectForKey:column.key];
return YES;
}
i++;
}
}
return NO;
}

- (CSVColumn *) columnWithKey:(NSString *)columnKey
Expand All @@ -395,6 +416,7 @@ - (CSVColumn *) columnWithKey:(NSString *)columnKey

- (NSArray *) activeColumns
{
// TODO: Use a filter predicate
NSMutableArray *arr = [NSMutableArray array];
if ([columns count] > 0) {
for (CSVColumn *column in columns) {
Expand Down Expand Up @@ -516,6 +538,20 @@ - (void) row:(CSVRow *)thisRow didBecomeHeaderRow:(BOOL)itDid


#pragma mark Utilities
- (NSString *) nextAvailableColumnKey
{
NSUInteger i = 0;
NSArray *keyArr = [columnDict allKeys];
NSMutableString *nextKey = [NSMutableString stringWithFormat:kColumnKeyMask, i];

while ([keyArr containsObject:nextKey]) {
i++;
[nextKey setString:[NSMutableString stringWithFormat:kColumnKeyMask, i]];
}

return nextKey;
}

- (void) notifyDelegateOfParsedRow:(CSVRow *)newRow // used to perform the delegate action on a different thread
{
[delegate csvDocument:self didParseRow:newRow];
Expand Down
Loading

0 comments on commit 11c8ef5

Please sign in to comment.