software design: deleting items from a tree with coredata backing

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

  1. macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #1
    Hello,

    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.
    Code:
    -(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