How to find NSOutlineView row index when using NSTreeController - cocoa

I'm using an NSTreeController to manage nodes for an NSOutlineView. When the user adds a new item, I create a new object and insert it:
EntityViewEntityNode *newNode = [EntityViewEntityNode nodeWithName:#"New entity" entity:newObject];
// Insert at end of group
//
NSIndexPath *insertAt = [pathOfGroupNode indexPathByAddingIndex:[selected.children count]];
[entityCollectionTreeController insertObject:newNode atArrangedObjectIndexPath:insertAt];
Now I'd like to open the table column for edit so the user can name the new item. This seems logical:
NSInteger row = [entityCollectionOutlineView rowForItem:newNode];
[entityCollectionOutlineView editColumn:0 row:row withEvent:nil select:YES];
However, row is always -1 indicating the object isn't found. Poking around reveals that the tree controller is not actually putting my objects directly in the tree, but is wrapping them in a node object of its own.
Anyone have insight into how I would go about getting a row index relative to the outline view, so I can do this (without, hopefully, enumerating everything in the outline view and figuring out the mapping back to my node?)

When you insert a new node it gets selected automatically in the outline view. So you can get the proper row by using...
NSInteger selectedRow = [entityCollectionOutlineView selectedRow];

Related

Row animations for NSTableView with Bindings

I have an NSTableView which uses an array controller as binding to a dynamic array and it works great.
Now I realized that when I am appending / inserting an element to the array the row is directly added to the table view without the row insert animation. When I am often adding elements to the array the table view looks weird due to the missing animation.
Is there any "official" way or workaround to get the row animations when I am inserting or removing an element of the dynamic array?
I know this questions is pretty old, but I ran into a similar issue when trying to animate an insertion within a NSTableView which uses bindings. This is what I ended up doing:
Unbind the array controller from the tableview content.
Insert the new object into the array controller (without unbinding first this would automatically insert it into the tableview without animation).
Animate the tableview insertion.
Re-bind the array controller to the tableview content.
// insertIndex and objectToInsert established earlier
[self.myTableView unbind:NSContentBinding];
[self.myArrayController insertObject:objectToInsert atArrangedObjectIndex:insertIndex];
[NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull context) {
[self.myTableView insertRowsAtIndexes:[NSIndexSet indexSetWithIndex:insertIndex] withAnimation:NSTableViewAnimationSlideDown];
} completionHandler:^{
[self.myTableView bind:NSContentBinding toObject:self.myArrayController withKeyPath:#"arrangedObjects" options:#{NSRaisesForNotApplicableKeysBindingOption : #(YES)}];
}];

How to expand table view cell and show content beneath it?

I want to have the table view cell expand and show the buttons that I have laid out below the visible view when the cell isn't selected. So far I have managed to expand the cell so that the entire view shows with the buttons, but there is one major problem with this....
The buttons that are supposed to be revealed only when the cell is selected always appear in the table, and the table view looks really weird becuase for each cell there are buttons overlapping the next cell which were supposed to be hidden!
I have tired making a subclass of the cell, but I am stuck because when I override the setSelected method to show the button, all the buttons from all the cells show up, not just the one I clicked, Ill provide my code below.
I there an easier way to show the buttons without using a subclass? And if not how could I use the subclass in a way that wouldn't show all the buttons for all the cells?
Cell Subclass (.m file)
- (void)awakeFromNib {
// Initialization code
editHidden.hidden = YES;
removeHidden.hidden = YES;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
editHidden.hidden = NO;
removeHidden.hidden = NO;
// Configure the view for the selected state
}
Your table view delegate needs to implement tableView:heightForRowAtIndexPath:. Implement this method to return the correct height for your cell given the state that it is in (collapsed or expanded). When it comes time to expand your cell you should update your state and call [tableView beginUpdates]; [tableView endUpdates]; to have it recalculate and relayout the tableview.

Tell an Array Controller to refresh the table view after the array is edited?

Thanks for reading:
I've gotten stuck on this problem before and I know there is a solution, but after a a few hours of searching I haven't been able to find it again.
I'm using an NSForm and an "Add" button to create a new instance of a student and add that student to an array (sessionRoster). No problems here.
- (IBAction)addNewStudentButtonPressed:(id)sender {
//CREATE NEW STUDENT
Student *newStudent = [[Student alloc] init];
//ASSIGN VALUES FROM FORM
newStudent.firstName = [[studentForm cellAtIndex:0] stringValue];
newStudent.lastName = [[studentForm cellAtIndex:1] stringValue];
//ADD STUDENT TO ROSTER
[sessionRoster addObject:newStudent];
//CLEAR FORM
[[studentForm cellAtIndex:0] setStringValue:#""];
[[studentForm cellAtIndex:1] setStringValue:#""];
}
I'm using an Array controller to display the array in a tableview. No problems here. I have the bindings correct, because I've included some "dummy" students in the init, and they appear when the program is run (I wanted to post the screenshot, but I don't have enough reputation).
My question is, how can I make the table update each time the "add" button is pressed?
I do have the table as a property, and calling [tableView reloadData] doesn't work. I believe the solution before was some kind of "contentWillUpdate:YES" and "contentDidUpdate:YES" pairing, but I can't find that information again.
Thanks for your time!
J
Add the student object to the arrayController not to the array. The array controller "does the lifting."

Tableview custom row names

I am making an app where I'll have a tableview with an 'add' button in the navigation bar, and this 'add' button creates a new row, but the problem is I can't figure out how to give rows unique names. To let the user decide the name, I have included an alert with a plain text field. The user should then write the name in the field and the new row will then be called that. But how do I do that?
I have used the tableview template provided in Xcode, which give each row a new name according to the clock they added a new row. I'll just want a alert to pop up first and then let the user type the name for the new row.
You have to identify each row somehow. One way is to use the index in the table as the identifier. I guess your adding the row to a NSArray which is mapped to the table rows or something similar, so you know the index of the new row. You only have to update the row of that index using this method on your UITableView:
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath
Assuming you have only one section, your array is called 'arrayWithRowsData' and you put the new row at the end, you can create the index path with:
int newRowIndex = [arrayWithRowsData count] - 1;
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:newRowIndex inSection:0];
Hope it helps.

NSTableView rowViewAtRow: always returning nil

I'm trying to display an NSPopover with additional information to a selected row of an NSTableView. For that I need to get a reference to the view representation of the selected row so I can "attach" my popover to it:
NSInteger row = [[self membersTableView] selectedRow];
NSTableRowView *aView = [[self membersTableView] rowViewAtRow: row makeIfNecessary: YES];
[self setQuickLookPopoverController: [QuickLookPopoverController showPopoverFor: anObject at: aView]];
In the above, the result of aView is always nil. According to Apple documentation, this is the method to obtain a view object, given a selected row. Especially the last sentence of the discussion is a bit weird:
Discussion This method will first attempt to return a currently
displayed view in the visible area. If there is no visible view, and
makeIfNecessary is YES, a prepared temporary view is returned. If
makeIfNecessary is NO, and the view is not visible, nil will be
returned.
In general, makeIfNecessary should be YES if you require a resulting
view, and NO if you only want to update properties on a view only if
it is available (generally this means it is visible).
An exception will be thrown if row is not within the numberOfRows. The
returned result should generally not be held onto for longer than the
current run loop cycle. It is better to call
rowViewAtRow:makeIfNecessary: whenever a view is required..
Why is this method always returning nil?
Solved it. I used NSTableView's method (NSRect) rectOfRow: (NSInteger) rowIndex which will give the frame of the required row.
Thanks for showing me the right direction, I had the same problem! I ended up doing the following, but note that I disabled selection of empty rows and that the following code is inside an IBAction:
[popOver showRelativeToRect:[sender bounds]
ofView:[sender rowViewAtRow:[sender selectedRow]
makeIfNecessary:YES]
preferredEdge:NSMaxXEdge];

Resources