Getting NSBrowser+NSTreeController to recognize its delegate

I'm refreshing some UI code and have run into a serious problem with NSBrowser.


I've updated my project to use bindings. The NSBrowser is now bound to an NSTreeController (for data and selection). So far, so good.


Now I need to add a delegate to customize some features of the view. The problem is this: the NSBrowser delegate can be implemented two different ways. The olde way, where you implement either -browser:numberOfRowsInColumn: or -browser:createRowsForColumn:inMatrix:, or you can use the "new" way where you implement a family of data source methods starting with -browser:numberOfChildrenOfItem:, -browser:child:ofItem:, and so on.


My problem is that I don't need/want to implement any of these methods, but I have to or NSBrowser won't recognize my object as a delegate.


I don't want to implement the old methods, because as soon as you do certain features of NSBrowser stop working and will throw an exception that says "is not supported for browsers with matrix delegates". Most notably, pressing the right arrow in the view, or calling a method like -itemAtRow:inColumn:.


Alternatively, if I try to implement any of the "new" methods, my NSTreeController stops supplying data to the browser.


But if I don't implement something, the NSBrowser doesn't recognize my object as a browser delegate and it refuses to send any of the other delegate message, like -browser:selectionIndexesForProposedSelection:inColumn:, -browser:shouldSizeColumn:forUserResize:, and -browser:willDisplayCell:atRow:column:, all of which I desperately need.

I slept on the problem and managed to find a workaround, although it's not a complete one.


If I implement the delegate method -browser:numberOfRowsInColumn:, NSBrowser recognizes my object as an old-style delegate and will send all of the optional delegate methods. However, as I mentioned, this also severly limits the usability of NSBrowser because now calls to -itemAtRow:inColumn: and similar methods throw an exception that they are not supported.


My solution (and by "solution" I mean "hack") is to subclass NSBrowser and implement my own -itemAtRow:inColumn: method, like this:


- (id)itemAtRow:(NSInteger)row inColumn:(NSInteger)column
{
  NSMatrix* columnMatrix = [self matrixInColumn:column];
  NSCell* cell = [columnMatrix cellAtRow:row column:0];
  return cell.objectValue;
}


Since all of the cells in the NSMatrix are bound to the objects in the NSTreeController, the item of any given [row,column] is a well-known value. (Why NSBrowser can't do this is beyond me.)


It doesn't solve the problem of -parentForItemInColumn:, which I don't have a simple solution for, but it does prevent -itemAtRow:inColumn: from throwing exceptions, which means that standard arrow-key navigation in the browser view works again.

First time I needed to use NSBrowser. Pretty confusing API. The documentation in the NSBrowserDelegate protocol lists a bunch of methods that are incompatiable with eachother.


Would probably be nicer if they just deprecated NSBrowser and replaced it with something new. I don't really like chicken dancing with delegate methods like this.


I get Must implement browser:willDisplayCell:atRow:column: and either browser:numberOfRowsInColumn: or browser:createRowsForColumn:inMatrix:

But there is the item API too, which draws double arrow indicators for branches, for some reason.

Getting NSBrowser+NSTreeController to recognize its delegate
 
 
Q