Implementing Menus for Tokens

If you want tokens in a token field to have menus, you must implement the tokenField:hasMenuForRepresentedObject: and tokenField:menuForRepresentedObject: delegation methods. A token field invokes the former method just before it displays a token to find out if it should draw a discovery triangle. It invokes the latter method when the user clicks the triangle.

Listing 1 gives a sample implementation of these methods. Note that it sets the token’s represented object as the represented object of the menu item that invokes an action method. The target of the action method fetches the represented object from the menu item to act upon it.

Listing 1  Implementing the menu delegation methods

- (BOOL)tokenField:(NSTokenField *)tokenField hasMenuForRepresentedObject:(id)representedObject {
    return YES;
}
 
- (NSMenu *)tokenField:(NSTokenField *)tokenField menuForRepresentedObject:(id)representedObject {
 
    NSMenu *tokenMenu = [[[NSMenu alloc] init] autorelease];
 
    if (![representedObject exists])
        return nil;
 
    NSMenuItem *artistItem = [[[NSMenuItem alloc] init] autorelease];
    [artistItem setTitle:[representedObject artist]];
    [tokenMenu addItem:artistItem];
 
    NSMenuItem *albumItem = [[[NSMenuItem alloc] init] autorelease];
    [albumItem setTitle:[NSString stringWithFormat:@"Album: %@", [representedObject album]]];
    [tokenMenu addItem:albumItem];
 
    NSMenuItem *durationItem = [[[NSMenuItem alloc] init] autorelease];
    [durationItem setTitle:[NSString stringWithFormat:@"Time: %@", [representedObject time]]];
    [tokenMenu addItem:durationItem];
 
    NSMenuItem *mItem = [[[NSMenuItem alloc] initWithTitle:@"Show Album Art" action:@selector(showAlbumArt:) keyEquivalent:@""] autorelease];
    [mItem setTarget:self];
    [mItem setRepresentedObject:representedObject];
    [tokenMenu addItem:mItem];
 
    return tokenMenu;
}