1

I have a view-based NSOutlineView configured with a dataSource and delegate. It consists of two columns a custom NSTableCellView class.

Entries in the outline view are editable by selecting a row and pressing the Return key. Everything is set up according the docs and works fine most of the time.

However, sometimes when I press Return while a row is selected, the cell's text field does not enter into edit mode. It just beeps.

I can still enter edit mode by "long clicking" on the text field. For some reason, the Return key event is sometimes handled differently by the outline view.

I captured two stacktraces:

#1 Working as expected:

working

You can see that from keyDown() the event eventually makes the cell's text field the first responder.

#2 Beeping

beep

I put a breakpoint at NSBeep and you can see that the key even takes a different path this time.

I suspect that maybe the internal state of the outline view or underlying NSTableView is mixed up...

How can I troubleshoot this from here? Which steps does the outline view take to determine if a row can be edited after the Return key was pressed?

Update

I did some more debugging (thanks to @Willeke for the tip about the breakpoint). I managed to tack it down to this:

  • Return key is pressed
  • NSOutlineView.keydown
  • ...
  • NSOutlineView.selectedRow
    • outline view checks which row is selected
  • NSOutlineView.rowView(atRow row: Int, makeIfNecessary: Bool)
    • outline view retrieves the selected row view
  • NSTableRowView.nextValidKeyView
    • current row view is asked for the next valid key view
  • NSTableRowView.nextKeyView
    • Now this returns sometimes nil and the app just beeps. Most of the time it returns the NSTableCellView for that row containing the NSTextField that is then made first responder and hence editable.

Now the question is why is the next key view nil sometimes? I click on the outline view's row so it does have the focus/is selected...

Mark
  • 6,647
  • 1
  • 45
  • 88
  • Set a breakpoint on the methods in backtrace #1 to check which one isn't called. Step through the last method that is called (`-[NSTableView _viewBasedAttemptToPerformClickOnViewOfClass:]`?) to find out where it fails. What's special about `FileNameTextField`? Is this question related to [NSOutlineView row not editable by “Return” key anymore after reloading a different table view cell](https://stackoverflow.com/questions/60397648/nsoutlineview-row-not-editable-by-return-key-anymore-after-reloading-a-differe)? – Willeke Apr 21 '20 at 21:23
  • @Willeke Thanks for your tip. My assembly is a bit rusty but I managed to track it down to `nextKeyVew`. I updated the question. About `FileNameTextField`: nothing too special. It selects the base name of a file name without the extension. The bug occurs even if I comment out all special behavior. – Mark Apr 22 '20 at 12:32
  • Is the cell view replaced when `NSTableRowView.nextKeyView` returns `nil`? – Willeke Apr 22 '20 at 13:15
  • No, not as far as I can tell. The item is a child item of a folder item. I can reproduce the problem like this: 1) programmatically select item, 2) programmatically select another item, 3) programmatically select the first item, 4) click on the first item & press Return key → beeps. If I perform step 4) right after step 1) it works just fine. My selection process does this: calls `NSOutlineView.expandItem()` for all parent items + call `selectRowIndexes(itemRow)` + `scrollRowToVisible(itemRow). – Mark Apr 23 '20 at 16:49
  • I noticed thatt the key view loop of the row view isn't always updated when the cell view is replaced by another one (from the reuse queue). Possible fix: subclass `NSTableRowView`, override `nextValidKeyView` and return the first focusable control in the row. – Willeke Apr 23 '20 at 22:30
  • Great, subclassing `NSTableRowView` did the trick! Thank you very much! Would you like to add your workaround as answer so that I can mark it as accepted (so you get proper credit for it)? – Mark Apr 29 '20 at 09:25

0 Answers0