[NSOutlineView / SourceList] How to prevent control-click on group items?

Let's say you have a NSOutlineView configured as a source list.

The data source provides items and group items.

There is a NSMenu set for the menu property of the NSOutlineView.

The group items rows are not selectable.


Problem:


When a group item is control-clicked or right-clicked, its row gets highlighted (bold blue rounded rect) and the contextual menu is displayed.


Question:


Is there a simple way to prevent this from happenning? To ge the same kind of behavior you see with the Finder sidebar or Calendar sidebar.


Attaching the NSMenu to the NSTableCellView does not work.

Attaching the NSMenu to the NSTableRow does not work.


Notes:


I haven't seen so far a simple solution. I've seen non simple solutions involving subclassing NSOutlineView and filtering the mouse down events that somehow requires the NSOutlineView subclass to know about the model.

I don't know, but I think there are two parts to this:


1. The reason there's no clicked-row highlighting in the Finder for the group items is — I would assume — that it's a group item. Your group items must say (via the outline view delegate) that they're group items. Did you do that?


2. The reason there's no menu is — I would assume — that the menu is dynamically configured depending on what's clicked, and the menu is emptied of menu items for group rows. (In Calendar, one of the group headers does pop up a menu, but there's no row highlighting.) According to the Table View Programming Guide:


developer.apple.com/library/content/documentation/Cocoa/Conceptual/TableView/RowSelection/RowSelection.html#//apple_ref/doc/uid/10000026i-CH6-SW4


you can customize the menu by setting a menu delegate and implementing menuWillOpen: to customize what's displayed.


I would start with part 2 of this, customizing the menu depending on which row was right-clicked. Possibly, if the menu has no items, the highlighting won't be shown, and part 1 will be taken care of too.

1. Yes. The delegate method is implemented. And the look of the group item and the presence of the Show | Hide switch button confirm it's working.


2. Regarding the menuWillOpen: delegate method. You should not believe what the documentation says:


Problem ID# 30546694: [NSMenu Documentation] Left hand doesn't know what the right hand is doing


https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/TableView/RowSelection/RowSelection.html


says the opposite of:


https://developer.apple.com/reference/appkit/nsmenudelegate/1518156-menuwillopen?language=objc


As I don't know which document is telling the truth, I stopped considering this a possible solution when I was investigating this problem.



Solution


But your idea about changing the contents of the menu reminded me about the - (NSMenu *)menuForEvent:; method. I had tried to subclass NSOutlineView and override this method. But I had given up using it as the clicked row is not set when this method is called, therefore finding out whether the item at the clicked row was a group one seemed not possible.


Actually, it's possible to figure out, it just requires to inspect the NSEvent * parameter and check whether the row at locationInWindow for a NSRightMouseDown event type is a group item according to the delegate. And, in this case, returning nil for the menu prevents the highlight and the menu from appearing.


- (NSMenu *)menuForEvent:(NSEvent *)inEvent {
  if (inEvent.type==NSRightMouseDown) {
    NSPoint tPoint=[self convertPoint:inEvent.locationInWindow fromView:nil];

    NSInteger tClickedRow=[self rowAtPoint:tPoint];

    if (tClickedRow!=-1) {
      id tItem=[self itemAtRow:tClickedRow];

      if ([self.delegate outlineView:self isGroupItem:tItem]==YES)
        return nil;
    }
  }

  return [super menuForEvent:inEvent];
}
[NSOutlineView / SourceList] How to prevent control-click on group items?
 
 
Q