// // PWTreeControllerNode.m // PWTreeControllerDemo // // Created by Frank Illenberger on 04.03.06. // Copyright 2006 ProjectWizards, Melle, Germany. // #import "PWTreeControllerNode.h" #import "PWTreeController.h" #import "PWTreeController-Private.h" #import "PWObservationInfo.h" #define PWTreeControllerSubNodesChangeContext @"PWTreeControllerSubNodesChange" #define PWTreeControllerIsLeafChangeContext @"PWTreeControllerIsLeafChange" @implementation PWTreeControllerNode - (id)initWithTreeController:(PWTreeController *)controller observedObject:(id)object parentNode:(PWTreeControllerNode *)parent { [super init]; treeController = controller; parentNode = parent; observedObject = [object retain]; CFDictionarySetValue(treeController->nodesForObjects, observedObject, self); if(treeController->childrenKeyPath) { [observedObject addObserver:self forKeyPath:treeController->childrenKeyPath options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:PWTreeControllerSubNodesChangeContext]; isObservingSubNodes = YES; } if(treeController->isLeafKeyPath) { [observedObject addObserver:self forKeyPath:treeController->isLeafKeyPath options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:PWTreeControllerIsLeafChangeContext]; isObservingLeafState = YES; } [self addAttributeObservers:treeController->attributeObservers recurse:NO]; isObservingAttributes = YES; return self; } - (void)createSubNodeForObjects:(NSSet *)objects { NSEnumerator *e = [objects objectEnumerator]; id object; while (object = [e nextObject]) { PWTreeControllerNode *node = [[PWTreeControllerNode alloc] initWithTreeController:treeController observedObject:object parentNode:self]; [subNodes addObject:node]; [node release]; } [filteredSubNodes release]; filteredSubNodes = nil; needsResort = YES; } - (void)removeSubNodeForObjects:(NSSet *)objects { NSEnumerator *e = [objects objectEnumerator]; id object; while (object = [e nextObject]) { PWTreeControllerNode *node = (PWTreeControllerNode *)CFDictionaryGetValue(treeController->nodesForObjects, object); [subNodes removeObject:node]; } [filteredSubNodes release]; filteredSubNodes = nil; needsResort = YES; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if(context == PWTreeControllerSubNodesChangeContext) { [treeController willChangeSubNodesOfNode:self]; if(subNodes) { int kind = [[change objectForKey:NSKeyValueChangeKindKey] intValue]; id new = [change objectForKey:NSKeyValueChangeNewKey]; if(kind == NSKeyValueChangeSetting || kind == NSKeyValueChangeReplacement || ![new count] ) [self prune]; else if(kind == NSKeyValueChangeInsertion) [self createSubNodeForObjects:new]; else if(kind == NSKeyValueChangeRemoval) [self removeSubNodeForObjects:new]; } determinedIsLeafValue = NO; [treeController didChangeSubNodesOfNode:self]; } else if(context == PWTreeControllerIsLeafChangeContext) { BOOL newIsLeaf = [[observedObject valueForKeyPath:treeController->isLeafKeyPath] boolValue]; if(!determinedIsLeafValue || newIsLeaf!=isLeaf) { [treeController willChangeLeafStateOfNode:self]; if(isLeaf && subNodes) [self prune]; determinedIsLeafValue = YES; [treeController didChangeLeafStateOfNode:self]; } } } - (void)addAttributeObservers:(NSArray *)observers recurse:(BOOL)recurse { int count = [observers count]; for(int index=0; indexobserver forKeyPath:o->keyPath options:o->options context:o->context]; } if(recurse) { int count = [subNodes count]; for(int index=0; indexobserver forKeyPath:o->keyPath]; } if(recurse) { int count = [subNodes count]; for(int index=0; indexattributeObservers recurse:NO]; isObservingAttributes = NO; } if(isObservingSubNodes) { [observedObject removeObserver:self forKeyPath:treeController->childrenKeyPath ]; isObservingSubNodes = NO; } if(isObservingLeafState) { [observedObject removeObserver:self forKeyPath:treeController->isLeafKeyPath ]; isObservingLeafState = NO; } } - (void)dealloc { if(treeController) { [self removeObservers]; if(CFDictionaryGetValue(treeController->nodesForObjects, observedObject)==self) CFDictionaryRemoveValue(treeController->nodesForObjects, observedObject); } [observedObject release]; [subNodes release]; [filteredSubNodes release]; [super dealloc]; } - (NSArray *) childNodes { return subNodes; } - (NSArray *)subNodes { if(isLeaf) return nil; else if(!subNodes) { id collection = [observedObject valueForKeyPath:[treeController childrenKeyPath]]; NSArray *array = [collection isKindOfClass:[NSArray class]] ? collection : [collection allObjects]; subNodes = [[treeController createNodesFromObservedObjectsArray:array parentNode:self] retain]; } else if(needsResort) { NSArray *descs = [treeController observedObjectsSortDescriptors]; [subNodes sortUsingDescriptors:descs]; [filteredSubNodes release]; filteredSubNodes = nil; needsResort = NO; } return subNodes; } - (PWTreeControllerNode *)parentNode { return parentNode; } - (NSArray *)filteredSubNodes { if(!determinedIsLeafValue || !isLeaf) { if(needsResort) { [filteredSubNodes release]; filteredSubNodes = nil; } if(!filteredSubNodes) { NSArray *nodes = [self subNodes]; filteredSubNodes = [[NSMutableArray alloc] init]; int count = [nodes count]; for(int index=0; indexfilteredObjectsAndAncestors containsObject:[subNode observedObject]]) [filteredSubNodes addObject:subNode]; } } } return filteredSubNodes; } - (NSArray *)arrangedSubNodes { return treeController->filterPredicate ? [self filteredSubNodes] : [self subNodes]; } - (BOOL)isLeaf { if(!determinedIsLeafValue) { if(treeController->isLeafKeyPath && !determinedIsLeafValue) isLeaf = [[observedObject valueForKeyPath:treeController->isLeafKeyPath] boolValue]; else if(subNodes) isLeaf = [subNodes count]==0; else isLeaf = [[observedObject valueForKeyPath:treeController->childrenKeyPath] count]==0; determinedIsLeafValue = YES; } return isLeaf; } - (id)observedObject { return observedObject; } - (id)representedObject { return observedObject; } - (void)setNeedsResort:(BOOL)needs { needsResort = needs; int count = [subNodes count]; for(int index=0; indexisLeafKeyPath) [observedObject addObserver:self forKeyPath:treeController->isLeafKeyPath options: 0 context:PWTreeControllerIsLeafChangeContext]; int count = [subNodes count]; for(int index=0; indexnodesForObjects, observedObject)==self) CFDictionaryRemoveValue(treeController->nodesForObjects, observedObject); int count = [subNodes count]; for(int index=0; index