When a new item is created in the NSOutlineView, I would like to have the item selected and editable, I'm currently using the following code within my NSOutlineview delegate/datasource, the new item is created, however it isn't focused/ editable.
NSWindow *w = [[self outlineView] window];
BOOL endEdit = [w makeFirstResponder:w];
if (!endEdit) {
return;
}
NSUInteger row = [[self outlineView] rowForItem:newGoal];
[[self outlineView] scrollRowToVisible:row];
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:row];
[[self outlineView] selectRowIndexes:indexSet byExtendingSelection:NO];
[[self outlineView] editColumn:0
row:row
withEvent:nil
select:YES];
NSError *anyError = nil;
BOOL success = [[self myContext] save:&anyError];
if (!success) {
NSLog(@"Error = %@", anyError);
}
My complete file is
//
// SBOutlineViewController.m
// Allocator
//
// Created by Cory Sullivan on 2013-04-21.
//
//
#import "SBOutlineViewController.h"
#import "SBAppDelegate.h"
@interface SBOutlineViewController ()
@end
NSString * const SBOutlineSelectionChangedNotification = @"SBSelectionChanged";
@implementation SBOutlineViewController
- (void)awakeFromNib
{
[self setTopLevelItems:[NSArray arrayWithObjects:@"Retirement", @"Education", nil]];
[self setMyContext:[[NSApp delegate] managedObjectContext]];
[self updateOutlineView];
}
- (void)updateOutlineView
{
NSFetchRequest *myRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *goalEntity = [NSEntityDescription entityForName:@"Goal" inManagedObjectContext:[self myContext]];
[myRequest setEntity:goalEntity];
NSError *anyError = nil;
[self setGoalItems:[[self myContext] executeFetchRequest:myRequest error:&anyError]];
NSMutableArray *retirementArray = [[NSMutableArray alloc] init];
NSMutableArray *educationArray = [[NSMutableArray alloc] init];
for (NSManagedObject *goalObject in [self goalItems]) {
if ([[goalObject valueForKey:@"goalType"] isEqual: @"Retirement"]) {
[retirementArray addObject:goalObject];
} else {
if ([[goalObject valueForKey:@"goalType"] isEqual:@"Education"]) {
[educationArray addObject:goalObject];
}
}
}
[self setMyOutlineDictionary:[[NSMutableDictionary alloc] initWithObjectsAndKeys:retirementArray, @"Retirement", educationArray, @"Education", nil]];
[[self outlineView] reloadData];
}
#pragma mark - Delegate and DataSoure Methods
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
return [[self _childrenForItem:item] objectAtIndex:index];
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
if ([outlineView parentForItem:item] == nil) {
return YES;
} else {
return NO;
}
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item
{
if ([outlineView parentForItem:item] == nil) {
return NO;
} else {
return YES;
}
}
- (NSInteger) outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
return [[self _childrenForItem:item] count];
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item {
return [_topLevelItems containsObject:item];
}
- (void)outlineViewSelectionDidChange:(NSNotification *)notification {
if ([_outlineView selectedRow] != -1) {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc postNotificationName:SBOutlineSelectionChangedNotification object:self];
}
}
- (NSArray *)_childrenForItem:(id)item {
NSArray *children;
if (item == nil) {
children = _topLevelItems;
} else {
children = [_myOutlineDictionary objectForKey:item];
}
return children;
}
- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
NSTableCellView *view = nil;
if ([_topLevelItems containsObject:item]) {
view = [outlineView makeViewWithIdentifier:@"HeaderCell" owner:self];
NSString *value = [item uppercaseString];
[[view textField] setStringValue:value];
return view;
} else {
view = [outlineView makeViewWithIdentifier:@"DataCell" owner:self];
[[view imageView] setImage:[NSImage imageNamed:NSImageNameActionTemplate]];
NSManagedObject *goalItem = [_goalItems objectAtIndex:[_goalItems indexOfObject:item]];
[[view textField] setStringValue:[goalItem valueForKey:@"goalName"]];
return view;
}
}
#pragma mark - Custom Actions
- (IBAction)goalActionPullDown:(id)sender
{
[self modifyGoalItems: [[sender selectedItem] tag]];
}
- (void)modifyGoalItems:(NSInteger)whichMenuTag
{
if (whichMenuTag == 5) {
NSAlert *alert = [NSAlert alertWithMessageText:@"Are you sure you want to delete goal and all related accounts?"
defaultButton:@"Remove"
alternateButton:@"Cancel"
otherButton:nil
informativeTextWithFormat:@"This can't be undone"];
[alert beginSheetModalForWindow:[_outlineView window]
modalDelegate:self
didEndSelector:@selector(alertEnded:code:context:)
contextInfo:NULL];
} else {
NSManagedObject *newGoal = [NSEntityDescription insertNewObjectForEntityForName:@"Goal" inManagedObjectContext:[self myContext]];
switch (whichMenuTag) {
case 1:
{
[newGoal setValue:@"New Goal" forKey:@"goalName"];
[newGoal setValue:@"Retirement" forKey:@"goalType"];
[self updateOutlineView];
}
break;
case 2:
{
[newGoal setValue:@"New Goal" forKey:@"goalName"];
[newGoal setValue:@"Education" forKey:@"goalType"];
[self updateOutlineView];
}
break;
case 3:
NSLog(@"You selected Item number 3");
break;
case 4:
NSLog(@"You selected Item number 4");
break;
default:
break;
}
NSWindow *w = [[self outlineView] window];
BOOL endEdit = [w makeFirstResponder:w];
if (!endEdit) {
return;
}
NSUInteger row = [[self outlineView] rowForItem:newGoal];
[[self outlineView] scrollRowToVisible:row];
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:row];
[[self outlineView] selectRowIndexes:indexSet byExtendingSelection:NO];
[[self outlineView] editColumn:0
row:row
withEvent:nil
select:YES];
NSError *anyError = nil;
BOOL success = [[self myContext] save:&anyError];
if (!success) {
NSLog(@"Error = %@", anyError);
}
}
}
- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
return YES;
}
- (void)alertEnded:(NSAlert *)alert
code:(int)choice
context:(void *)v
{
if (choice == NSAlertDefaultReturn) {
NSManagedObject *selectedGoal = [[self outlineView] itemAtRow:[[self outlineView] selectedRow]];
[[self myContext] deleteObject:selectedGoal];
NSError *anyError = nil;
BOOL success = [[self myContext] save:&anyError];
if (!success) {
NSLog(@"Error = %@", anyError);
}
[self updateOutlineView];
}
}
@end
Any attempt to do make the field editable within the current pass through the run loop will fail. What you need to do is to cue the selection up for the next time around the loop. Something like this:
[self performSelector:@selector(selectText:) withObject:textField afterDelay:0];
You might want to do something other than selectText on a textfield, but the technique is what you need.