Configuring a NSToolbar

Introduced with Leopard was Interface Builder 3 (IB3), which finally included support to include NSToolbar design in nib (or xib – the new trendy format) files.

Yes. But.

Following Apple documentation, I added a NSToolbar instance to my document window, and customized it with some NSToolbarItems. As expected, it works great, my toolbar items have custom icons and calls the specified action.

The problem occurred as I wanted to make some of these items “selectable” – meaning they would have a mode-selection behavior. The thing is IB3 doesn’t provide a way to set this property in its interface. The way to do this is to specify a delegate for the toolbar and override

- (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar;

The name of this method is pretty much self explanatory, but I hadn’t specified any item identifiers for my custom toolbar items in IB, because this essential property is nowhere to be found ! Looking at the xib file directly in a text editor, it looks like IB generates a hash-code for each custom toolbar item to use as its identifier. This makes it impossible (or at least darn difficult) to programmatically retrieve or use these items.

In the end I had to configure manually my toolbar’s content by loading a plist file which did more or less the work of the xib file : hold the configuration of my toolbar, but allowing me to specify which items were selectable. And it works great, except that I can’t visualize the content of my toolbar at design-time.

Now I have one more question to ask the Apple engineers at WWDC ;-)

You can read some code on the full-post.

Here is the code I use to manage my toolbar, using an external configuration file that is loaded by my environment manager.

@implementation TPTravelController (NSToolbarDelegate)
              
              - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
              {
                  // Retrieve the toolbar items configuration
                  NSDictionary* itemsConfiguration = [[TPEnvironment valueForKey:@"toolbarConfiguration"] valueForKey:@"toolbarItemsConfiguration"];
              
                  if (itemsConfiguration != nil) {
                      // Getting this item configuration using its identifier
                      NSDictionary* itemConfiguration = [itemsConfiguration valueForKey:itemIdentifier];
              
                      if (itemConfiguration != nil) {
                          // Instanciation of the new item
                          NSToolbarItem* item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
                          // Getting the item's icon
                          NSImage* itemIcon = [NSImage imageNamed:[itemConfiguration valueForKey:@"image"]];
                          [item setImage:itemIcon];
                          // Setting labels
                          // TODO : make localizable (move the configuration in a localized plist file ?)
                          [item setLabel:[itemConfiguration valueForKey:@"label"]];
                          [item setPaletteLabel:[itemConfiguration valueForKey:@"palLabel"]];
              
                          // Loading the action
                          NSString* itemAction = [itemConfiguration valueForKey:@"action"];
                          if (itemAction != nil) {
                              // Making a selector out of the action string
                              SEL actionSelector = NSSelectorFromString(itemAction);
                              // Avoiding future problems : the controller has to respond to this action
                              if ([self respondsToSelector:actionSelector]) {
                                  [item setTarget:self];
                                  [item setAction:actionSelector];
                              }
                          }
              
                          return item;
                      }
                  }
              
                  return [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
              }
              
              - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
              {
                  // Loading default items from the environment
                  NSArray* environmentValue = [[TPEnvironment valueForKey:@"toolbarConfiguration"] valueForKey:@"defaultToolbarItems"];
                  if (environmentValue != nil)
                  {
                      return environmentValue;
                  }
                  return [[NSArray alloc] init];
              }
              
              - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
              {
                  // Loading allowed items from the environment
                  NSArray* environmentValue = [[TPEnvironment valueForKey:@"toolbarConfiguration"] valueForKey:@"allowedToolbarItems"];
                  if (environmentValue != nil)
                  {
                      return environmentValue;
                  }
                  return [[NSArray alloc] init];
              }
              
              - (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar
              {
                  // Loading selectable items from the environment
                  NSArray* environmentValue = [[TPEnvironment valueForKey:@"toolbarConfiguration"] valueForKey:@"selectableToolbarItems"];
                  if (environmentValue != nil)
                  {
                      return environmentValue;
                  }
                  return [[NSArray alloc] init];
              }
              
              @end
              
Back