Reputation: 1112
I have an NSTableView (with editable text cells) and a contextual menu. When a row is selected and I right click on a different row, this functionality works as intended (selected row changes to right-clicked row and my contextual menu pops up).
When the currently selected row is right-clicked then the text cell under the mouse changes to edit mode and the contextual menu for text editing (not defined by me) pops up. This is not the intended functionality.
Intended Functionality
It doesn't feel like this should be a difficult problem - perhaps even a problem that could be solved in Interface Builder - but I can't quite work out the solution.
I thought it might be one where I need to validateProposedFirstResponder
, so I added that to the superview - but that didn't work (and, with hindsight, I can see why)
- (BOOL)validateProposedFirstResponder:(NSResponder *)responder forEvent:(NSEvent *)event {
if ([responder isKindOfClass:[NSTextFieldCell class]] || [responder isKindOfClass:[NSTableCellView class]] || [responder isKindOfClass:[NSTextField class]] ) {
return NO;
}
return [super validateProposedFirstResponder:responder forEvent:event];
}
As you can see, I kind of chucked everything at the wall - but the only responder class that it can 'see' being clicked is NSTableView
I guess then (and it feels like a clunky solution), I need to subclass one of NSTextFieldCell, NSTableCellView or NSTextField class and implement validateProposedFirstResponder
there. Can anyone advise me which one though, or propose a better solution?
Upvotes: 0
Views: 77
Reputation: 15633
AppKit determines which view handles the click by calling hitTest:
. Subclass NSTableView
, override hitTest:
and return the table view if the event is a right click.
- (NSView *)hitTest:(NSPoint)point {
if (NSApp.currentEvent.type == NSEventTypeRightMouseDown)
return self;
return [super hitTest:point];
}
Upvotes: 0
Reputation: 1112
@willeke makes a good suggestion (above), but it isn't quite the right solution…
In fact, the solution I used has two parts to it (and I accept that there may be better / more efficient solutions - in which case I'd really like to hear them!)
Part one - subclassing NSTextField
@implementation NSTextField (LCNSTextFieldAdditions)
-(BOOL)validateProposedFirstResponder:(NSResponder *)responder forEvent:(NSEvent *)event {
if ([responder isKindOfClass:[NSTextField class]] && event.type == NSEventTypeRightMouseDown ) {
[[(NSTextField*)responder window] makeFirstResponder:nil];
}
return false;
}
@end
This solves the problem of a right click activating edit mode, so that a right click will now always activate my contextual menu and not the contextual menu for text editing.
Part two - Aborting Edits
There's still a problem if an edit is active when the right click is pressed. The text cells can still be edited, of course, by clicking twice - but if the table is refreshed (one of the options in my contextual menu eventually results in a refresh) whilst edit is active then the application will crash. Therefore edits need to be saved or discarded before the right click.
I did this by calling an abort function in - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
The abort function looks like this…
- (void)abortEditing:(NSTableView *)table {
NSInteger selected = [table selectedRow];
for (int selectedCol=0; selectedCol < table.numberOfColumns; selectedCol++) {
NSTableCellView *selectedRow = [table viewAtColumn:selectedCol row:selected makeIfNecessary:YES];
NSTextField *selectedRowTextField = [selectedRow textField];
[selectedRowTextField abortEditing];
}
}
If anyone has a better solution I'd love to hear it. If not, I hope that this helps anyone else who has the same problem that I was experiencing.
Upvotes: 0