4
votes

I'm populating a NSOUtlineView with a NSTreeController.

The NSTreeController is a 3 levels hierarchy controller (CBMovie, CBDisc and CBEpisode), but only the first 2 levels are displayed in the outline view.

The implementation is the same for all objects: I've implemented methods to specify children, children count and if the object is a leaf. These methods are correctly called for all objects (also for those ones that are not displayed, the grandchildren: CBEpisode).

In the outline View, everything is displayed correctly for the first 2 level. But grandchildren are never displayed, I don't have the option to expand their parent to see them. I can only see CBMovie and CBDiscs.

I'm wondering if there is another setting I'm missing, about how deep the nodes can expand in NSTreeControllers or NSOutlineView configurations.

Below: Implementation in one of the three nodes. Each node class has different path to its children. This is specified in the -(NSArray*)children method (correctly called).

-(NSArray*)children
{
    return [[self Episodes] allObjects];
}

-(int)childrenCount
{
    return [[self Episodes] count];
}

-(BOOL)isLeaf
{
    return ![[self Episodes] count];
}

Output of logging code. The datasource, the NSTreeController, seems to have the correct structure.

   CBMovie
      CBDisc
         CBEpisode
         CBEpisode
    CBMovie
       CBDisc
       CBDisc
       CBDisc
       CBDisc
    CBMovie
       CBDisc
           CBEpisode
           CBEpisode

This is how I populate the NSOutlineView (cell based). I don't use datasource methods, but I'm binding it programmatically.

NSMutableDictionary *bindingOptions = [[NSMutableDictionary alloc] initWithCapacity:2];

        if (metadata.valueTransformer) {
            [bindingOptions setObject:metadata.valueTransformer forKey:NSValueTransformerNameBindingOption];
        }
        [bindingOptions setObject:[NSNumber numberWithBool:NO] forKey:NSCreatesSortDescriptorBindingOption];
        [bindingOptions setObject:[NSNumber numberWithBool:NO] forKey:NSRaisesForNotApplicableKeysBindingOption];

        [newColumn bind:@"value" toObject:currentItemsArrayController withKeyPath:[NSString stringWithFormat:@"arrangedObjects.%@", metadata.columnBindingKeyPath] options:bindingOptions];
2
Can you share some code?Stefan Arentz
From your description I cannot see any problems. Can you provide some more details, such as the implementation of your tree node?Renfei Song
@renfei My tree nodes are all inheriting from the same class. What do you need to know more precisely?aneuryzm
@StefanArentz I've added the only code I'm using for the tree implementation in my tree nodesaneuryzm
@renfei ok. Indeed that's why I posted it, because I have no clue. What kind of extra details you need? I need some leadaneuryzm

2 Answers

1
votes

Examining the NSTreeController side

The NSTreeController is a 3 levels hierarchy controller, but only the first 2 levels are displayed in the outline view.

Have you confirmed that all three levels are loaded into your NSTreeController? You could do this by logging its contents to the console with the extension below. If the output produced by this code matches what appears in your outline-view, the problem is probably on the NSTreeController side, not the outline-view.

#import "NSTreeController+Logging.h"

@implementation NSTreeController (Logging)

// Make sure this is declared in the associated header file.
-(void)logWithBlock:(NSString * (^)(NSTreeNode *))block {

    NSArray *topNodes = [self.arrangedObjects childNodes];
    [self logNodes:topNodes withIndent:@"" usingBlock:block];
}

// For internal use only.
-(void)logNodes:(NSArray *)nodes
     withIndent:(NSString *)indent
     usingBlock:(NSString * (^)(NSTreeNode *))block {

    for (NSTreeNode * each in nodes) {
        NSLog(@"%@%@", indent, block(each));
        NSString *newIndent = [NSString stringWithFormat:@"  %@", indent];
        [self logNodes:each.childNodes withIndent:newIndent usingBlock:block];
    }
}

@end

The above code does not need to be adjusted, all you need to do is call it with a customised block:

-(void)logIt {

    [self.treeController logWithBlock:^NSString *(NSTreeNode * node) {

        // This will be called for every node in the tree. This implementation
        // will see the object's description logged to the console - you may
        // want to do something more elaborate.
        NSString *description = [[node representedObject] description];
        return description;
    }];

}

Examining the NSOutlineView side

If all the data seems to have loaded correctly into the NSTreeController you could have a look at how your NSOutlineView is populated. The delegate method -[NSOutlineViewDelegate outlineView:viewForTableColumn:item] is a good place to start. The item argument is the NSTreeNode instance, so, before you return the relevant view you can look at this node and make sure it's behaving as expected. In your case, you should scrutinize the properties of item objects that are representing CBDisc objects. (You may need to click on disclosure buttons to get this method to fire for the relevant objects.)

-(NSView *)outlineView:(NSOutlineView *)outlineView
    viewForTableColumn:(NSTableColumn *)tableColumn
                  item:(id)item {

    NSTreeNode *node = (NSTreeNode *)item;
    NSManagedObject *representedObject = (NSManagedObject *)node.representedObject;

    // Query the node
    NSLog(@"%@ <%@>", representedObject.description, [representedObject class]);
    NSLog(@"  node is a leafNode: %@", node.isLeaf ? @"YES" : @"NO");
    NSLog(@"  node has child-count of: %lu", (unsigned long)node.childNodes.count);

    // Query the NSManagedObject
    // your stuff here...

    // This is app-specific - you'll probably need to change the identifier.
    return [outlineView makeViewWithIdentifier:@"StandardTableCellView" owner:self];
}
0
votes

So, I've figured out why.

Quite stupid: the main outline column containing the disclosure arrows was 20px width only and the arrows of the children had indentation.

I'm using the outline column for the arrows only and not the titles of the nodes, that's why it's so narrow.

I had disabled indentation and now I can see all arrows.