software design: deleting items from a tree with coredata backing

Discussion in 'Mac Programming' started by MrFusion, Mar 16, 2009.

  1. MrFusion
    Expand Collapse
    macrumors 6502a

    Jun 8, 2005

    This problem has been annoying me for days and I can't see the solution. There is probably a standard solution, but unfortunately I am ignorant of CS-algorithms.

    I have a NSTreeController with coredata providing the data.
    I can have nodes (folder) and leafs (children). When I select a folder, but none of its children, I want to delete all the children and the folder. If I select a folder and some of the children, I want to delete the selected children, but not the folder. If I select children, but not the parent folder, I want to delete only the children.

    The selection can be any combination.

    One version of semi-working code I came up with is below. The only problem in behaviour is that when a few children and the parent are selected, the parent still gets deleted.
    Yes, it looks ugly.
    -(void) removeManagedObjects:(NSArray *)items {	
    	NSMutableArray *toBeDeleted = [[NSMutableArray alloc] init]; //keep items around until it's clear what needs to be deleted
    	NSMutableArray *originals = [items mutableCopy];
    	while ([originals count] > 0) {
    		id node = [originals objectAtIndex:0];
    		if ([node isFolder]){
    			NSArray *allChildren = [[node mutableSetValueForKeyPath:@"children"] allObjects];
    			//are any of items selected a child of node?
    			NSMutableArray *selectedChildren = [[NSMutableArray alloc] init];
    			for (id possibleChild in originals) {
    				if ([possibleChild isChildOf:node]) {
    					[selectedChildren addObject:possibleChild];
    			if (([selectedChildren count] > 0) & ([selectedChildren count] < [allChildren count])){
    				//some children are selected. Delete those, but keep the parent around to keep the tree structure intact
    				[toBeDeleted removeObjectsInArray:selectedChildren];
    				[originals removeObjectsInArray:selectedChildren]; //children will be deleted, no need to evaluate them separately
    				[self removeManagedObjects:selectedChildren]; //get rid of children (recursive)
    				[originals removeObject:node]; //node has been evaluated, remove for future evaluation, but keep around for the tree integrity 
    			} else {
    				//zero children of folder are selected. Delete all, including the parent.
    				[self removeManagedObjects:allChildren];
    				[originals removeObject:node]; //node has been evaluated, remove for future evaluation
    				[toBeDeleted addObject:node]; //parent is no longer needed
    			[selectedChildren release];
    		} else {
    			BOOL foundparent = NO;
    			//is this node a child of another selected node, or is it stand alone?
    			for (id possibleParent in originals) {
    				if ([node isChildOf:possibleParent]) {
    					foundparent = YES;	
    			[originals removeObject:node];
    			if (!foundparent) {
    				[toBeDeleted addObject:node]; //node has been evaluated, is not a child of another selected node. remove for future evaluation
    			} else {
    				[originals addObject:node]; //node has been evaluated, keep around until it gets deleted together with the parent
    	for (id node in toBeDeleted) {
    		[[self managedObjectContext] deleteObject:node];
    	[toBeDeleted release];
    	[[self managedObjectContext] processPendingChanges];

Share This Page