Saturday, April 17, 2010

List Selection: Creating a chain of events and predicates across relationships.

The previous code can be modified to create a chain of events:

  1. The user is presented with a set of word lists.  They select which ones they want.
  2. The user is then presented with all the words in those word lists.  The select which ones they want.
  3. Finally the user accepts all the words selected and those words are merged to the current word list.

I accomplished all of this in my main list editor, a generic class is used to select the nodes:

Modify selection list to expose selected results

First I modified my UISelectionMaster to expose the currently selected items.  

- (NSArray *) currentSelectedItems:(NSString*) sortKey;



- (NSArray *) currentSelectedItems:(NSString *)sortKey
{
if (self.selectionController==nil)
return nil;
NSArray *returnValue=[self.selectionController.selectedItems getSortedArray:sortKey];
return returnValue;
}

Simple, and I might later modify it to just return a set.

Add first step in the chain

From the previous blog entry, but I've added a member property to contain the currently active dialog.  This way the callback can use it.
- (IBAction) mergeFromLists:(id) sender
{
JLTableContainer *container=
[JLTableContainer createFetchControlledTable:nil
  forEntity:@"WordList"  
forSimpleKey:@"ListName" 
   inContext: [SightWordState Instance].control.managedObjectContext 
createSectionsBy:nil 
controlledBy:nil];
[container updatePredicate:nil];
UISelectionMaster * selector=[[UISelectionMaster alloc] init];
selector.listToSelect=container;
[self.navigationController pushViewController:selector animated:true];
[selector startSelection];
[selector showToolbar:@"Select Lists" target:self action:@selector(listsSelected:)];

self.currentDialog=selector;
}


Feed results of first step into another instance of the same selection 


The tricky part was building my predicate from the previous selected words.  My object model has few elements, but it does have a two way relationship between words and word lists.  It turns out that given a list of ManagedObjects, you can feed that into a predicate against a relationship.   


I'm not sure if this is more or less efficient than iterating over all the words in all the lists and making a new list.  For sight words the performance difference will not be relevant.

- (IBAction) listsSelected:(id) sender
{


JLTableContainer *container=

[JLTableContainer createFetchControlledTable:nil
  forEntity:@"WordInformation" forSimpleKey:@"wordName" 
   inContext: [SightWordState Instance].control.managedObjectContext 
createSectionsBy:nil 
controlledBy:nil];
NSArray *selectedLists=[currentDialog currentSelectedItems:@"ListName"];
NSPredicate *predicate= [NSPredicate predicateWithFormat:@"ANY containedIn in %@",selectedLists ]; 
[container updatePredicate:predicate];
UISelectionMaster * selector=[[UISelectionMaster alloc] init];
selector.listToSelect=container;
[self.navigationController pushViewController:selector animated:true];
[selector startSelection];
self.currentDialog=selector;
[selector showToolbar:@"Add Words" target:self action:@selector(wordsSelected:)];

}



Take the results of the second selection and use them, pop back to the top of the list


Note that the really neat popToViewController allows me to pop multiple layers of dialogs back to the starting one.   Its pretty handy.   Once again I suspect this is not the most efficient way to use core data, however I'm still learning about core data, and for this application it shouldn't matter.

- (IBAction) wordsSelected:(id) sender
{
    for (WordInformation *wordInfo in [currentDialog currentSelectedItems:@"wordName"])
{
[currentWordList addContainedWordsObject:wordInfo];
}
[self.navigationController popToViewController:self animated:true ];
[[SightWordState Instance] save];
}

Left over bugs

The selection still needs some 'select all/clear all' options, as well as potentially extra filters.  In addition the toolbars are a little flaky, when navigating back to a previous option, the toolbar is lost.

No comments:

Post a Comment