// // PWTreeController.m // PWTreeControllerDemo // // Created by Frank Illenberger on 04.03.06. // Copyright 2006 ProjectWizards, Melle, Germany. // #import "PWTreeController.h" #import "PWTreeController-Private.h" #import "PWTreeControllerNode.h" #import "PWOutlineView.h" #import "PWOutlineView.h" #import "NSOutlineView-PWExtensions.h" #import "PWObservationInfo.h" #define PWSortAttributesObservingContext (void *)@"PWSortAttributesObservingContext" #define PWNewRootArray (void *)@"NewRootArray" @implementation PWTreeController CFHashCode directHashCallBack(const void *value) { return (CFHashCode)value; } - (void)setup { isAutosorting = YES; static CFDictionaryKeyCallBacks keyCallbacks = { .version = 0, .retain = NULL, .release = NULL, .copyDescription = NULL, .equal = NULL, .hash = directHashCallBack }; static CFDictionaryValueCallBacks valueCallbacks = { .version = 0, .retain = NULL, .release = NULL, .copyDescription = NULL, .equal = NULL }; nodesForObjects = CFDictionaryCreateMutable(nil, 0, &keyCallbacks, &valueCallbacks); attributeObservers = [[NSMutableArray alloc] init]; [self setRootKeyPath:@"rootObjects"]; [self setChildrenKeyPath:@"children"]; isSetup = YES; } - (id)init { [super init]; if(!isSetup) [self setup]; return self; } - (void)awakeFromNib { if(!isSetup) [self setup]; [outlineView _buildConfigurationMenu]; } - (int)outlineView:(NSOutlineView *)ov numberOfChildrenOfItem:(id)item { if(filterPredicate) return !item ? [filteredRootNodes count] : [[item filteredSubNodes] count]; else return !item ? [[self rootNodes] count] : [[item subNodes] count]; } - (BOOL)outlineView:(NSOutlineView *)ov isItemExpandable:(id)item { if (filterPredicate) return [[item filteredSubNodes] count]; else return ![item isLeaf]; } - (void) delete: (id) sender { [rootSource delete: sender]; } - (void) ungroup: (id) sender { [rootSource ungroup: sender]; } - (void) group: (id) sender { [rootSource group: sender]; } - (void) addChild: (id) sender { [rootSource addChildToOutline: sender]; } - (void) addSibling: (id) sender { [rootSource addSiblingToOutline: sender]; } - (id)outlineView:(NSOutlineView *)ov child:(int)index ofItem:(id)item { if(filterPredicate) return !item ? [filteredRootNodes objectAtIndex:index] : [[item filteredSubNodes] objectAtIndex:index]; else return !item ? [[self rootNodes] objectAtIndex:index] : [[item subNodes] objectAtIndex:index]; } - (id)outlineView:(NSOutlineView *)ov objectValueForTableColumn:(NSTableColumn *)column byItem:(id)item { if ([[column bindingKeyPath] isEqualToString:@"info"]) return nil; if ([[column bindingKeyPath] isEqualToString:@"note"]) return nil; return [[item representedObject] valueForKeyPath:[column bindingKeyPath]]; } - (void)outlineView:(NSOutlineView *)ov setObjectValue:(id)value forTableColumn:(NSTableColumn *)column byItem:(id)item { id obj = [item representedObject]; NSString *keyPath = [column bindingKeyPath]; NSError *error = nil; if ([[column identifier] isEqualToString:@"note"]) return; if ([[column identifier] isEqualToString:@"info"]) return; if ([[column identifier] isEqualToString:@"context"] || [[column identifier] isEqualToString:@"project"]) { id cell=[column dataCell]; value=[[cell itemAtIndex: [value intValue]] representedObject]; } if(![obj validateValue:&value forKeyPath:keyPath error:&error]) [ov presentError:error modalForWindow:[ov window] delegate:nil didPresentSelector:0 contextInfo:nil]; else [obj setValue:value forKeyPath:keyPath]; } - (void)outlineView:(NSOutlineView *)ov sortDescriptorsDidChange:(NSArray *)oldDescriptors { [self setSortDescriptors:[ov sortDescriptors]]; [ov reloadData]; } - (NSMutableArray *)createNodesFromObservedObjectsArray:(NSArray *)objects parentNode:(PWTreeControllerNode *)parent { NSMutableArray *nodes = [NSMutableArray array]; NSArray *descs = [self sortDescriptorsForSorting]; NSArray *sortedObjects = descs ? [objects sortedArrayUsingDescriptors:descs] : objects; int count = [sortedObjects count]; for(int index=0; index 1) return NSMultipleValuesMarker; return NSNotApplicableMarker; //return result; } - (NSArray *)selectedObjects { NSMutableArray *selection = [NSMutableArray array]; if(outlineView) { NSIndexSet *selectedRows = [outlineView selectedRowIndexes]; int row = [selectedRows firstIndex]; while(row!=NSNotFound) { id item = [outlineView itemAtRow:row]; if(item) [selection addObject:[item representedObject]]; row = [selectedRows indexGreaterThanIndex:row]; } } return selection; } - (PWTreeControllerNode *)nodeForObservedObject:(id)object { return (PWTreeControllerNode *)CFDictionaryGetValue(nodesForObjects, object); } - (void)setSelectedObjects:(NSArray *)objects { int count = [objects count]; NSMutableIndexSet *rows = [NSMutableIndexSet indexSet]; for(int index=0; indexobserver == observer && [info->keyPath isEqual:keyPath]) return info; } return nil; } - (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context { if([keyPath hasPrefix:@"arrangedObjects."]) { NSString *subPath = [keyPath substringFromIndex:16]; PWObservationInfo *info = [[[PWObservationInfo alloc] initWithObserver:anObserver keyPath:subPath options:options context:context] autorelease]; if(![attributeObservers containsObject:info]) { [attributeObservers addObject:info]; NSArray *observationArray = [NSArray arrayWithObject:info]; int count = [[self rootNodes] count]; for(int index=0; index)info proposedItem:(id)item proposedChildIndex:(int)index; { return [rootSource outlineView: view validateDrop: info proposedItem: item proposedChildIndex: index]; } - (BOOL)outlineView:(NSOutlineView *)view acceptDrop:(id )info item:(id)item childIndex:(int)index; { return [rootSource outlineView: view acceptDrop: info item: item childIndex: index]; } - (void) outlineView: (NSOutlineView *)view didFinishDragOperation:(NSDragOperation)operation { [rootSource outlineView: view didFinishDragOperation: operation]; } - (NSArray *) tableViewDefaultColumnIdentifiers: (NSTableView *) tv { return [rootSource tableViewDefaultColumnIdentifiers: tv]; } - (id) configurableColumnOutlineView: (id) ov shouldAllowTogglingColumn: column { return [rootSource configurableColumnOutlineView: ov shouldAllowTogglingColumn: column]; } - (NSString *) configurableColumnOutlineView: (id) ov menuStringForColumn: column { return [rootSource configurableColumnOutlineView: ov menuStringForColumn: column]; } @end