Live Sorting a NSTreeController
Live Sorting a NSTreeController
- Subject: Live Sorting a NSTreeController
- From: Arved von Brasch <email@hidden>
- Date: Sat, 27 May 2006 18:38:01 +1000
Greetings Cocoa Dev List,
Yet another NSTreeController query. Are there any examples out there
for Live Sorting of an NSTreeController?
This problem for me, stems from supporting drag and drop ordering of
items in an NSOutlineView. There are several examples of
implementing CoreData ordering in an NSOutlineView backed by bindings
through an NSTreeController. I have this working fine, and am happy
with it. My problem stems from the being able to undo these
actions. When ordering by drag and drop, a value is changed in the
ManagedObject, and hence the undo manager will be notified and it
will be possible to undo this action. The trouble is that undoing
the action will not cause the OutlineView (or NSTableView, if an
NSArrayController is being used) to be notified, and thus, there will
be no visual feedback to the user that the undo has actually taken
place, until the TableView or OutlineView is resorted.
I see two ways of getting around this problem:
1. Disable undos for drag and drops. Easy to do, but seems a bit of
a cop-out.
2. Establish a means of notification when an undo occurs. This
seems easiest to manage with live sorting.
I'm defining live sorting to be forcing the backing of the TableView
or OutlineView to resort immediately when a change is made.
This is really easy to do with a NSArrayController and NSTableView.
In the NSArrayController subclass, simply add:
- (void)awakeFromNib {
[super awakeFromNib];
// Any other set up code.
[[NSNotificationCenter defaultCenter] addObserver: self selector:
@selector(resortTable:) name: NSControlTextDidEndEditingNotification
object: theTable];
[[NSNotificationCenter defaultCenter] addObserver: self selector:
@selector(resortTable:) name: NSUndoManagerDidUndoChangeNotification
object: [[self managedObjectContext] undoManager]];
[[NSNotificationCenter defaultCenter] addObserver: self selector:
@selector(resortTable:) name: NSUndoManagerDidRedoChangeNotification
object: [[self managedObjectContext] undoManager]];
}
- (void)resortTable: (NSNotification *)notification {
[self rearrangeObjects];
}
You may also need to put a manual rearrange in addObject:, if you
want newly inserted objects to be sorted as well. This should now
behave as expected for undos of drag and drop sorting; namely, the
table will resort after a drag and drop has been undone. For
efficiency, you may want to put in some checks to see what kind of
undo operation was performed, if reloading your table is expensive.
For NSTreeController / NSOutlineView one would expect the situation
to be just as straight forward, but of course it isn't. The first
trouble comes in trying to decide where to add the initial value for
the positioning attribute. The ideal behaviour is for the order that
objects are added to the OutlineView to be remembered. Hence,
setting a default value in the model is not the best solution. It
can't be set in a redefinition of newObject because newObject is not
called through addChild:, and the documentation claims it shouldn't
be called at all. It can't be set in awakeFromInsert of the
ManagedObject, because at that point you don't know if the object is
destined to be a child or a parent. It can't be done simply in add:
or addChild: because I haven't been able to find a reliable method of
returning the newly created item. This is also a problem if you want
to automatically set the editable column of the new row through
editColumn:row:withEvent:select: You can redefine add: and addChild:
completely to create the object and insert it into the
TreeController, which will then let you use editColumn. Doing this,
however, makes it difficult to do the resort trick, because of the
way rearrange seems to be implemented.
insertObject:atArrangedObjectIndexPath: does not seem to always fetch
the newly created object, and calling rearrange will cause add: and
addChild: to occasionally fail.
So it seems that you can have editColumn:row:withEvent:select: or
live sorting but not both. At least, not with NSTreeController.
Another possible solution could be to simulate a double click on a
table header, to resort the table that way. I can't work out an easy
way to actually do this, however.
Does anyone have an ideas on how to support all these issues
simultaneously?
1. Undos cause outline view to resort if the undo affects the
attribute for the current sort descriptor.
2. Live resorting when objects are added and edited.
3. When new entities are added, editing is started immediately in a
specific table column.
Cheers,
Arved
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden