44 BOOL _automaticallyPreparesContent;
58 + (
CPSet)keyPathsForValuesAffectingContentObject
63 + (BOOL)automaticallyNotifiesObserversForKey:(
CPString)aKey
65 if (aKey ===
@"contentObject")
71 + (
CPSet)keyPathsForValuesAffectingCanAdd
76 + (
CPSet)keyPathsForValuesAffectingCanInsert
81 + (
CPSet)keyPathsForValuesAffectingCanRemove
100 - (id)initWithContent:(
id)aContent
102 if (
self = [super init])
120 return _contentObject;
127 - (void)setContent:(
id)aContent
130 [
self _selectionWillChange];
132 _contentObject = aContent;
134 [
self _selectionDidChange];
141 - (void)_setContentObject:(
id)aContent
143 [
self setContent:aContent];
151 return [
self content];
161 - (void)setAutomaticallyPreparesContent:(BOOL)shouldAutomaticallyPrepareContent
163 _automaticallyPreparesContent = shouldAutomaticallyPrepareContent;
170 - (BOOL)automaticallyPreparesContent
172 return _automaticallyPreparesContent;
178 - (void)prepareContent
187 - (void)setObjectClass:(Class)aClass
189 _objectClass = aClass;
205 - (id)_defaultNewObject
207 return [[[
self objectClass] alloc] init];
216 return [
self _defaultNewObject];
223 - (void)addObject:(
id)anObject
227 var binderClass = [[
self class] _binderClassForBinding:@"contentObject"];
228 [[binderClass getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
235 - (void)removeObject:(
id)anObject
237 if ([
self content] === anObject)
240 var binderClass = [[
self class] _binderClassForBinding:@"contentObject"];
241 [[binderClass getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
248 - (void)add:(
id)aSender
266 - (void)remove:(
id)aSender
284 - (void)setEditable:(BOOL)shouldBeEditable
286 _isEditable = shouldBeEditable;
302 return [[_CPObservableArray alloc] initWithArray:[_contentObject]];
316 - (void)_selectionWillChange
318 [_selection controllerWillChange];
319 [
self willChangeValueForKey:@"selection"];
325 - (void)_selectionDidChange
327 if (_selection === undefined || _selection === nil)
330 [_selection controllerDidChange];
331 [
self didChangeValueForKey:@"selection"];
339 return _observedKeys;
342 - (void)addObserver:(
id)anObserver forKeyPath:(
CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(
id)context
344 [_observedKeys addObject:aKeyPath];
348 - (void)removeObserver:(
id)anObserver forKeyPath:(
CPString)aKeyPath
350 [_observedKeys removeObject:aKeyPath];
369 var objectClassName = [aCoder decodeObjectForKey:CPObjectControllerObjectClassNameKey],
373 [
self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]];
375 [
self setContent:[aCoder decodeObjectForKey:CPObjectControllerContentKey]];
385 [aCoder encodeObject:[
self content]
forKey:CPObjectControllerContentKey];
388 [aCoder encodeObject:CPStringFromClass(_objectClass) forKey:CPObjectControllerObjectClassNameKey];
389 else if (_objectClassName)
390 [aCoder encodeObject:_objectClassName forKey:CPObjectControllerObjectClassNameKey];
392 [aCoder encodeBool:[
self isEditable] forKey:CPObjectControllerIsEditableKey];
398 if (![
self content] && [
self automaticallyPreparesContent])
404 @implementation _CPObservationProxy :
CPObject
416 - (id)initWithKeyPath:(
id)aKeyPath observer:(
id)anObserver object:(
id)anObject
418 if (
self = [super init])
421 _observer = anObserver;
448 - (void)setNotifyObject:(BOOL)notify
450 _notifyObject = notify;
455 if ([anObject
class] === [
self class])
457 if (anObject._observer === _observer && [anObject._keyPath
isEqual:_keyPath] && [anObject._object
isEqual:_object])
464 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObject change:(
CPDictionary)change context:(
id)context
467 [_object observeValueForKeyPath:aKeyPath ofObject:_object change:change context:context];
469 [_observer observeValueForKeyPath:aKeyPath ofObject:_object change:change context:context];
474 return [
super description] + [
CPString stringWithFormat:
@"observation proxy for %@ on key path %@", _observer, _keyPath];
480 @implementation _CPObservableArray : _CPJavaScriptArray
490 var ivars = class_copyIvarList(
self),
491 count = ivars.length;
494 a[ivar_getName(ivars[count])] = nil;
501 return "<_CPObservableArray: " + [super description] + " >";
504 - (id)initWithArray:(
CPArray)anArray
506 self = [
super initWithArray:anArray];
508 self.
isa = [_CPObservableArray class];
509 self._observationProxies = [];
514 - (void)addObserver:(
id)anObserver forKeyPath:(
CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(
id)context
516 if (aKeyPath.indexOf(
"@") === 0)
518 var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self];
520 proxy._options = options;
521 proxy._context = context;
523 [_observationProxies addObject:proxy];
525 var dotIndex = aKeyPath.indexOf(
"."),
526 remaining = aKeyPath.substring(dotIndex + 1),
529 [
self addObserver:proxy toObjectsAtIndexes:indexes forKeyPath:remaining options:options context:context];
534 [
self addObserver:anObserver toObjectsAtIndexes:indexes forKeyPath:aKeyPath options:options context:context];
538 - (void)removeObserver:(
id)anObserver forKeyPath:(
CPString)aKeyPath
540 if (aKeyPath.indexOf(
"@") === 0)
542 var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self],
543 index = [_observationProxies indexOfObject:proxy];
545 proxy = [_observationProxies objectAtIndex:index];
547 var dotIndex = aKeyPath.indexOf(
"."),
548 remaining = aKeyPath.substring(dotIndex + 1),
551 [
self removeObserver:proxy fromObjectsAtIndexes:indexes forKeyPath:remaining];
556 [
self removeObserver:anObserver fromObjectsAtIndexes:indexes forKeyPath:aKeyPath];
560 - (void)insertObject:(
id)anObject atIndex:(
unsigned)anIndex
562 for (var i = 0, count = [_observationProxies count]; i < count; i++)
564 var proxy = [_observationProxies objectAtIndex:i],
565 keyPath = [proxy keyPath],
566 operator = keyPath.indexOf(
".") === 0;
569 [
self willChangeValueForKey:keyPath];
571 [anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
574 [
self didChangeValueForKey:keyPath];
577 [
super insertObject:anObject atIndex:anIndex];
580 - (void)removeObjectAtIndex:(
unsigned)anIndex
582 var currentObject = [
self objectAtIndex:anIndex];
584 for (var i = 0, count = [_observationProxies count]; i < count; i++)
586 var proxy = [_observationProxies objectAtIndex:i],
587 keyPath = [proxy keyPath],
588 operator = keyPath.indexOf(
".") === 0;
591 [
self willChangeValueForKey:keyPath];
593 [currentObject removeObserver:proxy forKeyPath:keyPath];
596 [
self didChangeValueForKey:keyPath];
599 [
super removeObjectAtIndex:anIndex];
602 - (_CPObservableArray)objectsAtIndexes:(
CPIndexSet)theIndexes
604 return [_CPObservableArray arrayWithArray:[
super objectsAtIndexes:theIndexes]];
607 - (void)addObject:(
id)anObject
609 [
self insertObject:anObject atIndex:[
self count]];
612 - (void)removeLastObject
614 [
self removeObjectAtIndex:[
self count]];
617 - (void)replaceObjectAtIndex:(
unsigned)anIndex withObject:(
id)anObject
619 var currentObject = [
self objectAtIndex:anIndex];
621 for (var i = 0, count = [_observationProxies count]; i < count; i++)
623 var proxy = [_observationProxies objectAtIndex:i],
624 keyPath = [proxy keyPath],
625 operator = keyPath.indexOf(
".") === 0;
628 [
self willChangeValueForKey:keyPath];
630 [currentObject removeObserver:proxy forKeyPath:keyPath];
631 [anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
634 [
self didChangeValueForKey:keyPath];
637 [
super replaceObjectAtIndex:anIndex withObject:anObject];
650 Object _observedObjectsByKeyPath;
653 - (id)initWithController:(
id)aController
655 if (
self = [super init])
659 _controller = aController;
660 _observedObjectsByKeyPath = {};
666 - (id)_controllerMarkerForValues:(
CPArray)theValues
668 var count = [theValues
count],
673 else if (count === 1)
677 if ([_controller alwaysUsesMultipleValuesMarker])
685 if (![value
isEqual:[theValues objectAtIndex:i]])
691 if (value === nil || value.isa && [value
isEqual:[
CPNull null]])
699 var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath],
700 value = [
self _controllerMarkerForValues:values];
702 [_cachedValues setObject:value forKey:theKeyPath];
712 - (void)setValue:(
id)theValue forKeyPath:(
CPString)theKeyPath
714 [[_controller selectedObjects] setValue:theValue forKeyPath:theKeyPath];
715 [_cachedValues removeObjectForKey:theKeyPath];
729 - (void)setValue:(
id)theValue forKey:(
CPString)theKeyPath
736 return [_cachedValues count];
741 return [_cachedValues keyEnumerator];
744 - (void)controllerWillChange
746 _keys = [_cachedValues allKeys];
751 for (var i = 0, count = _keys.length; i < count; i++)
752 [
self willChangeValueForKey:_keys[i]];
754 [_cachedValues removeAllObjects];
757 - (void)controllerDidChange
759 [_cachedValues removeAllObjects];
764 for (var i = 0, count = _keys.length; i < count; i++)
765 [
self didChangeValueForKey:_keys[i]];
770 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObject change:(
CPDictionary)change context:(
id)context
772 [_cachedValues removeObjectForKey:aKeyPath];
775 - (void)addObserver:(
id)anObject forKeyPath:(
CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(
id)context
777 var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self];
779 [proxy setNotifyObject:YES];
780 [_observationProxies addObject:proxy];
783 var observedObjects = [_controller selectedObjects];
784 _observedObjectsByKeyPath[aKeyPath] = observedObjects;
785 [observedObjects addObserver:proxy forKeyPath:aKeyPath options:options context:context];
788 - (void)removeObserver:(
id)anObject forKeyPath:(
CPString)aKeyPath
790 var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self],
791 index = [_observationProxies indexOfObject:proxy];
793 var observedObjects = _observedObjectsByKeyPath[aKeyPath];
794 [observedObjects removeObserver:[_observationProxies objectAtIndex:index] forKeyPath:aKeyPath];
796 [_observationProxies removeObjectAtIndex:index];
798 _observedObjects = nil;