objective-ccocoanstableviewnscell

Mouse tracking with modifier keys in table view cell


I have a NSTextFieldCell in a column of a cell-based NSTableView. This cell should handle clicks. This works fine when no modifier keys are pressed. If I hold the shift or command keys, the table view swallows the mouseDown event in an attempt to handle row selection.

Is there a way to completely disable row selection in NSTableView?

Is there a way to have NSTableView pass through all events?

My cell subclass is derived from the LinkTextFieldCell in the TableViewLinks sample code. It implements:

- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag

Since I don't want row selection, my table view delegate implements:

- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)rowIndex
{
    return NO;
}

- (BOOL)tableView:(NSTableView *)tableView shouldTrackCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
    return YES;
}

My delegate methods are called from -[NSTableView mouseDown:]. The mouse tracking code is called when no modifier keys are pressed.

Is there a better way to fix this than subclassing NSTableView to override -[NSTableView mouseDown:]?


Solution

  • I have implemented a solution where I override mouseDown:. I don't really like it. But it works. Still hoping for better ideas.

    - (void)mouseDown:(NSEvent *)theEvent
    {
        if (! [self handleMouseDown:theEvent]) {
            [super mouseDown:theEvent];
        }
    }
    
    - (BOOL)handleMouseDown:(NSEvent *)theEvent
    {
        NSInteger                   clickCount                  = [theEvent clickCount];
    
        if (clickCount != 1) {
            return NO;
        }
    
        NSPoint                     locationInWindow            = [theEvent locationInWindow];
        NSPoint                     locationInView              = [self convertPoint:locationInWindow fromView:nil];
        NSInteger                   clickedRow                  = [self rowAtPoint:locationInView];
        NSInteger                   clickedColumn               = [self columnAtPoint:locationInView];
    
        if ((clickedRow < 0) || (clickedColumn < 0)) {
            return NO;
        }
    
        if ((clickedRow >= [self numberOfRows]) || (clickedColumn >= [self numberOfColumns])) {
            return NO;
        }
    
        NSArray                     *tableColumns               = [self tableColumns];
    
        NSTableColumn               *tableColumn                = [tableColumns objectAtIndex:clickedColumn];
        NSCell                      *cell                       = [tableColumn dataCellForRow:clickedRow];
    
        id <NSTableViewDelegate>    delegate                    = [self delegate];
        BOOL                        shouldTrackCell             = NO;
    
        if ([delegate respondsToSelector:@selector(tableView:shouldTrackCell:forTableColumn:row:)]) {
            shouldTrackCell = [delegate tableView:self shouldTrackCell:cell forTableColumn:tableColumn row:clickedRow];
        }
    
        if (! shouldTrackCell) {
            return NO;
        }
    
        BOOL                        prefersTrackingUntilMouseUp = [[cell class] prefersTrackingUntilMouseUp];
        NSRect                      cellFrame                   = [self frameOfCellAtColumn:clickedColumn row:clickedRow];
    
        return [cell trackMouse:theEvent inRect:cellFrame ofView:self untilMouseUp:prefersTrackingUntilMouseUp];
    }