API  0.9.7
 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 
23 
24 
25 // NOTE: CPDatePicker is not implemented yet
26 @class CPDatePicker
27 
28 
29 CPUndefinedAttributeType = 0;
30 CPInteger16AttributeType = 100;
31 CPInteger32AttributeType = 200;
32 CPInteger64AttributeType = 300;
33 CPDecimalAttributeType = 400;
34 CPDoubleAttributeType = 500;
35 CPFloatAttributeType = 600;
36 CPStringAttributeType = 700;
37 CPBooleanAttributeType = 800;
38 CPDateAttributeType = 900;
39 CPBinaryDataAttributeType = 1000;
40 CPTransformableAttributeType = 1800;
41 
42 @implementation CPPredicateEditorRowTemplate : CPObject
43 {
44  int _templateType;
45  unsigned _predicateOptions;
46  unsigned _predicateModifier;
47  unsigned _leftAttributeType;
48  unsigned _rightAttributeType;
49  BOOL _leftIsWildcard;
50  BOOL _rightIsWildcard;
51  CPArray _views;
52 
53 }
54 
89 - (id)initWithLeftExpressions:(CPArray)leftExpressions rightExpressions:(CPArray)rightExpressions modifier:(int)modifier operators:(CPArray)operators options:(int)options
90 {
91  self = [super init];
92  if (self != nil)
93  {
94  _templateType = 1;
95  _leftIsWildcard = NO;
96  _rightIsWildcard = NO;
97  _leftAttributeType = 0;
98  _rightAttributeType = 0;
99  _predicateModifier = modifier;
100  _predicateOptions = options;
101 
102  var leftView = [self _viewFromExpressions:leftExpressions],
103  rightView = [self _viewFromExpressions:rightExpressions],
104  middleView = [self _viewFromOperatorTypes:operators];
105 
106  _views = [[CPArray alloc] initWithObjects:leftView, middleView, rightView];
107  }
108 
109  return self;
110 }
111 
121 - (id)initWithLeftExpressions:(CPArray )leftExpressions rightExpressionAttributeType:(CPAttributeType)attributeType modifier:(CPComparisonPredicateModifier)modifier operators:(CPArray )operators options:(int)options
122 {
123  self = [super init];
124  if (self != nil)
125  {
126  var leftView = [self _viewFromExpressions:leftExpressions],
127  middleView = [self _viewFromOperatorTypes:operators],
128  rightView = [self _viewFromAttributeType:attributeType];
129 
130  _templateType = 1;
131  _leftIsWildcard = NO;
132  _rightIsWildcard = YES;
133  _leftAttributeType = 0;
134  _rightAttributeType = attributeType;
135  _predicateModifier = modifier;
136  _predicateOptions = options;
137  _views = [[CPArray alloc] initWithObjects:leftView, middleView, rightView];
138  }
139 
140  return self;
141 }
142 
149 - (id)initWithCompoundTypes:(CPArray )compoundTypes
150 {
151  self = [super init];
152  if (self != nil)
153  {
154  var leftView = [self _viewFromCompoundTypes:compoundTypes],
155  rightView = [[CPPopUpButton alloc] init];
156 
157  [rightView addItemWithTitle:@"of the following are true"];
158 
159  _templateType = 2;
160  _leftIsWildcard = NO;
161  _rightIsWildcard = NO;
162  _rightAttributeType = 0;
163  _views = [[CPArray alloc] initWithObjects:leftView, rightView];
164  }
165  return self;
166 }
167 
178 - (double)matchForPredicate:(CPPredicate)predicate
179 {
180  // How exactly this value (float 0-1) is computed ?
181  if ([self _templateType] == 2 && [predicate isKindOfClass:[CPCompoundPredicate class]])
182  {
183  if ([[self compoundTypes] containsObject:[predicate compoundPredicateType]])
184  return 1;
185  }
186  else if ([self _templateType] == 1 && [predicate isKindOfClass:[CPComparisonPredicate class]])
187  {
188  if (!_leftIsWildcard && ![[self leftExpressions] containsObject:[predicate leftExpression]])
189  return 0;
190 
191  if (![[self operators] containsObject:[predicate predicateOperatorType]])
192  return 0;
193 
194  if (!_rightIsWildcard && ![[self rightExpressions] containsObject:[predicate rightExpression]])
195  return 0;
196 
197  return 1;
198  }
199 
200  return 0;
201 }
202 
208 - (CPArray)templateViews
209 {
210  return _views;
211 }
212 
220 - (void)setPredicate:(CPPredicate)predicate
221 {
222  if (_templateType == 2)
223  [self _setCompoundPredicate:predicate];
224  else
225  [self _setComparisonPredicate:predicate];
226 }
227 
234 - (CPArray)displayableSubpredicatesOfPredicate:(CPPredicate)predicate
235 {
236  if ([predicate isKindOfClass:[CPCompoundPredicate class]])
237  {
238  var subpredicates = [predicate subpredicates];
239  if ([subpredicates count] == 0)
240  return nil;
241 
242  return subpredicates;
243  }
244 
245  return nil;
246 }
247 
256 - (CPPredicate)predicateWithSubpredicates:(CPArray)subpredicates
257 {
258  if (_templateType == 2)
259  {
260  var type = [[_views[0] selectedItem] representedObject];
261  return [[CPCompoundPredicate alloc] initWithType:type subpredicates:subpredicates];
262  }
263 
264  if (_templateType == 1)
265  {
266  var lhs = [self _leftExpression],
267  rhs = [self _rightExpression],
268  operator = [[_views[1] selectedItem] representedObject];
269 
270  return [CPComparisonPredicate predicateWithLeftExpression:lhs
271  rightExpression:rhs
272  modifier:[self modifier]
273  type:operator
274  options:[self options]];
275  }
276 
277  return nil;
278 }
279 
288 - (CPArray)leftExpressions
289 {
290  if (_templateType == 1 && !_leftIsWildcard)
291  {
292  var view = [_views objectAtIndex:0];
293  return [[view itemArray] valueForKey:@"representedObject"];
294  }
295 
296  return nil;
297 }
298 
303 - (CPArray)rightExpressions
304 {
305  if (_templateType == 1 && !_rightIsWildcard)
306  {
307  var view = [_views objectAtIndex:2];
308  return [[view itemArray] valueForKey:@"representedObject"];
309  }
310 
311  return nil;
312 }
313 
318 - (CPArray)compoundTypes
319 {
320  if (_templateType == 2)
321  {
322  var view = [_views objectAtIndex:0];
323  return [[view itemArray] valueForKey:@"representedObject"];
324  }
325 
326  return nil;
327 }
328 
334 {
335  if (_templateType == 1)
336  return _predicateModifier;
337 
338  return nil;
339 }
340 
345 - (CPArray)operators
346 {
347  if (_templateType == 1)
348  {
349  var view = [_views objectAtIndex:1];
350  return [[view itemArray] valueForKey:@"representedObject"];
351  }
352 
353  return nil;
354 }
355 
360 - (int)options
361 {
362  if (_templateType == 1)
363  return _predicateOptions;
364 
365  return nil;
366 }
367 
372 - (CPAttributeType)rightExpressionAttributeType
373 {
374  return _rightAttributeType;
375 }
376 
381 - (CPAttributeType)leftExpressionAttributeType
382 {
383  return _leftAttributeType;
384 }
385 
387 + (id)_bestMatchForPredicate:(CPPredicate)predicate inTemplates:(CPArray)templates quality:(double)quality
388 {
389  var count = [templates count],
390  match_value = 0,
391  templateIndex = CPNotFound,
392  i;
393 
394  for (i = 0; i < count; i++)
395  {
396  var template = [templates objectAtIndex:i],
397  amatch = [template matchForPredicate:predicate];
398 
399  if (amatch > match_value)
400  {
401  templateIndex = i;
402  match_value = amatch;
403  }
404  }
405 
406  if (templateIndex == CPNotFound)
407  {
408  [CPException raise:CPRangeException reason:@"Unable to find template matching predicate: " + [predicate predicateFormat]];
409  return nil;
410  }
411 
412  return [templates objectAtIndex:templateIndex];
413 }
414 
415 - (void)_setCompoundPredicate:(CPCompoundPredicate)predicate
416 {
417  var left = [_views objectAtIndex:0],
418  type = [predicate compoundPredicateType],
419  index = [left indexOfItemWithRepresentedObject:type];
420 
421  [left selectItemAtIndex:index];
422 }
423 
424 - (void)_setComparisonPredicate:(CPComparisonPredicate)predicate
425 {
426  var left = [_views objectAtIndex:0],
427  middle = [_views objectAtIndex:1],
428  right = [_views objectAtIndex:2],
429  leftExpression = [predicate leftExpression],
430  rightExpression = [predicate rightExpression],
431  operator = [predicate predicateOperatorType];
432 
433  if (_leftIsWildcard)
434  [left setObjectValue:[leftExpression constantValue]];
435  else
436  {
437  var index = [left indexOfItemWithRepresentedObject:leftExpression];
438  [left selectItemAtIndex:index];
439  }
440 
441  var op_index = [middle indexOfItemWithRepresentedObject:operator];
442  [middle selectItemAtIndex:op_index];
443 
444  if (_rightIsWildcard)
445  [right setObjectValue:[rightExpression constantValue]];
446  else
447  {
448  var index = [right indexOfItemWithRepresentedObject:rightExpression];
449  [right selectItemAtIndex:index];
450  }
451 }
452 
453 - (CPExpression)_leftExpression
454 {
455  return [self _expressionFromView:_views[0] forAttributeType:_leftAttributeType];
456 }
457 
458 - (CPExpression)_rightExpression
459 {
460  return [self _expressionFromView:_views[2] forAttributeType:_rightAttributeType];
461 }
462 
463 - (CPExpression)_expressionFromView:(CPView)aView forAttributeType:(CPAttributeType)attributeType
464 {
465  if (attributeType == 0)
466  return [[aView selectedItem] representedObject];
467 
468  var value;
469  if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
470  value = [aView intValue];
471  else if (attributeType == CPBooleanAttributeType)
472  value = [aView state];
473  else
474  value = [aView stringValue];
475 
476  return [CPExpression expressionForConstantValue:value];
477 }
478 
479 - (int)_rowType
480 {
481  return (_templateType - 1);
482 }
483 
484 - (id)copy
485 {
487 }
488 
489 + (id)_operatorsForAttributeType:(CPAttributeType)attributeType
490 {
491  var operators_array = [CPMutableArray array];
492 
493  switch (attributeType)
494  {
495  case CPInteger16AttributeType : [operators_array addObjects:4,5,0,2,1,3];
496  break;
497  case CPInteger32AttributeType : [operators_array addObjects:4,5,0,2,1,3];
498  break;
499  case CPInteger64AttributeType : [operators_array addObjects:4,5,0,2,1,3];
500  break;
501  case CPDecimalAttributeType : [operators_array addObjects:4,5,0,2,1,3];
502  break;
503  case CPDoubleAttributeType : [operators_array addObjects:4,5,0,2,1,3];
504  break;
505  case CPFloatAttributeType : [operators_array addObjects:4,5,0,2,1,3];
506  break;
507  case CPStringAttributeType : [operators_array addObjects:99,4,5,8,9];
508  break;
509  case CPBooleanAttributeType : [operators_array addObjects:4,5];
510  break;
511  case CPDateAttributeType : [operators_array addObjects:4,5,0,2,1,3];
512  break;
513  default : CPLogConsole("Cannot create operators for an CPAttributeType " + attributeType);
514  break;
515  }
516 
517  return operators_array;
518 }
519 
520 - (int)_templateType
521 {
522  return _templateType;
523 }
524 
525 - (id)_displayValueForPredicateOperator:(int)operator
526 {
527  var value;
528 
529  switch (operator)
530  {
531  case CPLessThanPredicateOperatorType : value = @"is less than";
532  break;
533  case CPLessThanOrEqualToPredicateOperatorType : value = @"is less than or equal to";
534  break;
535  case CPGreaterThanPredicateOperatorType : value = @"is greater than";
536  break;
537  case CPGreaterThanOrEqualToPredicateOperatorType : value = @"is greater than or equal to";
538  break;
539  case CPEqualToPredicateOperatorType : value = @"is";
540  break;
541  case CPNotEqualToPredicateOperatorType : value = @"is not";
542  break;
543  case CPMatchesPredicateOperatorType : value = @"matches";
544  break;
545  case CPLikePredicateOperatorType : value = @"is like";
546  break;
547  case CPBeginsWithPredicateOperatorType : value = @"begins with";
548  break;
549  case CPEndsWithPredicateOperatorType : value = @"ends with";
550  break;
551  case CPInPredicateOperatorType : value = @"in";
552  break;
553  case CPContainsPredicateOperatorType : value = @"contains";
554  break;
555  case CPBetweenPredicateOperatorType : value = @"between";
556  break;
557  default : CPLogConsole(@"unknown predicate operator %d" + operator);
558  }
559 
560  return value;
561 }
562 
563 - (id)_displayValueForCompoundPredicateType:(unsigned int)predicateType
564 {
565  var value;
566  switch (predicateType)
567  {
568  case CPNotPredicateType: value = @"None";
569  break;
570  case CPAndPredicateType: value = @"All";
571  break;
572  case CPOrPredicateType: value = @"Any";
573  break;
574  default : value = [CPString stringWithFormat:@"unknown compound predicate type %d",predicateType];
575  }
576 
577  return value;
578 }
579 
580 - (id)_displayValueForConstantValue:(id)value
581 {
582  return [value description]; // number, date, string, ... localize
583 }
584 
585 - (id)_displayValueForKeyPath:(CPString)keyPath
586 {
587  return keyPath; // localize
588 }
589 
590 - (CPPopUpButton)_viewFromExpressions:(CPArray)expressions
591 {
592  var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
593  count = [expressions count];
594 
595  for (var i = 0; i < count; i++)
596  {
597  var exp = expressions[i],
598  type = [exp expressionType],
599  title;
600 
601  switch (type)
602  {
603  case CPKeyPathExpressionType: title = [self _displayValueForKeyPath:[exp keyPath]];
604  break;
605  case CPConstantValueExpressionType: title = [self _displayValueForConstantValue:[exp constantValue]];
606  break;
607  default: [CPException raise:CPInvalidArgumentException reason:@"Invalid Expression type " + type];
608  break;
609  }
610 
611  var item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
612  [item setRepresentedObject:exp];
613  [popup addItem:item];
614  }
615 
616  [popup sizeToFit];
617 
618  return popup;
619 }
620 
621 - (CPPopUpButton)_viewFromOperatorTypes:(CPArray)operators
622 {
623  var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
624  count = [operators count];
625 
626  for (var i = 0; i < count; i++)
627  {
628  var op = operators[i],
629  title = [self _displayValueForPredicateOperator:op],
630  item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
631 
632  [item setRepresentedObject:op];
633  [popup addItem:item];
634  }
635 
636  [popup sizeToFit];
637 
638  return popup;
639 }
640 
641 - (CPView)_viewFromCompoundTypes:(CPArray)compoundTypes
642 {
643  var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
644  count = [compoundTypes count];
645 
646  for (var i = 0; i < count; i++)
647  {
648  var type = compoundTypes[i],
649  title = [self _displayValueForCompoundPredicateType:type],
650  item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
651 
652  [item setRepresentedObject:type];
653  [popup addItem:item];
654  }
655 
656  [popup sizeToFit];
657 
658  return popup;
659 }
660 
661 - (CPView)_viewFromAttributeType:(CPAttributeType)attributeType
662 {
663  var view;
664 
665  if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
666  {
667  view = [self _textFieldWithFrame:CGRectMake(0, 0, 50, 26)];
668  }
669  else if (attributeType == CPStringAttributeType)
670  {
671  view = [self _textFieldWithFrame:CGRectMake(0, 0, 150, 26)];
672  }
673  else if (attributeType == CPBooleanAttributeType)
674  {
675  view = [[CPCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 26)];
676  }
677  else if (attributeType == CPDateAttributeType)
678  view = [[CPDatePicker alloc] initWithFrame:CGRectMake(0, 0, 150, 26)];
679  else
680  return nil;
681 
682  [view setTag:attributeType];
683 
684  return view;
685 }
686 
687 - (CPTextField)_textFieldWithFrame:(CGRect)frame
688 {
689  var textField = [[CPTextField alloc] initWithFrame:frame];
690  [textField setBezeled:YES];
691  [textField setBezelStyle:CPTextFieldSquareBezel];
692  [textField setBordered:YES];
693  [textField setEditable:YES];
694  [textField setFont:[CPFont systemFontOfSize:10]];
695  [textField setSendsActionOnEndEditing:YES];
696 
697  return textField;
698 }
699 
700 - (void)_setOptions:(unsigned)options
701 {
702  _predicateOptions = options;
703 }
704 
705 - (void)_setModifier:(unsigned)modifier
706 {
707  _predicateModifier = modifier;
708 }
709 
710 - (CPString)description
711 {
712  if (_templateType == 2)
713  return [CPString stringWithFormat:@"<%@ %p %@>",[self className],self,[[self compoundTypes] componentsJoinedByString:@", "]];
714  else if (_templateType == 1 && _rightIsWildcard)
715  return [CPString stringWithFormat:@"<%@ %p [%@] [%@] %d>",[self className],self,[[self leftExpressions] componentsJoinedByString:@", "],[[self operators] componentsJoinedByString:@", "],[self rightExpressionAttributeType]];
716  else
717  return [CPString stringWithFormat:@"<%@ %p [%@] [%@] [%@]>",[self className],self,[[self leftExpressions] componentsJoinedByString:@", "],[[self operators] componentsJoinedByString:@", "],[[self rightExpressions] componentsJoinedByString:@", "]];
718 }
719 
720 /*
721 - (void)_setLeftExpressionObject:(id)object
722 {
723 }
724 - (void)_setRightExpressionObject:(id)object
725 {
726 }
727 - (BOOL)_predicateIsNoneAreTrue:(id)predicate
728 {
729 }
730 - (id)_viewFromExpressionObject:(id)object
731 {
732 }
733 */
734 @end
735 
736 var CPPredicateTemplateTypeKey = @"CPPredicateTemplateType",
737  CPPredicateTemplateOptionsKey = @"CPPredicateTemplateOptions",
738  CPPredicateTemplateModifierKey = @"CPPredicateTemplateModifier",
739  CPPredicateTemplateLeftAttributeTypeKey = @"CPPredicateTemplateLeftAttributeType",
740  CPPredicateTemplateRightAttributeTypeKey = @"CPPredicateTemplateRightAttributeType",
741  CPPredicateTemplateLeftIsWildcardKey = @"CPPredicateTemplateLeftIsWildcard",
742  CPPredicateTemplateRightIsWildcardKey = @"CPPredicateTemplateRightIsWildcard",
743  CPPredicateTemplateViewsKey = @"CPPredicateTemplateViews";
744 
745 @implementation CPPredicateEditorRowTemplate (CPCoding)
746 
747 - (id)initWithCoder:(CPCoder)coder
748 {
749  self = [super init];
750  if (self != nil)
751  {
752  _templateType = [coder decodeIntForKey:CPPredicateTemplateTypeKey];
753  _predicateOptions = [coder decodeIntForKey:CPPredicateTemplateOptionsKey];
754  _predicateModifier = [coder decodeIntForKey:CPPredicateTemplateModifierKey];
755  _leftAttributeType = [coder decodeIntForKey:CPPredicateTemplateLeftAttributeTypeKey];
756  _rightAttributeType = [coder decodeIntForKey:CPPredicateTemplateRightAttributeTypeKey];
757  _leftIsWildcard = [coder decodeBoolForKey:CPPredicateTemplateLeftIsWildcardKey];
758  _rightIsWildcard = [coder decodeBoolForKey:CPPredicateTemplateRightIsWildcardKey];
759  _views = [coder decodeObjectForKey:CPPredicateTemplateViewsKey];
760 
761  // In Xcode 4, when the menu item title == template's expression keypath, representedObject is empty.
762  // So we need to regenerate expressions from titles.
763  if (_templateType == 1 && _leftIsWildcard == NO)
764  {
765  var itemArray = [_views[0] itemArray],
766  count = [itemArray count];
767 
768  for (var i = 0; i < count; i++)
769  {
770  var item = itemArray[i];
771  if ([item representedObject] == nil)
772  {
773  var exp = [CPExpression expressionForKeyPath:[item title]];
774  [item setRepresentedObject:exp];
775  }
776  }
777  }
778  }
779 
780  return self;
781 }
782 
783 - (void)encodeWithCoder:(CPCoder)coder
784 {
785  [coder encodeInt:_templateType forKey:CPPredicateTemplateTypeKey];
786  [coder encodeInt:_predicateOptions forKey:CPPredicateTemplateOptionsKey];
787  [coder encodeInt:_predicateModifier forKey:CPPredicateTemplateModifierKey];
788  [coder encodeInt:_leftAttributeType forKey:CPPredicateTemplateLeftAttributeTypeKey];
789  [coder encodeInt:_rightAttributeType forKey:CPPredicateTemplateRightAttributeTypeKey];
790  [coder encodeBool:_leftIsWildcard forKey:CPPredicateTemplateLeftIsWildcardKey];
791  [coder encodeBool:_rightIsWildcard forKey:CPPredicateTemplateRightIsWildcardKey];
792  [coder encodeObject:_views forKey:CPPredicateTemplateViewsKey];
793 }
794 
795 @end
798 @implementation CPPredicateEditorRowTemplate (CPSynthesizedAccessors)
799 
800 
803 - (int)_templateType
804 {
805  return _templateType;
806 }
807 
811 - (void)_setTemplateType:(int)aValue
812 {
813  _templateType = aValue;
814 }
815 
819 - (void)_setOptions:(unsigned)aValue
820 {
821  _predicateOptions = aValue;
822 }
823 
827 - (void)_setModifier:(unsigned)aValue
828 {
829  _predicateModifier = aValue;
830 }
831 
835 - (unsigned)leftAttributeType
836 {
837  return _leftAttributeType;
838 }
839 
843 - (void)_setLeftAttributeType:(unsigned)aValue
844 {
845  _leftAttributeType = aValue;
846 }
847 
851 - (unsigned)rightAttributeType
852 {
853  return _rightAttributeType;
854 }
855 
859 - (void)_setRightAttributeType:(unsigned)aValue
860 {
861  _rightAttributeType = aValue;
862 }
863 
867 - (BOOL)leftIsWildcard
868 {
869  return _leftIsWildcard;
870 }
871 
875 - (void)setLeftIsWildcard:(BOOL)aValue
876 {
877  _leftIsWildcard = aValue;
878 }
879 
883 - (BOOL)rightIsWildcard
884 {
885  return _rightIsWildcard;
886 }
887 
891 - (void)setRightIsWildcard:(BOOL)aValue
892 {
893  _rightIsWildcard = aValue;
894 }
895 
899 - (void)setTemplateViews:(CPArray)aValue
900 {
901  _views = aValue;
902 }
903 
904 @end