Aperture SDK and NSTableView

Problem: Making a plugin for Aperture in which I have a table containing a series of on/off values
Problem: The On/Off values are actually not “On” and “Off” but vary from line to line
Problem: Although I’m probably the last person running an OS X 10.4 as operational system, the Aperture SDK is 10.4
Problem: The function that would allow me to have a different cell for each line ( dataCellForTableColum: ) is 10.5+

Banging my head against the wall did not produce good results (in that department anyway). Looking up mailing lists questions and forums have yielded a lot of interesting solutions, none of which actually worked in my particular case (among other things, setting up an NSMenuDelegate — the problem with that is does not change the menu in its collapsed state, only when selecting items from it –, subclassing NSPopupButtonCell, with all the headache of passing data to and fro — the problem with that is a massive flux of memory allocations and reallocations which yields in most cases to a crash, even when I don’t autorelease anything –, or duplicating the menu over and over again — which doesn’t work, because on 10.4 the cells are not copies… they are all the same, refreshed for every line –, etc… ).

In the end, the solution is not particularly elegant for me, but it works, and is within the boundaries of whatever philosophy holds the NSTableView of 10.4 together : fresh menu, every time.

Basic setup:
An NSTableView with a column in which the datacell is an NSPopupButtonCell. Mine has the identifer “value” (as opposed to “name”).
A table view delegate that knows what the values for this line should be (for On and Off), and capable of producing an NSArray with the two values (here called “bitsValues”) using a function names “getBitValuesForRow:(int)”

The code goes in the function willDisplayCell:

- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
  if([@"value" compare:[tableColumn identifier]] == NSOrderedSame) { // right column
    if ([cell isKindOfClass:[NSPopUpButtonCell class]]) { // right type of cell -- you never know
      NSArray *bitsValues = [self getBitValuesForRow:row];
 
      if(bitsValues != nil && [bitsValues count] == 2) {
        // don't forget that, otherwise, your menus will snap back to item 0
        int indexOfSelection = [cell indexOfSelectedItem];
        [cell setMenu:[[[NSMenu alloc] init] autorelease]];
        NSMenuItem *item = [[NSMenuItem alloc]
                initWithTitle: [bitsValues objectAtIndex:0]
                action:nil
                keyEquivalent:@""];
        [item setTarget:nil];
        [[cell menu] addItem:[item autorelease]];
        item = [[NSMenuItem alloc]
                initWithTitle: [bitsValues objectAtIndex:1]
                action:nil
                keyEquivalent:@""];
        [item setTarget:nil];
        [[cell menu] addItem:[item autorelease]];
        [cell selectItemAtIndex:indexOfSelection]; // see above
    }
  }
 }
}

As far as I know it works well, without any leak and with the intended results.

Enjoy, and as usual, let me know if it’s useful to any of you fellow coders out there.

  

Leave a Reply