Yepher
Yepher

Reputation: 1505

Generically render an arbritrary NSArray or NSDictionary in a NSOutlineView

When using XCode and you open a "plist" file you get the contents in a nice outline view.

In my project CoreDataUtility I would like to do something very similar. In core data a developer can store NSDictionary and NSArray as a transformable object. I would like to be able to present those object in a nice tree view instead of just dumping the description to a NSTextView.

I'm sure I can start coding it and get it to work but first I wanted to check if anyone knows how to get NSTreeView to do this intrinsically or if anyone has sample code that already does something similar?

Thanks for any help you might be able to offer.

Upvotes: 1

Views: 366

Answers (1)

Thomas Tempelmann
Thomas Tempelmann

Reputation: 12095

You cannot use nested NSDictionary objects directory with an NSTreeController because a dict's children wouldn't be of the correct form, as you'd always need same-named keyPaths for the value you want to show in the NSOutlineView's columns.

However, you can easily convert the nested NSDictionary objects into a slightly different representation that meets this requirement.

Consider you have an outlineview with two columns. You'd bind the first column's Value to the Tree Controller's arrangedObjects.col1 and the second to arrangedObjects.col2.

Then here's the code for creating a suitable NSDictionary:


- (NSDictionary*) makeNodeFrom:(NSObject*)value withName:(NSString*)name {
    NSMutableDictionary *result = NSMutableDictionary.dictionary;   // has keys: name, value, children, isLeaf, count
    result[@"col1"] = name;
    if ([value isKindOfClass:NSDictionary.class]) {
        NSMutableArray *children = NSMutableArray.array;
        [(NSDictionary*)value enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSObject *obj, BOOL *stop) {
            [children addObject:[self makeNodeFrom:obj withName:key]];
        }];
        result[@"children"] = children;
        result[@"count"] = @(children.count);
    } else {
        result[@"isLeaf"] = @YES;
        result[@"col2"] = value;
    }
    return result;
}

// return the model from a generic dictionary:
- (NSDictionary)myModel {
    NSDictionary *sampleDict = @{
        @"key1": @"value1,
        @"node": @{
            @"key2": @"value2"
        }
    };
    return [self makeNodeFrom:sampleDict withName:@"root"];
}

In the Tree Controller, bind its Content Array to myModel, and set its keyPath properties as follows:

  • Children: children
  • Count: count
  • Left: isLeaf

Upvotes: 0

Related Questions