/* RExplorer-OutlineDelegate.m created by epeyton on Tue 11-Jan-2000 */ #import "RExplorer-OutlineDelegate.h" @implementation RExplorer (OutlineDelegate) - (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item { [inspectorText setString:[item description]]; [inspectorText display]; return YES; } - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item { if (item == nil) { // root return [[currentSelectedItemDict allValues] objectAtIndex:index]; } else { //id newItem = [currentSelectedItemDict objectForKey:item]; if ([item isKindOfClass:[NSArray class]]) { if ([item count]) { return [item objectAtIndex:index]; } } else if ([item isKindOfClass:[NSDictionary class]]) { if ([item count]) { return [[item allValues] objectAtIndex:index]; } } return item; } return nil; } - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item { //id newItem = [currentSelectedItemDict objectForKey:item]; if ([item isKindOfClass:[NSArray class]]) { if ([item count] > 0) { return YES; } } else if ([item isKindOfClass:[NSDictionary class]]) { if ([[item allKeys] count] > 0) { return YES; } } return NO; } - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item { if (item == nil) { // root //NSLog(@"%@", currentSelectedItemDict); return [[currentSelectedItemDict allKeys] count]; } else { //id newItem = [currentSelectedItemDict objectForKey:item]; if ([item isKindOfClass:[NSArray class]] || [item isKindOfClass:[NSDictionary class]]) { return [item count]; } } return 0; } - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { if (tableColumn == keyColumn) { id parentObject = (id)NSMapGet(_parentMap, item); if (!parentObject) { parentObject = currentSelectedItemDict; } if ([parentObject isKindOfClass:[NSArray class]]) { return [NSNumber numberWithInt:[parentObject indexOfObject:item]]; } if ([parentObject isKindOfClass:[NSDictionary class]]) { //int index = [[parentObject allValues] indexOfObject:item]; //return [[parentObject allKeys] objectAtIndex:index]; id obj = (id)NSMapGet(_keyMap, item); return obj; } return item; } if (tableColumn == typeColumn) { // Return an NSNumber with the index of the selected item in the popup of classes. id obj = @""; if ([item isKindOfClass:[NSDictionary class]]) { obj = NSLocalizedString(@"Dictionary", @""); } else if ([item isKindOfClass:[NSArray class]]) { obj = NSLocalizedString(@"Array", @""); } else if ([item isKindOfClass:[NSString class]]) { obj = NSLocalizedString(@"String", @""); } else if ([item isKindOfClass:[NSData class]]) { obj = NSLocalizedString(@"Data", @""); } else if ([item isKindOfClass:[NSDate class]]) { obj = NSLocalizedString(@"Date", @""); } else if ([item isKindOfClass:[RBool class]]) { obj = NSLocalizedString(@"Boolean", @""); } else if ([item isKindOfClass:[NSNumber class]]) { obj = NSLocalizedString(@"Number", @""); } return obj; } else { if ([item isKindOfClass:[NSArray class]]) { if ([item count] == 1) { return [NSString stringWithFormat:NSLocalizedString(@"(%d Object)", @""), [item count]]; } else { return [NSString stringWithFormat:NSLocalizedString(@"(%d Objects)" ,@""), [item count]]; } } else if ([item isKindOfClass:[NSDictionary class]]) { if ([item count] == 1) { return [NSString stringWithFormat:NSLocalizedString(@"(%d Key/Value Pair)", @""), [item count]]; } else { return [NSString stringWithFormat:NSLocalizedString(@"(%d Key/Value Pairs)", @""), [item count]]; } } else if ([item isKindOfClass:[NSData class]]) { return [self CFDataShow:item]; } else if ([item isKindOfClass:[NSNumber class]]) { long long val = [item longLongValue]; return [NSString stringWithFormat:@"%s (%#qx)", [[item description] cString],val]; } return [item description]; } return @""; } - (NSString *)CFDataShow:(CFDataRef) object { UInt32 asciiNormalCount = 0; UInt32 asciiSymbolCount = 0; const UInt8 * bytes; CFIndex index; CFIndex length; NSMutableString *newString = [NSMutableString string]; [newString appendString:@"<"]; length = CFDataGetLength(object); bytes = CFDataGetBytePtr(object); // // This algorithm detects ascii strings, or a set of ascii strings, inside a // stream of bytes. The string, or last string if in a set, needn't be null // terminated. High-order symbol characters are accepted, unless they occur // too often (80% of characters must be normal). Zero padding at the end of // the string(s) is valid. If the data stream is only one byte, it is never // considered to be a string. // for (index = 0; index < length; index++) // (scan for ascii string/strings) { if (bytes[index] == 0) // (detected null in place of a new string, { // ensure remainder of the string is null) for (; index < length && bytes[index] == 0; index++) { } break; // (either end of data or a non-null byte in stream) } else // (scan along this potential ascii string) { for (; index < length; index++) { if (isprint(bytes[index])) asciiNormalCount++; else if (bytes[index] >= 128 && bytes[index] <= 254) asciiSymbolCount++; else break; } if (index < length && bytes[index] == 0) // (end of string) continue; else // (either end of data or an unprintable character) break; } } if ((asciiNormalCount >> 2) < asciiSymbolCount) // (is 80% normal ascii?) index = 0; else if (length == 1) // (is just one byte?) index = 0; if (index >= length && asciiNormalCount) // (is a string or set of strings?) { Boolean quoted = FALSE; for (index = 0; index < length; index++) { if (bytes[index]) { if (quoted == FALSE) { quoted = TRUE; if (index) [newString appendString:@",\""]; else [newString appendString:@"\""]; } [newString appendFormat:@"%c", bytes[index]]; } else { if (quoted == TRUE) { quoted = FALSE; [newString appendString:@"\""]; } else break; } } if (quoted == TRUE) [newString appendString:@"\""]; } else // (is not a string or set of strings) { for (index = 0; index < length; index++) [newString appendFormat:@"%02x", bytes[index]]; } [newString appendString:@">"]; return [[newString copy] autorelease]; } @end