API 0.9.5
AppKit/CPRuleEditor/CPPredicateEditor.j
Go to the documentation of this file.
00001 /*
00002  * CPPredicateEditor.j
00003  * AppKit
00004  *
00005  * Created by cacaodev.
00006  * Copyright 2011, cacaodev.
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00021  */
00022 
00023 
00024 @implementation CPPredicateEditor : CPRuleEditor
00025 {
00026     CPArray _allTemplates;
00027     CPArray _rootTrees;
00028     CPArray _rootHeaderTrees;
00029     id      _predicateTarget;
00030     SEL     _predicateAction;
00031 }
00032 
00033 #pragma mark public methods
00034 
00053 - (CPArray)rowTemplates
00054 {
00055     return _allTemplates;
00056 }
00057 
00063 - (void)setRowTemplates:(id)rowTemplates
00064 {
00065     if (_allTemplates == rowTemplates)
00066         return;
00067 
00068     _allTemplates = rowTemplates;
00069 
00070     [self _updateItemsByCompoundTemplates];
00071     [self _updateItemsBySimpleTemplates];
00072 
00073     if ([self numberOfRows] > 0)
00074     {
00075         var predicate = [super predicate];
00076         [self _reflectPredicate:predicate];
00077     }
00078 }
00079 
00081 - (void)_initRuleEditorShared
00082 {
00083     [super _initRuleEditorShared];
00084 
00085     _rootTrees = [CPArray array];
00086     _rootHeaderTrees = [CPArray array];
00087 }
00088 
00089 - (id)initWithFrame:(CGRect)aFrame
00090 {
00091     self = [super initWithFrame:aFrame];
00092     if (self != nil)
00093     {
00094         var initialTemplate = [[CPPredicateEditorRowTemplate alloc] initWithCompoundTypes:[CPAndPredicateType, CPOrPredicateType]];
00095         _allTemplates = [CPArray arrayWithObject:initialTemplate];
00096     }
00097 
00098     return self;
00099 }
00100 
00101 - (id)objectValue
00102 {
00103     return [super predicate];
00104 }
00105 
00106 - (void)_updateItemsBySimpleTemplates
00107 {
00108     var templates = [CPMutableArray array],
00109         count = [_allTemplates count],
00110         t;
00111 
00112     while (count--)
00113     {
00114         var t = _allTemplates[count];
00115         if ([t _rowType] == CPRuleEditorRowTypeSimple)
00116             [templates insertObject:t atIndex:0];
00117     }
00118 
00119     var trees = [self _constructTreesForTemplates:templates];
00120     if ([trees count] > 0)
00121         _rootTrees = [self _mergeTree:trees];
00122 }
00123 
00124 - (void)_updateItemsByCompoundTemplates
00125 {
00126     var templates = [CPMutableArray array],
00127         count = [_allTemplates count],
00128         t;
00129 
00130     while (count--)
00131     {
00132         var t = _allTemplates[count];
00133         if ([t _rowType] == CPRuleEditorRowTypeCompound)
00134             [templates insertObject:t atIndex:0];
00135     }
00136 
00137     var trees = [self _constructTreesForTemplates:templates];
00138     if ([trees count] > 0)
00139         _rootHeaderTrees = [self _mergeTree:trees];
00140 }
00141 
00142 - (CPArray)_constructTreesForTemplates:(id)templates
00143 {
00144     var trees = [CPMutableArray array],
00145         count = [templates count];
00146 
00147     for (var i = 0; i < count; i++)
00148     {
00149         var tree = [self _constructTreeForTemplate:templates[i]];
00150         [trees addObjectsFromArray:tree];
00151     }
00152 
00153     return trees;
00154 }
00155 
00156 - (id)_mergeTree:(id)tree
00157 {
00158     var merged = [CPMutableArray array],
00159         titles = [CPMutableArray array],
00160         count = [tree count];
00161 
00162     for (var i = 0; i < count; i++)
00163     {
00164         var t = tree[i],
00165             title = [CPString stringWithString:[t title]];
00166 
00167         if ([titles containsObject:title])
00168         {
00169             CPLogConsole("CPPredicateEditor does not support templates merging yet. Ignoring duplicate template: " + [t description]);
00170             continue;
00171         }
00172 
00173         [merged addObject:t];
00174         [titles addObject:title];
00175     }
00176 
00177     return merged;
00178 }
00179 
00180 - (id)_constructTreeForTemplate:(CPPredicateEditorRowTemplate)aTemplate
00181 {
00182     var tree = [CPArray array],
00183         templateViews = [aTemplate templateViews],
00184         count = [templateViews count];
00185 
00186     while (count--)
00187     {
00188         var children = [CPArray array],
00189             itemsCount = 0,
00190             menuIndex = -1,
00191             itemsArray,
00192 
00193             templateView = [templateViews objectAtIndex:count],
00194             isPopup = [templateView isKindOfClass:[CPPopUpButton class]];
00195 
00196         if (isPopup)
00197         {
00198             itemArray = [[templateView itemArray] valueForKey:@"title"];
00199             itemsCount = [itemArray count];
00200             menuIndex = 0;
00201         }
00202 
00203         for (; menuIndex < itemsCount; menuIndex++)
00204         {
00205             var item = [_CPPredicateEditorTree new];
00206             [item setIndexIntoTemplate:count];
00207             [item setTemplate:aTemplate];
00208             [item setMenuItemIndex:menuIndex];
00209             if (isPopup)
00210                 [item setTitle:[itemArray objectAtIndex:menuIndex]];
00211 
00212             [children addObject:item];
00213         }
00214 
00215         [children makeObjectsPerformSelector:@selector(setChildren:) withObject:tree];
00216         tree = children;
00217     }
00218 
00219     return tree;
00220 }
00221 
00222 #pragma mark Set the Predicate
00223 
00224 - (void)setObjectValue:(id)objectValue
00225 {
00226     if (![[objectValue predicateFormat] isEqualToString:[[super predicate] predicateFormat]]) // ??
00227         [self _reflectPredicate:objectValue];
00228 }
00229 
00230 - (void)_reflectPredicate:(id)predicate
00231 {
00232     var animation = _currentAnimation;
00233     _currentAnimation = nil;
00234 
00235     if (predicate != nil)
00236     {
00237         if ((_nestingMode == CPRuleEditorNestingModeSimple || _nestingMode == CPRuleEditorNestingModeCompound)
00238             && [predicate isKindOfClass:[CPComparisonPredicate class]])
00239             predicate = [[CPCompoundPredicate alloc] initWithType:[self _compoundPredicateTypeForRootRows] subpredicates:[CPArray arrayWithObject:predicate]];
00240 
00241         var row = [self _rowObjectFromPredicate:predicate];
00242         if (row != nil)
00243             [_boundArrayOwner setValue:[CPArray arrayWithObject:row] forKey:_boundArrayKeyPath];
00244     }
00245 
00246     [self setAnimation:animation];
00247 }
00248 
00249 - (id)_rowObjectFromPredicate:(CPPredicate)predicate
00250 {
00251     var quality, // TODO: We should use this ref somewhere !
00252         type,
00253         matchedTemplate = [CPPredicateEditorRowTemplate _bestMatchForPredicate:predicate inTemplates:[self rowTemplates] quality:quality];
00254 
00255     if (matchedTemplate == nil)
00256         return nil;
00257 
00258     var copyTemplate = [matchedTemplate copy],
00259         subpredicates = [matchedTemplate displayableSubpredicatesOfPredicate:predicate];
00260 
00261     if (subpredicates == nil)
00262     {
00263         [copyTemplate _setComparisonPredicate:predicate];
00264         type = CPRuleEditorRowTypeSimple;
00265     }
00266     else
00267     {
00268         [copyTemplate _setCompoundPredicate:predicate];
00269         type = CPRuleEditorRowTypeCompound;
00270     }
00271 
00272     var row = [self _rowFromTemplate:copyTemplate originalTemplate:matchedTemplate withRowType:type];
00273 
00274     if (subpredicates == nil)
00275         return row;
00276 
00277     var count = [subpredicates count],
00278         subrows = [CPMutableArray array];
00279 
00280     for (var i = 0; i < count; i++)
00281     {
00282         var subrow = [self _rowObjectFromPredicate:subpredicates[i]];
00283         if (subrow != nil)
00284             [subrows addObject:subrow];
00285     }
00286 
00287     [row setValue:subrows forKey:[super subrowsKeyPath]];
00288 
00289     return row;
00290 }
00291 
00292 - (id)_rowFromTemplate:(CPPredicateEditorRowTemplate)aTemplate originalTemplate:(CPPredicateEditorRowTemplate)originalTemplate withRowType:(CPRuleEditorRowType)rowType
00293 {
00294     var criteria = [CPArray array],
00295         values = [CPArray array],
00296         templateViews = [aTemplate templateViews],
00297         rootItems,
00298         count;
00299 
00300     rootItems = (rowType == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
00301 
00302     while ((count = [rootItems count]) > 0)
00303     {
00304         var treeChild;
00305         for (var i = 0; i < count; i++)
00306         {
00307             treeChild = [rootItems objectAtIndex:i];
00308 
00309             var currentView = [templateViews objectAtIndex:[treeChild indexIntoTemplate]],
00310                 menuItemIndex = [treeChild menuItemIndex];
00311 
00312             if (menuItemIndex == -1 || [[treeChild title] isEqual:[currentView titleOfSelectedItem]])
00313             {
00314                 var node = [_CPPredicateEditorRowNode rowNodeFromTree:treeChild];
00315                 [node applyTemplate:aTemplate withViews:templateViews forOriginalTemplate:originalTemplate];
00316 
00317                 [criteria addObject:node];
00318                 [values addObject:[node displayValue]];
00319                 break;
00320             }
00321         }
00322 
00323         rootItems = [treeChild children];
00324     }
00325 
00326     var row = [CPDictionary dictionaryWithObjectsAndKeys:criteria, @"criteria", values, @"displayValues", rowType, @"rowType"];
00327 
00328     return row;
00329 }
00330 
00331 #pragma mark Get the predicate
00332 
00333 - (void)_updatePredicate
00334 {
00335     [self willChangeValueForKey:@"objectValue"];
00336     [self _updatePredicateFromRows];
00337     [self didChangeValueForKey:@"objectValue"];
00338 }
00339 
00340 - (void)_updatePredicateFromRows
00341 {
00342     var rootRowsArray = [super _rootRowsArray],
00343         subpredicates = [CPMutableArray array],
00344         count = count2 = [rootRowsArray count],
00345         predicate;
00346 
00347     while (count--)
00348     {
00349         var item = [rootRowsArray objectAtIndex:count],
00350             subpredicate = [self _predicateFromRowItem:item];
00351 
00352         if (subpredicate != nil)
00353             [subpredicates insertObject:subpredicate atIndex:0];
00354     }
00355 
00356     if (_nestingMode != CPRuleEditorNestingModeList && count2 == 1)
00357         predicate = [subpredicates lastObject];
00358     else
00359         predicate = [[CPCompoundPredicate alloc] initWithType:[self _compoundPredicateTypeForRootRows] subpredicates:subpredicates];
00360 
00361     [super _setPredicate:predicate];
00362 }
00363 
00364 - (id)_predicateFromRowItem:(id)rowItem
00365 {
00366     var subpredicates = [CPArray array],
00367         rowType = [rowItem valueForKey:_typeKeyPath];
00368 
00369     if (rowType == CPRuleEditorRowTypeCompound)
00370     {
00371         var subrows = [rowItem valueForKey:_subrowsArrayKeyPath],
00372         count = [subrows count];
00373 
00374         for (var i = 0; i < count; i++)
00375         {
00376             var subrow = [subrows objectAtIndex:i];
00377             var predicate = [self _predicateFromRowItem:subrow];
00378             [subpredicates addObject:predicate];
00379         }
00380     }
00381 
00382     var criteria = [rowItem valueForKey:_itemsKeyPath],
00383         displayValues = [rowItem valueForKey:_valuesKeyPath],
00384         count = [criteria count],
00385         lastItem = [criteria lastObject],
00386         template = [lastItem templateForRow],
00387         templateViews = [template templateViews];
00388 
00389     for (var j = 0; j < count; j++)
00390     {
00391         var view = [templateViews objectAtIndex:j],
00392             value = [displayValues objectAtIndex:j];
00393         [[criteria objectAtIndex:j] setTemplateViews:templateViews];
00394 
00395         if ([view isKindOfClass:[CPPopUpButton class]])
00396             [view selectItemWithTitle:value];
00397         else if ([view respondsToSelector:@selector(setObjectValue:)])
00398             [view setObjectValue:[value objectValue]];
00399     }
00400 
00401     return [template predicateWithSubpredicates:subpredicates];
00402 }
00403 
00404 - (CPCompoundPredicateType)_compoundPredicateTypeForRootRows
00405 {
00406     return CPAndPredicateType;
00407 }
00408 
00409 #pragma mark Control delegate
00410 
00411 - (void)_sendRuleAction
00412 {
00413     [self _updatePredicate];
00414     [super _sendRuleAction];
00415 }
00416 
00417 - (BOOL)_sendsActionOnIncompleteTextChange
00418 {
00419     return NO;
00420 }
00421 
00422 /*
00423 - (void)_setDefaultTargetAndActionOnView:(CPView)view
00424 {
00425     if ([view isKindOfClass:[CPControl class]])
00426     {
00427         [view setTarget:self];
00428         [view setAction:@selector(_templateControlValueDidChange:)];
00429     }
00430 }
00431 - (void)_templateControlValueDidChange:(id)sender
00432 {
00433 }
00434 - (void)controlTextDidBeginEditing:(CPNotification)notification
00435 {
00436 }
00437 - (void)controlTextDidEndEditing:(CPNotification)notification
00438 {
00439 }
00440 - (void)controlTextDidChange:(CPNotification)notification
00441 {
00442 }
00443 */
00444 
00445 #pragma mark RuleEditor delegate methods
00446 
00447 - (int)_queryNumberOfChildrenOfItem:(id)rowItem withRowType:(int)type
00448 {
00449     if (rowItem == nil)
00450     {
00451         var trees = (type == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
00452         return [trees count];
00453     }
00454     return [[rowItem children] count];
00455 }
00456 
00457 - (id)_queryChild:(int)childIndex ofItem:(id)rowItem withRowType:(int)type
00458 {
00459     if (rowItem == nil)
00460     {
00461         var trees = (type == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
00462         return [_CPPredicateEditorRowNode rowNodeFromTree:trees[childIndex]];
00463     }
00464 
00465     return [[rowItem children] objectAtIndex:childIndex];
00466 }
00467 
00468 - (id)_queryValueForItem:(id)rowItem inRow:(int)rowIndex
00469 {
00470     return [rowItem displayValue];
00471 }
00472 
00473 @end
00474 
00475 var CPPredicateTemplatesKey = @"CPPredicateTemplates";
00476 
00477 @implementation CPPredicateEditor (CPCoding)
00478 
00479 - (id)initWithCoder:(id)aCoder
00480 {
00481     self = [super initWithCoder:aCoder];
00482     if (self != nil)
00483     {
00484         var nibTemplates = [aCoder decodeObjectForKey:CPPredicateTemplatesKey];
00485         if (nibTemplates != nil)
00486             [self setRowTemplates:nibTemplates];
00487     }
00488 
00489     return self;
00490 }
00491 
00492 - (void)encodeWithCoder:(id)aCoder
00493 {
00494     [super encodeWithCoder:aCoder];
00495     [aCoder encodeObject:_allTemplates forKey:CPPredicateTemplatesKey];
00496 }
00497 
00498 @end
00499 
00502 @implementation CPPredicateEditor (CPSynthesizedAccessors)
00503 
00504 
00507 - (id)target
00508 {
00509     return _predicateTarget;
00510 }
00511 
00515 - (void)setTarget:(id)aValue
00516 {
00517     _predicateTarget = aValue;
00518 }
00519 
00523 - (SEL)action
00524 {
00525     return _predicateAction;
00526 }
00527 
00531 - (void)setAction:(SEL)aValue
00532 {
00533     _predicateAction = aValue;
00534 }
00535 
00536 @end
 All Classes Files Functions Variables Defines