Re: custom view binding to NSTreeController
Re: custom view binding to NSTreeController
- Subject: Re: custom view binding to NSTreeController
- From: Rob Keniger <email@hidden>
- Date: Thu, 4 Dec 2008 15:46:39 +1000
On 03/12/2008, at 11:51 AM, Matthew Johnson wrote:
I am creating a custom view which I would like to bind to
NSTreeController. I have tried observing both [treeController
arrangedObjects] and [[treeController arrangedObjects] childNodes].
Both seem to only notify that a change has occurred and do not
provide any details about the change (insertion, removal, etc). If
this is the case, you would have to walk the entire tree every time
a change happens in order to detect changes. This seems like a
pretty bad idea. There must be a better way to do this.
Not as far as I know, there's a bit of manual work in implementing
this. I'd love to hear if anyone has a better way to do it.
I am hoping somebody can share an example of how to implement the
observation necessary to create a custom view that binds to
NSTreeController. Does anybody have sample code? Is anyone able to
provide a high level idea of how NSOutlineView and NSBrowser do
this? Is it even possible to do this efficiently with public API?
You can definitely do it as I am doing it at present, although you can
only do it in 10.5+ as NSTreeController is horribly broken in 10.4.
Here is some code, edited in mail:
@implementation NSTreeController (Additions)
//returns a flattened array of all the "real" objects in the tree.
//We use this to handle registration and deregistration of observers
of the objects that are being managed
-(NSArray *) treeNodesAsArray:(NSArray*)nodes
{
NSMutableArray* theObjectArray=[NSMutableArray array];
for(NSTreeNode *node in nodes)
{
[theObjectArray addObject:[node representedObject]];
if([[node childNodes] count])
{
[theObjectArray addObjectsFromArray:[self treeNodesAsArray:[node
childNodes]]];
}
}
return theObjectArray;
}
-(NSArray*) representedObjects
{
if([self childrenKeyPath]==nil)
return nil;
NSArray* arrangedObjects=[self arrangedObjects];
if(arrangedObjects==nil)
return nil;
NSArray* childNodes=[[self arrangedObjects]childNodes];
if(childNodes==nil)
return nil;
return [self treeNodesAsArray:childNodes];
}
@end
Then, in your controller:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context
{
if (context == MyObservationContext)
{
NSArray *items = [treeController representedObjects];
//if there has been no change, don't do anything
if([items isEqualToArray:self.oldItems])
return;
//get the items that have been added to the array
NSMutableArray *newItems = [items mutableCopy];
[newItems removeObjectsInArray: self.oldItems];
NSMutableArray *removedItems = [self.oldItems mutableCopy];
[removedItems removeObjectsInArray:items];
//stop observing the removed items
[self stopObservingOldItemProperties:removedItems];
//start observing the new items
[self startObservingNewItemProperties:newItems];
//store the current array of items as the old array so we can
compare it next time
self.oldItems=items;
//do whatever UI adjustments you need to do
}
--
Rob Keniger
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden