tags:

views:

108

answers:

1

Is there any way to prevent the NSTokenField to select everything when pressing the ENTER key or when making to the first responder maybe using the TAB key?

+2  A: 

An NSTokenField is a subclass of NSTextField. There's no easy, direct way to directly manipulate the selection of these classes (aside from -selectText:, which selects all).

To do this when it becomes the first responder, you'll need to subclass NSTokenField (remember to set the class of the field in your XIB to that of your custom subclass) and override -becomeFirstResponder like so:

- (BOOL)becomeFirstResponder
{
    if ([super becomeFirstResponder])
    {
        // If super became first responder, we can get the
        // field editor and manipulate its selection directly
        NSText * fieldEditor = [[self window] fieldEditor:YES forObject:self];
        [fieldEditor setSelectedRange:NSMakeRange([[fieldEditor string] length], 0)];
        return YES;
    }
    return NO;
}

This code first looks to see if super answers "yes" (and becomes the first responder). If it does, we know it will have a field editor (an NSText instance), whose selection we can directly manipulate. So we get its field editor and set its selected range (I put the insertion point at the end with a { lastchar, nolength } range).

To do this when the field is done editing (return, tabbing out, etc.), override -textDidEndEditing: like this:

- (void)textDidEndEditing:(NSNotification *)aNotification
{
    [super textDidEndEditing:aNotification];
    NSText * fieldEditor = [[self window] fieldEditor:YES forObject:self];
    [fieldEditor setSelectedRange:NSMakeRange([[fieldEditor string] length], 0)];
}

In this case, when the user ends editing, this method lets super do its thing, then it looks to see if it's still the first responder. If it is, it does the same as above: puts the insertion carat at the end of the field.

Note, this behavior is not standard and is unexpected. Use sparingly.

Joshua Nozzi
Thanks Joshua, that works! But what about the behavior when pressing ENTER. Trying to override the 'keyDown:' doesn't work. Any idea to disable this behavior?
Robert
I updated the answer with the -textDidEndEditing: case. Since both methods end up calling the same thing, it starts to look like a job for refactoring. I would pull out the field editor code into its own method (like -adjustSelection) and call that to make the code more readable and less repetitive.
Joshua Nozzi
The textDidEndEditing: case isn't working correctly for me. Lets say a set the text cursor after the last token and don't start typing anything characters but simply click RETURN. Is this case all tags are selected even though I added your textDidEndEditing: proposal. Any ideas why?
Robert
Seems if the token field is the only thing in the window to accept first responder, it won't resign it. I tested the code with another text field so I could test tabbing out and back. Remove the if statement so the field editor is always manipulated. Seems to work alright.
Joshua Nozzi
I added a downloadable, drop-in class here: http://joshua.nozzi.name/source/nonselectingtokenfield/
Joshua Nozzi
Don't forget to accept answers that work.
Joshua Nozzi