View Full Version : software design: deleting items from a tree with coredata backing

Mar 16, 2009, 03:49 PM

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];