API  0.9.10
CPObjectController.j
Go to the documentation of this file.
1 /*
2  * CPObjectController.j
3  * AppKit
4  *
5  * Created by Ross Boucher.
6  * Copyright 2009, 280 North, Inc.
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 
35 @implementation CPObjectController : CPController
36 {
37  id _contentObject;
38  id _selection;
39 
40  Class _objectClass;
41  CPString _objectClassName;
42 
43  BOOL _isEditable;
44  BOOL _automaticallyPreparesContent;
45  BOOL _usesLazyFetching;
46  BOOL _isUsingManagedProxy;
47  _CPManagedProxy _managedProxy;
48 
49  CPCountedSet _observedKeys;
50 }
51 
52 + (void)initialize
53 {
54  if (self !== [CPObjectController class])
55  return;
56 
57  [self exposeBinding:@"editable"];
58  [self exposeBinding:@"contentObject"];
59 }
60 
62 {
63  return [CPSet setWithObjects:"content"];
64 }
65 
66 + (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey
67 {
68  if (aKey === @"contentObject")
69  return NO;
70 
71  return YES;
72 }
73 
75 {
76  return [CPSet setWithObject:"editable"];
77 }
78 
80 {
81  return [CPSet setWithObject:"editable"];
82 }
83 
85 {
86  return [CPSet setWithObjects:"editable", "selection"];
87 }
88 
92 - (id)init
93 {
94  return [self initWithContent:nil];
95 }
96 
103 - (id)initWithContent:(id)aContent
104 {
105  if (self = [super init])
106  {
107  [self setEditable:YES];
109 
110  _observedKeys = [[CPCountedSet alloc] init];
111  _selection = [[CPControllerSelectionProxy alloc] initWithController:self];
112 
113  [self setContent:aContent];
114  }
115 
116  return self;
117 }
118 
123 - (id)content
124 {
125  return _contentObject;
126 }
127 
132 - (void)setContent:(id)aContent
133 {
134  [self willChangeValueForKey:@"contentObject"];
135  [self _selectionWillChange];
136 
137  _contentObject = aContent;
138 
139  [self _selectionDidChange];
140  [self didChangeValueForKey:@"contentObject"];
141 }
142 
146 - (void)_setContentObject:(id)aContent
147 {
148  [self setContent:aContent];
149 }
150 
154 - (id)_contentObject
155 {
156  return [self content];
157 }
158 
166 - (void)setAutomaticallyPreparesContent:(BOOL)shouldAutomaticallyPrepareContent
167 {
168  _automaticallyPreparesContent = shouldAutomaticallyPrepareContent;
169 }
170 
176 {
177  return _automaticallyPreparesContent;
178 }
179 
185 - (void)setEntityName:(CPString)newEntityName
186 {
187  if (!_managedProxy)
188  {
189  _managedProxy = [[_CPManagedProxy alloc] init];
190  _isUsingManagedProxy = YES;
191  }
192 
193  [_managedProxy setEntityName:newEntityName];
194 }
195 
202 {
203  return [_managedProxy entityName];
204 }
205 
211 - (void)setFetchPredicate:(CPPredicate)newPredicate
212 {
213  [_managedProxy setFetchPredicate:newPredicate];
214 }
215 
221 - (CPPredicate)fetchPredicate
222 {
223  return [_managedProxy fetchPredicate];
224 }
225 
230 {
231  [self setContent:[self newObject]];
232 }
233 
239 - (void)setObjectClass:(Class)aClass
240 {
241  _objectClass = aClass;
242 }
243 
249 - (Class)objectClass
250 {
251  return _objectClass;
252 }
253 
257 - (id)_defaultNewObject
258 {
259  return [[[self objectClass] alloc] init];
260 }
261 
267 {
268  return [self _defaultNewObject];
269 }
270 
275 - (void)addObject:(id)anObject
276 {
277  [self setContent:anObject];
278 
279  var binderClass = [[self class] _binderClassForBinding:@"contentObject"];
280  [[binderClass getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
281 }
282 
287 - (void)removeObject:(id)anObject
288 {
289  if ([self content] === anObject)
290  [self setContent:nil];
291 
292  var binderClass = [[self class] _binderClassForBinding:@"contentObject"];
293  [[binderClass getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
294 }
295 
300 - (void)add:(id)aSender
301 {
302  // FIXME: This should happen on the next run loop?
303  [self addObject:[self newObject]];
304 }
305 
309 - (BOOL)canAdd
310 {
311  return [self isEditable];
312 }
313 
318 - (void)remove:(id)aSender
319 {
320  // FIXME: This should happen on the next run loop?
321  [self removeObject:[self content]];
322 }
323 
327 - (BOOL)canRemove
328 {
329  return [self isEditable] && [[self selectedObjects] count];
330 }
331 
336 - (void)setEditable:(BOOL)shouldBeEditable
337 {
338  _isEditable = shouldBeEditable;
339 }
340 
344 - (BOOL)isEditable
345 {
346  return _isEditable;
347 }
348 
352 - (CPArray)selectedObjects
353 {
354  return [[_CPObservableArray alloc] initWithArray:[_contentObject]];
355 }
356 
361 {
362  return _selection;
363 }
364 
368 - (void)_selectionWillChange
369 {
370  [_selection controllerWillChange];
371  [self willChangeValueForKey:@"selection"];
372 }
373 
377 - (void)_selectionDidChange
378 {
379  if (_selection === undefined || _selection === nil)
380  _selection = [[CPControllerSelectionProxy alloc] initWithController:self];
381 
382  [_selection controllerDidChange];
383  [self didChangeValueForKey:@"selection"];
384 }
385 
390 {
391  return _observedKeys;
392 }
393 
394 - (void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
395 {
396  [_observedKeys addObject:aKeyPath];
397  [super addObserver:anObserver forKeyPath:aKeyPath options:options context:context];
398 }
399 
400 - (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath
401 {
402  [_observedKeys removeObject:aKeyPath];
403  [super removeObserver:anObserver forKeyPath:aKeyPath];
404 }
405 
406 @end
407 
408 var CPObjectControllerContentKey = @"CPObjectControllerContentKey",
409  CPObjectControllerObjectClassNameKey = @"CPObjectControllerObjectClassNameKey",
410  CPObjectControllerIsEditableKey = @"CPObjectControllerIsEditableKey",
411  CPObjectControllerAutomaticallyPreparesContentKey = @"CPObjectControllerAutomaticallyPreparesContentKey",
412  CPObjectControllerUsesLazyFetchingKey = @"CPObjectControllerUsesLazyFetchingKey",
413  CPObjectControllerIsUsingManagedProxyKey = @"CPObjectControllerIsUsingManagedProxyKey",
414  CPObjectControllerManagedProxyKey = @"CPObjectControllerManagedProxyKey";
415 
417 
418 - (id)initWithCoder:(CPCoder)aCoder
419 {
420  self = [super init];
421 
422  if (self)
423  {
424  var objectClassName = [aCoder decodeObjectForKey:CPObjectControllerObjectClassNameKey],
425  objectClass = CPClassFromString(objectClassName),
426  content = [aCoder decodeObjectForKey:CPObjectControllerContentKey];
427 
428  [self setObjectClass:objectClass || [CPMutableDictionary class]];
429  [self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]];
430  [self setAutomaticallyPreparesContent:[aCoder decodeBoolForKey:CPObjectControllerAutomaticallyPreparesContentKey]];
431  [self setUsesLazyFetching:[aCoder decodeBoolForKey:CPObjectControllerUsesLazyFetchingKey]];
432  _isUsingManagedProxy = [aCoder decodeBoolForKey:CPObjectControllerIsUsingManagedProxyKey];
433  _managedProxy = [aCoder decodeObjectForKey:CPObjectControllerManagedProxyKey];
434 
435  if (content != nil)
436  [self setContent:content];
437 
438  _observedKeys = [[CPCountedSet alloc] init];
439  }
440 
441  return self;
442 }
443 
444 - (void)encodeWithCoder:(CPCoder)aCoder
445 {
446  [aCoder encodeObject:[self content] forKey:CPObjectControllerContentKey];
447 
448  if (_objectClass)
449  [aCoder encodeObject:CPStringFromClass(_objectClass) forKey:CPObjectControllerObjectClassNameKey];
450  else if (_objectClassName)
451  [aCoder encodeObject:_objectClassName forKey:CPObjectControllerObjectClassNameKey];
452 
453  [aCoder encodeBool:[self isEditable] forKey:CPObjectControllerIsEditableKey];
454  [aCoder encodeBool:[self automaticallyPreparesContent] forKey:CPObjectControllerAutomaticallyPreparesContentKey];
455  [aCoder encodeBool:[self usesLazyFetching] forKey:CPObjectControllerUsesLazyFetchingKey];
456  [aCoder encodeBool:_isUsingManagedProxy forKey:CPObjectControllerIsUsingManagedProxyKey];
457 
458  if (_managedProxy)
459  [aCoder encodeObject:_managedProxy forKey:CPObjectControllerManagedProxyKey];
460 }
461 
463 {
464  if (![self content] && [self automaticallyPreparesContent])
465  [self prepareContent];
466 }
467 
468 @end
469 
470 @implementation _CPObservationProxy : CPObject
471 {
472  id _keyPath;
473  id _observer;
474  id _object;
475 
476  BOOL _notifyObject;
477 
478  id _context;
479  int _options;
480 }
481 
482 - (id)initWithKeyPath:(id)aKeyPath observer:(id)anObserver object:(id)anObject
483 {
484  if (self = [super init])
485  {
486  _keyPath = aKeyPath;
487  _observer = anObserver;
488  _object = anObject;
489  }
490 
491  return self;
492 }
493 
494 - (id)observer
495 {
496  return _observer;
497 }
498 
499 - (id)keyPath
500 {
501  return _keyPath;
502 }
503 
504 - (id)context
505 {
506  return _context;
507 }
508 
509 - (int)options
510 {
511  return _options;
512 }
513 
514 - (void)setNotifyObject:(BOOL)notify
515 {
516  _notifyObject = notify;
517 }
518 
519 - (BOOL)isEqual:(id)anObject
520 {
521  if (self === anObject)
522  return YES;
523 
524  if (!anObject || [anObject class] !== [self class] || anObject._observer !== _observer || anObject._keyPath !== _keyPath || anObject._object !== _object)
525  return NO;
526 
527  return YES;
528 }
529 
530 - (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
531 {
532  if (_notifyObject)
533  [_object observeValueForKeyPath:aKeyPath ofObject:_object change:change context:context];
534 
535  [_observer observeValueForKeyPath:aKeyPath ofObject:_object change:change context:context];
536 }
537 
539 {
540  return [super description] + [CPString stringWithFormat:@"observation proxy for %@ on key path %@", _observer, _keyPath];
541 }
542 
543 @end
544 
545 // FIXME: This should subclass CPMutableArray not _CPJavaScriptArray
546 @implementation _CPObservableArray : _CPJavaScriptArray
547 {
548  CPArray _observationProxies;
549 }
550 
551 + (id)alloc
552 {
553  var a = [];
554  a.isa = self;
555 
556  var ivars = class_copyIvarList(self),
557  count = ivars.length;
558 
559  while (count--)
560  a[ivar_getName(ivars[count])] = nil;
561 
562  return a;
563 }
564 
566 {
567  return "<_CPObservableArray: " + [super description] + " >";
568 }
569 
570 - (id)initWithArray:(CPArray)anArray
571 {
572  self = [super initWithArray:anArray];
573 
574  self.isa = [_CPObservableArray class];
575  self._observationProxies = [];
576 
577  return self;
578 }
579 
580 - (void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
581 {
582  if (aKeyPath.charAt(0) === "@")
583  {
584  // Simple collection operators are scalar and can't be proxied
585  if ([_CPCollectionKVCOperator isSimpleCollectionOperator:aKeyPath])
586  return;
587 
588  var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self];
589 
590  proxy._options = options;
591  proxy._context = context;
592 
593  [_observationProxies addObject:proxy];
594 
595  var dotIndex = aKeyPath.indexOf("."),
596  remaining = aKeyPath.substring(dotIndex + 1),
597  indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
598 
599  [self addObserver:proxy toObjectsAtIndexes:indexes forKeyPath:remaining options:options context:context];
600  }
601  else
602  {
603  var indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
604  [self addObserver:anObserver toObjectsAtIndexes:indexes forKeyPath:aKeyPath options:options context:context];
605  }
606 }
607 
608 - (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath
609 {
610  if (aKeyPath.charAt(0) === "@")
611  {
612  // Simple collection operators are scalar and can't be proxied
613  if ([_CPCollectionKVCOperator isSimpleCollectionOperator:aKeyPath])
614  return;
615 
616  var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self],
617  index = [_observationProxies indexOfObject:proxy];
618 
619  proxy = [_observationProxies objectAtIndex:index];
620 
621  var dotIndex = aKeyPath.indexOf("."),
622  remaining = aKeyPath.substring(dotIndex + 1),
623  indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
624 
625  [self removeObserver:proxy fromObjectsAtIndexes:indexes forKeyPath:remaining];
626  }
627  else
628  {
629  var indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
630  [self removeObserver:anObserver fromObjectsAtIndexes:indexes forKeyPath:aKeyPath];
631  }
632 }
633 
634 - (void)insertObject:(id)anObject atIndex:(CPUInteger)anIndex
635 {
636  for (var i = 0, count = [_observationProxies count]; i < count; i++)
637  {
638  var proxy = [_observationProxies objectAtIndex:i],
639  keyPath = [proxy keyPath],
640  operator = keyPath.charAt(0) === ".";
641 
642  if (operator)
643  [self willChangeValueForKey:keyPath];
644 
645  [anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
646 
647  if (operator)
648  [self didChangeValueForKey:keyPath];
649  }
650 
651  [super insertObject:anObject atIndex:anIndex];
652 }
653 
654 - (void)removeObjectAtIndex:(CPUInteger)anIndex
655 {
656  var currentObject = [self objectAtIndex:anIndex];
657 
658  for (var i = 0, count = [_observationProxies count]; i < count; i++)
659  {
660  var proxy = [_observationProxies objectAtIndex:i],
661  keyPath = [proxy keyPath],
662  operator = keyPath.charAt(0) === ".";
663 
664  if (operator)
665  [self willChangeValueForKey:keyPath];
666 
667  [currentObject removeObserver:proxy forKeyPath:keyPath];
668 
669  if (operator)
670  [self didChangeValueForKey:keyPath];
671  }
672 
673  [super removeObjectAtIndex:anIndex];
674 }
675 
676 - (CPArray)objectsAtIndexes:(CPIndexSet)theIndexes
677 {
678  return [_CPObservableArray arrayWithArray:[super objectsAtIndexes:theIndexes]];
679 }
680 
681 - (void)addObject:(id)anObject
682 {
683  [self insertObject:anObject atIndex:[self count]];
684 }
685 
686 - (void)removeLastObject
687 {
688  [self removeObjectAtIndex:[self count]];
689 }
690 
691 - (void)replaceObjectAtIndex:(CPUInteger)anIndex withObject:(id)anObject
692 {
693  var currentObject = [self objectAtIndex:anIndex];
694 
695  for (var i = 0, count = [_observationProxies count]; i < count; i++)
696  {
697  var proxy = [_observationProxies objectAtIndex:i],
698  keyPath = [proxy keyPath],
699  operator = keyPath.charAt(0) === ".";
700 
701  if (operator)
702  [self willChangeValueForKey:keyPath];
703 
704  [currentObject removeObserver:proxy forKeyPath:keyPath];
705  [anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
706 
707  if (operator)
708  [self didChangeValueForKey:keyPath];
709  }
710 
711  [super replaceObjectAtIndex:anIndex withObject:anObject];
712 }
713 
714 @end
715 
716 @implementation CPControllerSelectionProxy : CPObject
717 {
718  id _controller;
719  id _keys;
720 
721  CPDictionary _cachedValues;
722  CPArray _observationProxies;
723 
724  Object _observedObjectsByKeyPath;
725 }
726 
727 - (id)initWithController:(id)aController
728 {
729  if (self = [super init])
730  {
731  _cachedValues = @{};
732  _observationProxies = [CPArray array];
733  _controller = aController;
734  _observedObjectsByKeyPath = {};
735  }
736 
737  return self;
738 }
739 
740 - (id)_controllerMarkerForValues:(CPArray)theValues
741 {
742  var count = [theValues count],
743  value;
744 
745  if (!count)
746  value = CPNoSelectionMarker;
747  else if (count === 1)
748  value = [theValues objectAtIndex:0];
749  else
750  {
751  if ([_controller alwaysUsesMultipleValuesMarker])
752  value = CPMultipleValuesMarker;
753  else
754  {
755  value = [theValues objectAtIndex:0];
756 
757  for (var i = 0, count = [theValues count]; i < count && value != CPMultipleValuesMarker; i++)
758  {
759  if (![value isEqual:[theValues objectAtIndex:i]])
760  value = CPMultipleValuesMarker;
761  }
762  }
763  }
764 
765  if (value === nil || value.isa && [value isEqual:[CPNull null]])
766  value = CPNullMarker;
767 
768  return value;
769 }
770 
771 - (id)valueForKeyPath:(CPString)theKeyPath
772 {
773  var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath];
774 
775  // Simple collection operators like @count return a scalar value, not an array or set
776  if ([values isKindOfClass:CPArray] || [values isKindOfClass:CPSet])
777  {
778  var value = [self _controllerMarkerForValues:values];
779  [_cachedValues setObject:value forKey:theKeyPath];
780 
781  return value;
782  }
783  else
784  return values;
785 }
786 
787 - (id)valueForKey:(CPString)theKeyPath
788 {
789  return [self valueForKeyPath:theKeyPath];
790 }
791 
792 - (void)setValue:(id)theValue forKeyPath:(CPString)theKeyPath
793 {
794  [[_controller selectedObjects] setValue:theValue forKeyPath:theKeyPath];
795  [_cachedValues removeObjectForKey:theKeyPath];
796 
797  // Allow handlesContentAsCompoundValue to work, based on observation of Cocoa's
798  // NSArrayController - when handlesContentAsCompoundValue and setValue:forKey:@"selection.X"
799  // is called, the array controller causes the compound value to be rewritten if
800  // handlesContentAsCompoundValue == YES. Note that
801  // A) this doesn't use observation (observe: X is not visible in backtraces)
802  // B) it only happens through the selection proxy and not on arrangedObject.X, content.X
803  // or even selectedObjects.X.
804  // FIXME The main code for this should somehow be in CPArrayController and also work
805  // for table based row edits.
806  [[CPBinder getBinding:@"contentArray" forObject:_controller] _contentArrayDidChange];
807 }
808 
809 - (void)setValue:(id)theValue forKey:(CPString)theKeyPath
810 {
811  [self setValue:theValue forKeyPath:theKeyPath];
812 }
813 
814 - (unsigned)count
815 {
816  return [_cachedValues count];
817 }
818 
819 - (id)keyEnumerator
820 {
821  return [_cachedValues keyEnumerator];
822 }
823 
824 - (void)controllerWillChange
825 {
826  _keys = [_cachedValues allKeys];
827 
828  if (!_keys)
829  return;
830 
831  for (var i = 0, count = _keys.length; i < count; i++)
832  [self willChangeValueForKey:_keys[i]];
833 
834  [_cachedValues removeAllObjects];
835 }
836 
837 - (void)controllerDidChange
838 {
839  [_cachedValues removeAllObjects];
840 
841  if (!_keys)
842  return;
843 
844  for (var i = 0, count = _keys.length; i < count; i++)
845  [self didChangeValueForKey:_keys[i]];
846 
847  _keys = nil;
848 }
849 
850 - (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
851 {
852  [_cachedValues removeObjectForKey:aKeyPath];
853 }
854 
855 - (void)addObserver:(id)anObject forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
856 {
857  var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self];
858 
859  [proxy setNotifyObject:YES];
860  [_observationProxies addObject:proxy];
861 
862  // We keep a reference to the observed objects because removeObserver: will be called after the selection changes.
863  var observedObjects = [_controller selectedObjects];
864  _observedObjectsByKeyPath[aKeyPath] = observedObjects;
865  [observedObjects addObserver:proxy forKeyPath:aKeyPath options:options context:context];
866 }
867 
868 - (void)removeObserver:(id)anObject forKeyPath:(CPString)aKeyPath
869 {
870  [_observationProxies enumerateObjectsUsingBlock:function(aProxy, idx, stop)
871  {
872  if (aProxy._object === self && aProxy._keyPath == aKeyPath && aProxy._observer === anObject)
873  {
874  var observedObjects = _observedObjectsByKeyPath[aKeyPath];
875 
876  [observedObjects removeObserver:aProxy forKeyPath:aKeyPath];
877  [_observationProxies removeObjectAtIndex:idx];
878 
879  _observedObjectsByKeyPath[aKeyPath] = nil;
880 
881  stop(YES);
882  }
883  }];
884 }
885 
886 @end
887 
888 
889 @implementation _CPManagedProxy : CPObject
890 {
891  CPString _entityName;
892  CPPredicate _fetchPredicate;
893 }
894 
895 @end
896 
897 var CPManagedProxyEntityNameKey = @"CPManagedProxyEntityNameKey",
898  CPManagedProxyFetchPredicateKey = @"CPManagedProxyFetchPredicateKey";
899 
900 @implementation _CPManagedProxy (CPCoding)
901 
902 - (id)initWithCoder:(CPCoder)aCoder
903 {
904  self = [super init];
905 
906  if (self)
907  {
908  [self setEntityName:[aCoder decodeObjectForKey:CPManagedProxyEntityNameKey]];
909  [self setFetchPredicate:[aCoder decodeObjectForKey:CPManagedProxyFetchPredicateKey]];
910  }
911 
912  return self;
913 }
914 
915 - (void)encodeWithCoder:(CPCoder)aCoder
916 {
917  [aCoder encodeObject:[self entityName] forKey:CPManagedProxyEntityNameKey];
918  [aCoder encodeObject:[self fetchPredicate] forKey:CPManagedProxyFetchPredicateKey];
919 }
920 
921 @end
922 
924 
929 {
930  return _usesLazyFetching;
931 }
932 
936 - (void)setUsesLazyFetching:(BOOL)aValue
937 {
938  _usesLazyFetching = aValue;
939 }
940 
941 @end
void setValue:forKeyPath:(id theValue, [forKeyPath] CPString theKeyPath)
void setAutomaticallyPreparesContent:(BOOL shouldAutomaticallyPrepareContent)
CPSet keyPathsForValuesAffectingCanInsert()
void removeObject:(id anObject)
void willChangeValueForKey:(CPString aKey)
CPSet keyPathsForValuesAffectingCanRemove()
var isEqual
An object representation of nil.
Definition: CPNull.h:2
var CPObjectControllerAutomaticallyPreparesContentKey
void addObject:(id anObject)
var CPManagedProxyEntityNameKey
id valueForKeyPath:(CPString theKeyPath)
A collection of unique integers.
Definition: CPIndexSet.h:2
void setEditable:(BOOL shouldBeEditable)
CPString description()
Definition: CPObject.j:358
void setUsesLazyFetching:(BOOL aValue)
A mutable key-value pair collection.
Definition: CPDictionary.h:2
var CPManagedProxyFetchPredicateKey
var CPObjectControllerManagedProxyKey
void setContent:(id aContent)
CPMultipleValuesMarker
void encodeObject:forKey:(id anObject, [forKey] CPString aKey)
An immutable string (collection of characters).
Definition: CPString.h:2
var CPObjectControllerObjectClassNameKey
CPSet keyPathsForValuesAffectingContentObject()
CPBinder getBinding:forObject:(CPString aBinding, [forObject] id anObject)
var CPObjectControllerUsesLazyFetchingKey
CPSet keyPathsForValuesAffectingCanAdd()
void addObserver:forKeyPath:options:context:(id anObserver, [forKeyPath] CPString aPath, [options] CPKeyValueObservingOptions options, [context] id aContext)
void exposeBinding:(CPString aBinding)
void didChangeValueForKey:(CPString aKey)
An mutable collection which may contain a specific object numerous times.
Definition: CPCountedSet.h:2
Defines methods for use when archiving & restoring (enc/decoding).
Definition: CPCoder.h:2
void removeObserver:forKeyPath:(id anObserver, [forKeyPath] CPString aPath)
var CPObjectControllerIsEditableKey
var CPObjectControllerContentKey
CPNoSelectionMarker
id indexSetWithIndexesInRange:(CPRange aRange)
Definition: CPIndexSet.j:60
id initWithContent:(id aContent)
Class class()
Definition: CPObject.j:179
CPPredicate fetchPredicate()
void setObjectClass:(Class aClass)
var CPObjectControllerIsUsingManagedProxyKey
function CPClassFromString(aClassName)
Definition: CPObjJRuntime.j:33
CPNullMarker
id alloc()
Definition: CPObject.j:130
id stringWithFormat:(CPString format, [,] ...)
Definition: CPString.j:166