API  0.9.6
 All Classes Files Functions Variables Macros Groups Pages
CPPredicateEditorRowTemplate.j
Go to the documentation of this file.
1 /*
2  * CPPredicateEditorRowTemplate.j
3  * AppKit
4  *
5  * Created by cacaodev.
6  * Copyright 2011, cacaodev.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
35 
36 @implementation CPPredicateEditorRowTemplate : CPObject
37 {
38  int _templateType;
39  unsigned _predicateOptions;
40  unsigned _predicateModifier;
41  unsigned _leftAttributeType;
42  unsigned _rightAttributeType;
43  BOOL _leftIsWildcard;
44  BOOL _rightIsWildcard;
45  CPArray _views;
46 
47 }
48 
83 - (id)initWithLeftExpressions:(CPArray)leftExpressions rightExpressions:(CPArray)rightExpressions modifier:(int)modifier operators:(CPArray)operators options:(int)options
84 {
85  self = [super init];
86  if (self != nil)
87  {
88  _templateType = 1;
89  _leftIsWildcard = NO;
90  _rightIsWildcard = NO;
91  _leftAttributeType = 0;
92  _rightAttributeType = 0;
93  _predicateModifier = modifier;
94  _predicateOptions = options;
95 
96  var leftView = [self _viewFromExpressions:leftExpressions],
97  rightView = [self _viewFromExpressions:rightExpressions],
98  middleView = [self _viewFromOperatorTypes:operators];
99 
100  _views = [[CPArray alloc] initWithObjects:leftView, middleView, rightView];
101  }
102 
103  return self;
104 }
105 
115 - (id)initWithLeftExpressions:(CPArray )leftExpressions rightExpressionAttributeType:(CPAttributeType)attributeType modifier:(CPComparisonPredicateModifier)modifier operators:(CPArray )operators options:(int)options
116 {
117  self = [super init];
118  if (self != nil)
119  {
120  var leftView = [self _viewFromExpressions:leftExpressions],
121  middleView = [self _viewFromOperatorTypes:operators],
122  rightView = [self _viewFromAttributeType:attributeType];
123 
124  _templateType = 1;
125  _leftIsWildcard = NO;
126  _rightIsWildcard = YES;
127  _leftAttributeType = 0;
128  _rightAttributeType = attributeType;
129  _predicateModifier = modifier;
130  _predicateOptions = options;
131  _views = [[CPArray alloc] initWithObjects:leftView, middleView, rightView];
132  }
133 
134  return self;
135 }
136 
143 - (id)initWithCompoundTypes:(CPArray )compoundTypes
144 {
145  self = [super init];
146  if (self != nil)
147  {
148  var leftView = [self _viewFromCompoundTypes:compoundTypes],
149  rightView = [[CPPopUpButton alloc] init];
150 
151  [rightView addItemWithTitle:@"of the following are true"];
152 
153  _templateType = 2;
154  _leftIsWildcard = NO;
155  _rightIsWildcard = NO;
156  _rightAttributeType = 0;
157  _views = [[CPArray alloc] initWithObjects:leftView, rightView];
158  }
159  return self;
160 }
161 
172 - (double)matchForPredicate:(CPPredicate)predicate
173 {
174  // How exactly this value (float 0-1) is computed ?
175  if ([self _templateType] == 2 && [predicate isKindOfClass:[CPCompoundPredicate class]])
176  {
177  if ([[self compoundTypes] containsObject:[predicate compoundPredicateType]])
178  return 1;
179  }
180  else if ([self _templateType] == 1 && [predicate isKindOfClass:[CPComparisonPredicate class]])
181  {
182  if (!_leftIsWildcard && ![[self leftExpressions] containsObject:[predicate leftExpression]])
183  return 0;
184 
185  if (![[self operators] containsObject:[predicate predicateOperatorType]])
186  return 0;
187 
188  if (!_rightIsWildcard && ![[self rightExpressions] containsObject:[predicate rightExpression]])
189  return 0;
190 
191  return 1;
192  }
193 
194  return 0;
195 }
196 
202 - (CPArray)templateViews
203 {
204  return _views;
205 }
206 
214 - (void)setPredicate:(CPPredicate)predicate
215 {
216  if (_templateType == 2)
217  [self _setCompoundPredicate:predicate];
218  else
219  [self _setComparisonPredicate:predicate];
220 }
221 
228 - (CPArray)displayableSubpredicatesOfPredicate:(CPPredicate)predicate
229 {
230  if ([predicate isKindOfClass:[CPCompoundPredicate class]])
231  {
232  var subpredicates = [predicate subpredicates];
233  if ([subpredicates count] == 0)
234  return nil;
235 
236  return subpredicates;
237  }
238 
239  return nil;
240 }
241 
250 - (CPPredicate)predicateWithSubpredicates:(CPArray)subpredicates
251 {
252  if (_templateType == 2)
253  {
254  var type = [[_views[0] selectedItem] representedObject];
255  return [[CPCompoundPredicate alloc] initWithType:type subpredicates:subpredicates];
256  }
257 
258  if (_templateType == 1)
259  {
260  var lhs = [self _leftExpression],
261  rhs = [self _rightExpression],
262  operator = [[_views[1] selectedItem] representedObject];
263 
265  rightExpression:rhs
266  modifier:[self modifier]
267  type:operator
268  options:[self options]];
269  }
270 
271  return nil;
272 }
273 
282 - (CPArray)leftExpressions
283 {
284  if (_templateType == 1 && !_leftIsWildcard)
285  {
286  var view = [_views objectAtIndex:0];
287  return [[view itemArray] valueForKey:@"representedObject"];
288  }
289 
290  return nil;
291 }
292 
297 - (CPArray)rightExpressions
298 {
299  if (_templateType == 1 && !_rightIsWildcard)
300  {
301  var view = [_views objectAtIndex:2];
302  return [[view itemArray] valueForKey:@"representedObject"];
303  }
304 
305  return nil;
306 }
307 
312 - (CPArray)compoundTypes
313 {
314  if (_templateType == 2)
315  {
316  var view = [_views objectAtIndex:0];
317  return [[view itemArray] valueForKey:@"representedObject"];
318  }
319 
320  return nil;
321 }
322 
328 {
329  if (_templateType == 1)
330  return _predicateModifier;
331 
332  return nil;
333 }
334 
339 - (CPArray)operators
340 {
341  if (_templateType == 1)
342  {
343  var view = [_views objectAtIndex:1];
344  return [[view itemArray] valueForKey:@"representedObject"];
345  }
346 
347  return nil;
348 }
349 
354 - (int)options
355 {
356  if (_templateType == 1)
357  return _predicateOptions;
358 
359  return nil;
360 }
361 
366 - (CPAttributeType)rightExpressionAttributeType
367 {
368  return _rightAttributeType;
369 }
370 
375 - (CPAttributeType)leftExpressionAttributeType
376 {
377  return _leftAttributeType;
378 }
379 
381 + (id)_bestMatchForPredicate:(CPPredicate)predicate inTemplates:(CPArray)templates quality:(double)quality
382 {
383  var count = [templates count],
384  match_value = 0,
385  templateIndex = CPNotFound,
386  i;
387 
388  for (i = 0; i < count; i++)
389  {
390  var template = [templates objectAtIndex:i],
391  amatch = [template matchForPredicate:predicate];
392 
393  if (amatch > match_value)
394  {
395  templateIndex = i;
396  match_value = amatch;
397  }
398  }
399 
400  if (templateIndex == CPNotFound)
401  {
402  [CPException raise:CPRangeException reason:@"Unable to find template matching predicate: " + [predicate predicateFormat]];
403  return nil;
404  }
405 
406  return [templates objectAtIndex:templateIndex];
407 }
408 
409 - (void)_setCompoundPredicate:(CPCompoundPredicate)predicate
410 {
411  var left = [_views objectAtIndex:0],
412  type = [predicate compoundPredicateType],
413  index = [left indexOfItemWithRepresentedObject:type];
414 
415  [left selectItemAtIndex:index];
416 }
417 
418 - (void)_setComparisonPredicate:(CPComparisonPredicate)predicate
419 {
420  var left = [_views objectAtIndex:0],
421  middle = [_views objectAtIndex:1],
422  right = [_views objectAtIndex:2],
423  leftExpression = [predicate leftExpression],
424  rightExpression = [predicate rightExpression],
425  operator = [predicate predicateOperatorType];
426 
427  if (_leftIsWildcard)
428  [left setObjectValue:[leftExpression constantValue]];
429  else
430  {
431  var index = [left indexOfItemWithRepresentedObject:leftExpression];
432  [left selectItemAtIndex:index];
433  }
434 
435  var op_index = [middle indexOfItemWithRepresentedObject:operator];
436  [middle selectItemAtIndex:op_index];
437 
438  if (_rightIsWildcard)
439  [right setObjectValue:[rightExpression constantValue]];
440  else
441  {
442  var index = [right indexOfItemWithRepresentedObject:rightExpression];
443  [right selectItemAtIndex:index];
444  }
445 }
446 
447 - (CPExpression)_leftExpression
448 {
449  return [self _expressionFromView:_views[0] forAttributeType:_leftAttributeType];
450 }
451 
452 - (CPExpression)_rightExpression
453 {
454  return [self _expressionFromView:_views[2] forAttributeType:_rightAttributeType];
455 }
456 
457 - (CPExpression)_expressionFromView:(CPView)aView forAttributeType:(CPAttributeType)attributeType
458 {
459  if (attributeType == 0)
460  return [[aView selectedItem] representedObject];
461 
462  var value;
463  if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
464  value = [aView intValue];
465  else if (attributeType == CPBooleanAttributeType)
466  value = [aView state];
467  else
468  value = [aView stringValue];
469 
471 }
472 
473 - (int)_rowType
474 {
475  return (_templateType - 1);
476 }
477 
478 - (id)copy
479 {
481 }
482 
483 + (id)_operatorsForAttributeType:(CPAttributeType)attributeType
484 {
485  var operators_array = [CPMutableArray array];
486 
487  switch (attributeType)
488  {
489  case CPInteger16AttributeType : [operators_array addObjects:4,5,0,2,1,3];
490  break;
491  case CPInteger32AttributeType : [operators_array addObjects:4,5,0,2,1,3];
492  break;
493  case CPInteger64AttributeType : [operators_array addObjects:4,5,0,2,1,3];
494  break;
495  case CPDecimalAttributeType : [operators_array addObjects:4,5,0,2,1,3];
496  break;
497  case CPDoubleAttributeType : [operators_array addObjects:4,5,0,2,1,3];
498  break;
499  case CPFloatAttributeType : [operators_array addObjects:4,5,0,2,1,3];
500  break;
501  case CPStringAttributeType : [operators_array addObjects:99,4,5,8,9];
502  break;
503  case CPBooleanAttributeType : [operators_array addObjects:4,5];
504  break;
505  case CPDateAttributeType : [operators_array addObjects:4,5,0,2,1,3];
506  break;
507  default : CPLogConsole("Cannot create operators for an CPAttributeType " + attributeType);
508  break;
509  }
510 
511  return operators_array;
512 }
513 
514 - (int)_templateType
515 {
516  return _templateType;
517 }
518 
519 - (id)_displayValueForPredicateOperator:(int)operator
520 {
521  var value;
522 
523  switch (operator)
524  {
525  case CPLessThanPredicateOperatorType : value = @"is less than";
526  break;
527  case CPLessThanOrEqualToPredicateOperatorType : value = @"is less than or equal to";
528  break;
529  case CPGreaterThanPredicateOperatorType : value = @"is greater than";
530  break;
531  case CPGreaterThanOrEqualToPredicateOperatorType : value = @"is greater than or equal to";
532  break;
533  case CPEqualToPredicateOperatorType : value = @"is";
534  break;
535  case CPNotEqualToPredicateOperatorType : value = @"is not";
536  break;
537  case CPMatchesPredicateOperatorType : value = @"matches";
538  break;
539  case CPLikePredicateOperatorType : value = @"is like";
540  break;
541  case CPBeginsWithPredicateOperatorType : value = @"begins with";
542  break;
543  case CPEndsWithPredicateOperatorType : value = @"ends with";
544  break;
545  case CPInPredicateOperatorType : value = @"in";
546  break;
547  case CPContainsPredicateOperatorType : value = @"contains";
548  break;
549  case CPBetweenPredicateOperatorType : value = @"between";
550  break;
551  default : CPLogConsole(@"unknown predicate operator %d" + operator);
552  }
553 
554  return value;
555 }
556 
557 - (id)_displayValueForCompoundPredicateType:(unsigned int)predicateType
558 {
559  var value;
560  switch (predicateType)
561  {
562  case CPNotPredicateType: value = @"None";
563  break;
564  case CPAndPredicateType: value = @"All";
565  break;
566  case CPOrPredicateType: value = @"Any";
567  break;
568  default : value = [CPString stringWithFormat:@"unknown compound predicate type %d",predicateType];
569  }
570 
571  return value;
572 }
573 
574 - (id)_displayValueForConstantValue:(id)value
575 {
576  return [value description]; // number, date, string, ... localize
577 }
578 
579 - (id)_displayValueForKeyPath:(CPString)keyPath
580 {
581  return keyPath; // localize
582 }
583 
584 - (CPPopUpButton)_viewFromExpressions:(CPArray)expressions
585 {
586  var popup = [[CPPopUpButton alloc] initWithFrame:CPMakeRect(0, 0, 100, 18)],
587  count = [expressions count];
588 
589  for (var i = 0; i < count; i++)
590  {
591  var exp = expressions[i],
592  type = [exp expressionType],
593  title;
594 
595  switch (type)
596  {
597  case CPKeyPathExpressionType: title = [self _displayValueForKeyPath:[exp keyPath]];
598  break;
599  case CPConstantValueExpressionType: title = [self _displayValueForConstantValue:[exp constantValue]];
600  break;
601  default: [CPException raise:CPInvalidArgumentException reason:@"Invalid Expression type " + type];
602  break;
603  }
604 
605  var item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
606  [item setRepresentedObject:exp];
607  [popup addItem:item];
608  }
609 
610  [popup sizeToFit];
611 
612  return popup;
613 }
614 
615 - (CPPopUpButton)_viewFromOperatorTypes:(CPArray)operators
616 {
617  var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
618  count = [operators count];
619 
620  for (var i = 0; i < count; i++)
621  {
622  var op = operators[i],
623  title = [self _displayValueForPredicateOperator:op],
624  item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
625 
626  [item setRepresentedObject:op];
627  [popup addItem:item];
628  }
629 
630  [popup sizeToFit];
631 
632  return popup;
633 }
634 
635 - (CPView)_viewFromCompoundTypes:(CPArray)compoundTypes
636 {
637  var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
638  count = [compoundTypes count];
639 
640  for (var i = 0; i < count; i++)
641  {
642  var type = compoundTypes[i],
643  title = [self _displayValueForCompoundPredicateType:type],
644  item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
645 
646  [item setRepresentedObject:type];
647  [popup addItem:item];
648  }
649 
650  [popup sizeToFit];
651 
652  return popup;
653 }
654 
655 - (CPView)_viewFromAttributeType:(CPAttributeType)attributeType
656 {
657  var view;
658 
659  if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
660  {
661  view = [self _textFieldWithFrame:CGRectMake(0, 0, 50, 26)];
662  }
663  else if (attributeType == CPStringAttributeType)
664  {
665  view = [self _textFieldWithFrame:CGRectMake(0, 0, 150, 26)];
666  }
667  else if (attributeType == CPBooleanAttributeType)
668  {
669  view = [[CPCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 26)];
670  }
671  else if (attributeType == CPDateAttributeType)
672  view = [[CPDatePicker alloc] initWithFrame:CGRectMake(0, 0, 150, 26)];
673  else
674  return nil;
675 
676  [view setTag:attributeType];
677 
678  return view;
679 }
680 
681 - (CPTextField)_textFieldWithFrame:(CGRect)frame
682 {
683  var textField = [[CPTextField alloc] initWithFrame:frame];
684  [textField setBezeled:YES];
685  [textField setBezelStyle:CPTextFieldSquareBezel];
686  [textField setBordered:YES];
687  [textField setEditable:YES];
688  [textField setFont:[CPFont systemFontOfSize:10]];
689  [textField setSendsActionOnEndEditing:YES];
690 
691  return textField;
692 }
693 
694 - (void)_setOptions:(unsigned int)options
695 {
696  _predicateOptions = options;
697 }
698 
699 - (void)_setModifier:(unsigned int)modifier
700 {
701  _predicateModifier = modifier;
702 }
703 
704 - (CPString)description
705 {
706  if (_templateType == 2)
707  return [CPString stringWithFormat:@"<%@ %p %@>",[self className],self,[[self compoundTypes] componentsJoinedByString:@", "]];
708  else if (_templateType == 1 && _rightIsWildcard)
709  return [CPString stringWithFormat:@"<%@ %p [%@] [%@] %d>",[self className],self,[[self leftExpressions] componentsJoinedByString:@", "],[[self operators] componentsJoinedByString:@", "],[self rightExpressionAttributeType]];
710  else
711  return [CPString stringWithFormat:@"<%@ %p [%@] [%@] [%@]>",[self className],self,[[self leftExpressions] componentsJoinedByString:@", "],[[self operators] componentsJoinedByString:@", "],[[self rightExpressions] componentsJoinedByString:@", "]];
712 }
713 
714 /*
715 - (void)_setLeftExpressionObject:(id)object
716 {
717 }
718 - (void)_setRightExpressionObject:(id)object
719 {
720 }
721 - (BOOL)_predicateIsNoneAreTrue:(id)predicate
722 {
723 }
724 - (id)_viewFromExpressionObject:(id)object
725 {
726 }
727 */
728 @end
729 
730 var CPPredicateTemplateTypeKey = @"CPPredicateTemplateType",
731  CPPredicateTemplateOptionsKey = @"CPPredicateTemplateOptions",
732  CPPredicateTemplateModifierKey = @"CPPredicateTemplateModifier",
733  CPPredicateTemplateLeftAttributeTypeKey = @"CPPredicateTemplateLeftAttributeType",
734  CPPredicateTemplateRightAttributeTypeKey = @"CPPredicateTemplateRightAttributeType",
735  CPPredicateTemplateLeftIsWildcardKey = @"CPPredicateTemplateLeftIsWildcard",
736  CPPredicateTemplateRightIsWildcardKey = @"CPPredicateTemplateRightIsWildcard",
737  CPPredicateTemplateViewsKey = @"CPPredicateTemplateViews";
738 
739 @implementation CPPredicateEditorRowTemplate (CPCoding)
740 
741 - (id)initWithCoder:(CPCoder)coder
742 {
743  self = [super init];
744  if (self != nil)
745  {
746  _templateType = [coder decodeIntForKey:CPPredicateTemplateTypeKey];
747  _predicateOptions = [coder decodeIntForKey:CPPredicateTemplateOptionsKey];
748  _predicateModifier = [coder decodeIntForKey:CPPredicateTemplateModifierKey];
749  _leftAttributeType = [coder decodeIntForKey:CPPredicateTemplateLeftAttributeTypeKey];
750  _rightAttributeType = [coder decodeIntForKey:CPPredicateTemplateRightAttributeTypeKey];
751  _leftIsWildcard = [coder decodeBoolForKey:CPPredicateTemplateLeftIsWildcardKey];
752  _rightIsWildcard = [coder decodeBoolForKey:CPPredicateTemplateRightIsWildcardKey];
753  _views = [coder decodeObjectForKey:CPPredicateTemplateViewsKey];
754 
755  // In Xcode 4, when the menu item title == template's expression keypath, representedObject is empty.
756  // So we need to regenerate expressions from titles.
757  if (_templateType == 1 && _leftIsWildcard == NO)
758  {
759  var itemArray = [_views[0] itemArray],
760  count = [itemArray count];
761 
762  for (var i = 0; i < count; i++)
763  {
764  var item = itemArray[i];
765  if ([item representedObject] == nil)
766  {
767  var exp = [CPExpression expressionForKeyPath:[item title]];
768  [item setRepresentedObject:exp];
769  }
770  }
771  }
772  }
773 
774  return self;
775 }
776 
777 - (void)encodeWithCoder:(CPCoder)coder
778 {
779  [coder encodeInt:_templateType forKey:CPPredicateTemplateTypeKey];
780  [coder encodeInt:_predicateOptions forKey:CPPredicateTemplateOptionsKey];
781  [coder encodeInt:_predicateModifier forKey:CPPredicateTemplateModifierKey];
782  [coder encodeInt:_leftAttributeType forKey:CPPredicateTemplateLeftAttributeTypeKey];
783  [coder encodeInt:_rightAttributeType forKey:CPPredicateTemplateRightAttributeTypeKey];
784  [coder encodeBool:_leftIsWildcard forKey:CPPredicateTemplateLeftIsWildcardKey];
785  [coder encodeBool:_rightIsWildcard forKey:CPPredicateTemplateRightIsWildcardKey];
786  [coder encodeObject:_views forKey:CPPredicateTemplateViewsKey];
787 }
788 
789 @end
792 @implementation CPPredicateEditorRowTemplate (CPSynthesizedAccessors)
793 
794 
797 - (int)_templateType
798 {
799  return _templateType;
800 }
801 
805 - (void)_setTemplateType:(int)aValue
806 {
807  _templateType = aValue;
808 }
809 
813 - (void)_setOptions:(unsigned)aValue
814 {
815  _predicateOptions = aValue;
816 }
817 
821 - (void)_setModifier:(unsigned)aValue
822 {
823  _predicateModifier = aValue;
824 }
825 
829 - (unsigned)leftAttributeType
830 {
831  return _leftAttributeType;
832 }
833 
837 - (void)_setLeftAttributeType:(unsigned)aValue
838 {
839  _leftAttributeType = aValue;
840 }
841 
845 - (unsigned)rightAttributeType
846 {
847  return _rightAttributeType;
848 }
849 
853 - (void)_setRightAttributeType:(unsigned)aValue
854 {
855  _rightAttributeType = aValue;
856 }
857 
861 - (BOOL)leftIsWildcard
862 {
863  return _leftIsWildcard;
864 }
865 
869 - (void)setLeftIsWildcard:(BOOL)aValue
870 {
871  _leftIsWildcard = aValue;
872 }
873 
877 - (BOOL)rightIsWildcard
878 {
879  return _rightIsWildcard;
880 }
881 
885 - (void)setRightIsWildcard:(BOOL)aValue
886 {
887  _rightIsWildcard = aValue;
888 }
889 
893 - (void)setTemplateViews:(CPArray)aValue
894 {
895  _views = aValue;
896 }
897 
898 @end