Pregunta

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
¿Fue útil?

Solución

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top