Search code examples
swiftmacosnsoutlineviewnstreecontroller

Getting NSTreeController Data on NSOutlineView selection


I've built an NSOutlineView that gets dynamically updated data from an NSTreeController and that all works fine. What I can't seem to do is work backwards from there based on a user selection in the NSOutlineView.

    var deviceStore = [TreeNode]()

is my backing datastore that is updated in real-time it is an array of Device Objects, which may )or may not) contain an array of Service objects as children.

This all works. But when I select a row in the Outline View, I need to work my way back to the original object in the deviceStore -- or, at the very least, get the displayed data from the OutlineView so that I can walk the deviceStore to find the original item.

What I've got is func outlineViewSelectionDidChange(_ notification: Notification) {} which is called when a selection is made, and I can, from that, extract the NSTreeController TreeNode via treeController.selectedNodes but from there, I am in the weeds. The selectedNodes is the complete array of the selected Node, so if it's a child (leaf) node, it includes its parent node, and all its siblings.

Give then Table shown here: OutlineView

The selectedNodes array looks like this:

<NSTreeControllerTreeNode: 0x6080000c4590>, child nodes {
    0:<NSTreeControllerTreeNode: 0x6000000ca6b0>, child nodes {
        0:<NSTreeControllerTreeNode: 0x6000000caf70>, child nodes {}
        1:<NSTreeControllerTreeNode: 0x6000000cafe0>, child nodes {}
        2:<NSTreeControllerTreeNode: 0x6000000cb050>, child nodes {}
    }
    1:<NSTreeControllerTreeNode: 0x6080000d1790>, child nodes {
        0:<NSTreeControllerTreeNode: 0x6000000cce80>, child nodes {}
    }
}

And the selectedIndex is 4.

I can't see how to get back to what, in my data model, would be deviceStore[0].serviceStore[2] from this information.

If I could retrieve the value in the Service ID column from the selected Row, I could simply walk the deviceStore tree to find it.

I'm sure there's a simply, elegant, easy way to do this that I just haven't found yet, but being new to NSTreeControllers and NSOutlineViews I'm lost.


Solution

  • I was never able to actually get back to the TreeController backing-store data baed on where the user clicks in the TreeView. What I was able to do was to work backwards to the data though.

    func outlineViewSelectionDidChange(_ notification: Notification) {
        let selectedIndex = (notification.object as AnyObject).selectedRow!
        let selCol1 = outlineView.view(atColumn: 0, row: selectedIndex, makeIfNecessary: false)?.subviews.last as! NSTextField
        let selCol2 = outlineView.view(atColumn: 1, row: selectedIndex, makeIfNecessary: false)?.subviews.last as! NSTextField
    
        let devName = selCol1.stringValue
        let devID = selCol2.stringValue
    ...
    }
    

    I could then 'walk' the deviceStrore array until I found the devName and devID in it, and deal with it accordingly.

    Probably not the most elegant solution, but at least it finally works.