4

I have a flawless functioning view-based NSOutlineView with a proper set-up datasource in my project. Now I want to allow the user to change certain entries. So I made the NSTextField in the IB editable. For a cell-based NSOutlineView you can use the delegate method outlineView:setObjectValue:forTableColumn:byItem: however it's not available for a view-based NSOutlineView as stated in the header file for the NSOutlineViewData protocol:

/* View Based OutlineView: This method is not applicable. */

(void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;

So I searched for another delegate method and found outlineView:shouldEditTableColumn:item:. However this delegate method doesn't get fired. Probably because I'm not editing a cell.

So my question is: Is there any other way to notice when a row changed than having a delegate for each NSTextField?

Paul
  • 1,295
  • 2
  • 11
  • 26

2 Answers2

9

You are correct that your text field needs to be editable in Interface Builder.

Next, make your controller conform to NSTextFieldDelegate. Then, set the delegate for the text field in outlineView:viewForTableColumn:item:, like so:

tableCellView.textField.delegate = self

Here's a simplified example, where you've implemented the method for returning the table cell view for an item for your outline view.

-(NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
    NSTableCellView *tableCellView = [outlineView makeViewWithIdentifier:@"myTableCellView" owner:self];

    MyItem *myItem = (MyItem *)item; // MyItem is just a pretend custom model object 
    tableCellView.delegate = self;
    tableCellView.textField.stringValue = [myItem title];

    tableCellView.textField.delegate = self;

    return result;
}

Then, the controller should get a controlTextDidEndEditing notification:

- (void)controlTextDidEndEditing:(NSNotification *)obj
{
    NSTextField *textField = [obj object];
    NSString *newTitle = [textField stringValue];

    NSUInteger row = [self.sidebarOutlineView rowForView:textField];

    MyItem *myItem = [self.sidebarOutlineView itemAtRow:row];
    myItem.name = newTitle;  
}
Chris Livdahl
  • 4,662
  • 2
  • 38
  • 33
  • The controlTextDidEndEditing function is not part of the NSTextFieldDelegate protocol. This works fine, but I don't know why nor how I could have found this on my own. – Wizard of Kneup Dec 06 '15 at 06:11
  • @WizardofKneup NSTextFieldDelegate protocol inherits from NSControlTextEditingDelegate protocol which is where you could have found the methods. – Dalzhim May 09 '17 at 22:55
4

Well, it seems like Apple wants us to use the delegate methods of each NSTextField as stated here:

This method is intended for use with cell-based table views, it must not be used with view-based table views. Instead target/action is used for each item in the view cell.

So there's currently no other way to do this.

LShi
  • 1,500
  • 16
  • 29
Paul
  • 1,295
  • 2
  • 11
  • 26
  • Hey @Paul Engstler, do you have an example of implementing this `target/action` method? I'm not sure I get what this means or where to look to figure out how to do it properly. – imns May 22 '14 at 14:18
  • Answer is technical correct, but answer from Chris below shows how to solve the underlying problem of how to set the edited value. – Wizard of Kneup Dec 06 '15 at 06:14