Historically the specification of tokens to be used in custom strings such as file names and report generation was just to use some special character such as ‘%’ or ‘@’ and pair it with some more ore less cryptic token to specify the kind of the replacement, e.g.: ‘%d.4′ or ‘%User’ and other variants such as ‘@day@’.
Of course this is not what today’s end users, especially on Apple Mac OS X want to see. I was already thinking how to make this more comfortable in one ouf our Mac products and with Adobe’s recent Lightroom demo I got an inspiration: Basically they use what Apple introduced with Apple Mail’s address field, rounded visual tokens you can inserted and drag around easily. So I set out to implement this using the NSTokenField, new in OS X 10.4, however I had to find out making it behave as wanted was not as easy as I hoped. One needs quite some Cocoa and ObjC experience to implement normal text intermixed with those rounded tokens and Google was quite sparse on on details and thus I decided to document the details here:
Note I’m not a Cocoa guru - feel free to comment suggestions and improvements!
Of course introducing it in your UI just means dropping it ouf of the Interface Builder’s toolbox into your project. The difficulties begin when you want to control the appearance of the tokens and display some as ordinary text.
For this you need to create your own class and add it to the NSArray that the NSTokenFieldCell uses to hold the tokens. Furthermore you need to define a delegate for the NSTokenField so that this delegate can respond to requests such as:
- (NSString *)tokenField:(NSTokenField *)tokenField displayStringForRepresentedObject:(id)representedObject
and
- (NSTokenStyle)tokenField:(NSTokenField *)tokenField styleForRepresentedObject:(id)representedObject
so you gain control about the formating of the individual tokens and the ordinary text parts can get the default NSPlainTextTokenStyle and you can return NSRoundedTokenStyle as well as the display text for your custom tokens.
When you want a context menu for your tokens you furthermore need to implement:
- (BOOL)tokenField:(NSTokenField *)tokenField hasMenuForRepresentedObject:(id)representedObject
as well as:
- (NSMenu *)tokenField:(NSTokenField *)tokenField menuForRepresentedObject:(id)representedObject
and to allow drag’n drop of your precious tokens your class need to adhere to the NSCoding protocol and implement:
- (void)encodeWithCoder:(NSCoder *)encoder
and
- (id)initWithCoder:(NSCoder *)decoder
and though deprecated you must use the old, non-keyed coding and decoding for this drag’n drop code:
In my example code this just was:
[encoder encodeObject:name];
respective:
name = [[decoder decodeObject] retain];
I hope this is a help for other people that want to use the NSTokenField and find the current Apple documentation slightly lacking detail. The full Xcode project is attached below:
TokenFieldTest