Today I want to talk about NSPredicateEditor and how to use it with a DADataTable.
What is NSPredicateEditor…
Cocoa’s NSPredicateEditor class provides an excellent way to compose predicates at runtime. The main benefit is that the user needs to know nothing about predicates and their format, but with help of NSPredicateEditor can easily build quite complex conditions they need. Using NSPredicateEditor also allows to avoid any kind of typing errors, because in most of cases all the user needs is to do is just to select appropriate fields and values from popup buttons.
Here is the screenshot of Bugs 7 showing NSPredicateEditor that represents following condition: (Live == 1 AND AreaID == 4 AND OwnerID == 5) OR ID == 37222
Usually, a row template holds three elements: left and right expressions and a condition between them. In our case, the left expression represents the column from our table and the right expression represents the value pattern for that column. Obviously, it is good to have template with most suitable editor for each column data type. DataAbstract for OS X provides proper templates for each fields that can be used in the table. In addition to standard NSPredicateEditorRowTemplate DA brings several custom row templates that simplify building predicates for the tables.
The most interesting here is the DALookupFieldPredicateEditorRowTemplate class. This class allows to create row template for a lookup field, where the user can chose certain lookup value from list of allowed values, proposed by a popup button. It allows user to deal with meaningful values instead of just IDs. This is well shown in the figure above.
I should also mention DAFallbackPredicateEditorRowTemplate. This class describes special template for any predicate that is not supported by a given set of templates. For example if your editor tries to render a NSPredicate that comes into your application from outside and cannot understand a certain part of the compound predicate, then it will render it as “unsupported predicate” with help of DAFallbackPredicateEditorRowTemplate. This assures that the sub-predicate, while not editable in the NSPredicateEditor, will not get lost.
…and How Can You Use it?
Let’s see how to configure NSPredicateEditor instance for composing predicates for a certain custom DADataTable.
When you need to configure the editor for exposing a sub-set of columns only, you need to create array of row templates obtained from each table field you want to see in editor:
NSMutableArray*rowTemplates =[NSMutableArray arrayWithCapacity:[[da bugs] fieldCount]]; for(NSString*f in allowedFields){ DAFieldDefinition *fd =[[da bugs] fieldByName:f]; [rowTemplates addObjectsFromArray:[fd predicateEditorRowTemplates]]; } |
NSPredicateEditorRowTemplate*compoundTemplate =[[[NSPredicateEditorRowTemplate alloc] initWithCompoundTypes:[NSArray arrayWithObjects:[NSNumber numberWithInt: NSAndPredicateType], [NSNumber numberWithInt: NSOrPredicateType], [NSNumber numberWithInt: NSNotPredicateType], nil]] autorelease]; [rowTemplates addObject:compoundTemplate]; |
[rowTemplates addObject:[DAFallbackPredicateEditorRowTemplate rowTemplate]]; |
[editor setRowTemplates:rowTemplates]; |
[editor setRowTemplates:[[da bugs] defaultPredicateEditorRowTemplates]]; |
You can use that editor to let the user define NSPredicates both for local filtering data in table like:
NSPredicate*p =[editor predicate]; rows =[[[myTable rows] filteredArrayUsingPredicate:p] retain]; [tableView reloadData]; |
NSPredicate*p =[editor predicate]; DADynamicWhereClause *clause =[DADynamicWhereClause dynamicWhereClauseWithPredicate:p]; request =[rda beginGetDataTable:@"MyTable" select:[self fieldsToSelect] where:clause start:NO]; [request setDelegate:self]; [request start]; |