5

I'm trying to create a source list for a new program and I'm having a little issue using a view-based NSOutlineView. My code works fine using a cell-based NSOutlineView so I'm a little confused about what is happening.

Here is my code for the delegate and data source:

#pragma mark -
#pragma mark NSOutlineView Delegate

- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item {
    return (item == nil) ? YES : [(SourceListNode *)item groupItem];
}

- (id)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
    if ([(SourceListNode *)item groupItem]) {
        return [outlineView makeViewWithIdentifier:@"HeaderCell" owner:self];
    }
    else {
        return [outlineView makeViewWithIdentifier:@"DataCell" owner:self];
    }
}

#pragma mark -
#pragma mark NSOutlineView Data Source

- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
    return (item == nil) ? [sourceListNodes count] : [(SourceListNode *)item numberOfChildren];
}

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
    return (item == nil) ? YES : ([(SourceListNode *)item numberOfChildren] > 0);
}

- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
    return (item == nil) ? [sourceListNodes objectAtIndex:index] : [(SourceListNode *)item childAtIndex:index];
}

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
    return [(SourceListNode *)item name];
}

When I run this through the debugger it see that outlineView:objectValueForTableColumn:byItem: does not execute. The result is an outline view with no text. The correct cells are created and I am able to select them and expand them. What am I missing?

UPDATE: I deleted my source list in IB, added a new one, and connected it to my controller object. The results were better, but the header cells had the text "HEADER CELL" and the child cells had "Table View Cell".

I ran the program through the debugger again and this time outlineView:objectValueForTableColumn:byItem: was executed. It did not populate the text of the cell though.

I then updated outlineView:viewForTableColumn:item: as follows:

- (id)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
    NSTableCellView *result;
    if ([(SourceListNode *)item groupItem]) {
        result = [outlineView makeViewWithIdentifier:@"HeaderCell" owner:self];
    }
    else {
        result = [outlineView makeViewWithIdentifier:@"DataCell" owner:self];
    }

    [[result textField] setStringValue:[(SourceListNode *)item name]];

    return result;
}

Now everything works as expected.

So in short, I have solved my problem. However, I now have another question. What is the purpose of outlineView:objectValueForTableColumn:byItem: for view-base outline views? It executes, but does not appear to do anything.

John Barnes
  • 67
  • 1
  • 7
  • Hi John, did you since figured out why objectValueForTableColumn is required for view-based outline view? I'm wondering the same thing myself. – Indoor Mar 12 '14 at 15:04

1 Answers1

4

View-based is a tad different than cell-based.

All that is different is replacing the "id" return value to "NSView".

Change this:

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

To this:

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

This is given the assumption you are running 10.7, and you are actually going to return an NSView.

evdude100
  • 437
  • 4
  • 18
  • I changed `id` to `NSView *`. It didn't change the results of my update (to original post). – John Barnes Jan 06 '12 at 21:21
  • Don't return an NSTableCellView. Return an NSView. The NSView you return doesn't have to have a initialized frame; NSControl controls that for you. Populate a new NSView, add elements to it-- then return it. – evdude100 Jan 06 '12 at 21:36
  • I'd have to play around with that a bit, but I'm not sure why I'd want to do that in this case. The default source list in IB is configured with two NSTableCellViews (HeaderCell and DataCell). Once I have one I only need to add `[[result textField] setStringValue:[(SourceListNode *)item name]];` and everything works. What am I not considering? – John Barnes Jan 06 '12 at 22:09
  • Sorry that I cannot be of much help. I don't know. – evdude100 Jan 07 '12 at 16:50
  • you are a genius! Thanks. I forgot that by default, interface builder creates view based outline views!!! – Duck Feb 15 '15 at 03:50