Search code examples
cocoacocoa-bindingskey-value-observingnsoutlineviewnstreecontroller

NSTreeController: custom behavior for "canInsert" binding


I have a Cocoa app with an NSOutlineView managed by an NSTreeController.

In addition there's a button for adding new elements to the outline view. I bound the button's enabled flag to the tree controller's canInsert property.

I only want to allow adding up to 5 elements to the outline view. After that, canInsert should return NO.

I created my own sub-class of NSTreeController and overwrote canInsert, but the enabled status of the button does not change, because it doesn't realize that the tree controller has changed when adding elements.

I also implemented: keyPathsForValuesAffectingCanInsert and tried returning various properties such as content, arrangedObjects, but no luck here.

@implementation ILCustomTreeController

- (BOOL)canInsert
{
    return [[self arrangedObjects] count] < 5;
}

+ (NSSet *)keyPathsForValuesAffectingCanInsert
{
    return [NSSet setWithObject:@"content"]; // I also tried 'arrangedObjects'
}

@end

Solution

  • Here's a workaround that does work (although I still think this should be solved by using keyPathForValuesAffectingCanInsert). Suggestions are welcome.

    @implementation ILCustomTreeController
    
    - (BOOL)canInsert
    {    
        return [[self arrangedObjects] count] <= 4;
    }
    
    - (void)addObject:(id)object
    {
        [self willChangeValueForKey:@"canInsert"];
        [super addObject:object];
        [self didChangeValueForKey:@"canInsert"];
    }
    
    - (void)insertObject:(id)object atArrangedObjectIndexPath:(NSIndexPath *)indexPath
    {
        [self willChangeValueForKey:@"canInsert"];
        [super insertObject:object atArrangedObjectIndexPath:indexPath];
        [self didChangeValueForKey:@"canInsert"];
    }
    
    - (void)remove:(id)sender
    {
        [self willChangeValueForKey:@"canInsert"];
        [super remove:sender];
        [self didChangeValueForKey:@"canInsert"];    
    }
    
    @end