views:

68

answers:

1

The Background

I've built a source list (similar to iTunes et al.) in my Cocoa app.

  • I've got an NSOutlineView, with Value column bound to arrangedObjects.name key path of an NSTreeController.

  • The NSTreeController accesses JGSourceListNode entities in a Core Data store.

  • I have three subclasses of JGSourceListNode - JGProjectNode, JGGroupNode and JGFolderNode.

  • I have selectedIndexPaths on NSTreeController bound to an NSArray called selectedIndexPaths in my App Delegate.

On startup, I search for group nodes and if they're not found in the core data store I create them:

if ([allGroupNodes count] == 0) {
    JGGroupNode *rootTrainingNode = [JGGroupNode insertInManagedObjectContext:context];
    [rootTrainingNode setNodeName:@"TRAIN"];

    JGProjectNode *childUntrainedNode = [JGProjectNode insertInManagedObjectContext:context];
    [childUntrainedNode setParent:rootTrainingNode];
    [childUntrainedNode setNodeName:@"Untrained"];

    JGGroupNode *rootBrowsingNode = [JGGroupNode insertInManagedObjectContext:context];
    [rootBrowsingNode setNodeName:@"BROWSE"];

    JGFolderNode *childFolder = [JGFolderNode insertInManagedObjectContext:context];
    [childFolder setNodeName:@"Folder"];
    [childFolder setParent:rootBrowsingNode];

    [context save:nil];
}

What I Want

When I start the app, I want both top level groups to be expanded and "Untrained" to be highlighted as shown:

My Window

The Problem

I put the following code in the applicationDidFinishLaunching: method of the app delegate:

[sourceListOutlineView expandItem:[sourceListOutlineView itemAtRow:0]];
[sourceListOutlineView expandItem:[sourceListOutlineView itemAtRow:2]];
NSIndexPath *rootIndexPath = [NSIndexPath indexPathWithIndex:0];
NSIndexPath *childIndexPath = [rootIndexPath indexPathByAddingIndex:0];
[self setSelectedIndexPaths:[NSArray arrayWithObject:childIndexPath]];

but the outline view seems to not have been prepared yet, so this code does nothing.

Ideally, eventually I want to save the last selection the user had made and restore this on a restart.

The Question

I'm sure it's possible using some crazy KVO to observe when the NSTreeController or NSOutlineView gets populated then expand the items and change the selection, but that feels clumsy and too much like a work around.

How would I do this elegantly?

+1  A: 

Elegantly? This isn't elegant but it's how I'm doing it. I just do it manually. At app quit I write this value to user defaults:

lastSelectedRow = [outlineView selectedRow]

Then at app launch I run this in app did finish launching:

[self performSelector:@selector(selectLastNoteOrCreateDefaultNote) withObject:nil afterDelay:1];

Notice I just use a delay because I noticed the same as you that "the outline view seems to not have been prepared yet". Then in that selector I use this.

[outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:lastSelectedRow] byExtendingSelection:NO];

It works but better (more elegant) solutions are welcome from me too.

regulus6633
You should probably set the delay to `0`, which will send the message in the next iteration of the event loop without there being a visible "delay".
Rob Keniger
Hey Rob, that did work. I'm surprised but I guess it just needed to wait for the next event loop as you mentioned... and of course a 0 delay is better/faster. Thanks.
regulus6633