44 BOOL _automaticallyPreparesContent;
54 [
self exposeBinding:@"editable"];
55 [
self exposeBinding:@"contentObject"];
58 + (CPSet)keyPathsForValuesAffectingContentObject
60 return [CPSet setWithObjects:"content"];
63 + (BOOL)automaticallyNotifiesObserversForKey:(
CPString)aKey
65 if (aKey ===
@"contentObject")
71 + (CPSet)keyPathsForValuesAffectingCanAdd
73 return [CPSet setWithObject:"editable"];
76 + (CPSet)keyPathsForValuesAffectingCanInsert
78 return [CPSet setWithObject:"editable"];
81 + (CPSet)keyPathsForValuesAffectingCanRemove
83 return [CPSet setWithObjects:"editable", "selection"];
100 - (id)initWithContent:(
id)aContent
102 if (
self = [super init])
122 return _contentObject;
129 - (void)setContent:(
id)aContent
131 [
self willChangeValueForKey:@"contentObject"];
132 [
self _selectionWillChange];
134 _contentObject = aContent;
136 [
self _selectionDidChange];
137 [
self didChangeValueForKey:@"contentObject"];
143 - (void)_setContentObject:(
id)aContent
145 [
self setContent:aContent];
153 return [
self content];
163 - (void)setAutomaticallyPreparesContent:(BOOL)shouldAutomaticallyPrepareContent
165 _automaticallyPreparesContent = shouldAutomaticallyPrepareContent;
172 - (BOOL)automaticallyPreparesContent
174 return _automaticallyPreparesContent;
180 - (void)prepareContent
189 - (void)setObjectClass:(Class)aClass
191 _objectClass = aClass;
207 - (id)_defaultNewObject
209 return [[[
self objectClass] alloc] init];
218 return [
self _defaultNewObject];
225 - (void)addObject:(
id)anObject
229 var binderClass = [[
self class] _binderClassForBinding:@"contentObject"];
230 [[binderClass getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
237 - (void)removeObject:(
id)anObject
239 if ([
self content] === anObject)
242 var binderClass = [[
self class] _binderClassForBinding:@"contentObject"];
243 [[binderClass getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
250 - (void)add:(
id)aSender
268 - (void)remove:(
id)aSender
286 - (void)setEditable:(BOOL)shouldBeEditable
288 _isEditable = shouldBeEditable;
302 - (CPArray)selectedObjects
304 return [[_CPObservableArray alloc] initWithArray:[_contentObject]];
318 - (void)_selectionWillChange
320 [_selection controllerWillChange];
321 [
self willChangeValueForKey:@"selection"];
327 - (void)_selectionDidChange
329 if (_selection === undefined || _selection === nil)
332 [_selection controllerDidChange];
333 [
self didChangeValueForKey:@"selection"];
341 return _observedKeys;
344 - (void)addObserver:(
id)anObserver forKeyPath:(
CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(
id)context
346 [_observedKeys addObject:aKeyPath];
347 [
super addObserver:anObserver forKeyPath:aKeyPath options:options context:context];
350 - (void)removeObserver:(
id)anObserver forKeyPath:(
CPString)aKeyPath
352 [_observedKeys removeObject:aKeyPath];
353 [
super removeObserver:anObserver forKeyPath:aKeyPath];
371 var objectClassName = [aCoder decodeObjectForKey:CPObjectControllerObjectClassNameKey],
375 [
self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]];
377 [
self setContent:[aCoder decodeObjectForKey:CPObjectControllerContentKey]];
387 [aCoder encodeObject:[
self content]
forKey:CPObjectControllerContentKey];
390 [aCoder encodeObject:CPStringFromClass(_objectClass) forKey:CPObjectControllerObjectClassNameKey];
391 else if (_objectClassName)
392 [aCoder encodeObject:_objectClassName forKey:CPObjectControllerObjectClassNameKey];
394 [aCoder encodeBool:[
self isEditable] forKey:CPObjectControllerIsEditableKey];
400 if (![
self content] && [
self automaticallyPreparesContent])
406 @implementation _CPObservationProxy :
CPObject
418 - (id)initWithKeyPath:(
id)aKeyPath observer:(
id)anObserver object:(
id)anObject
420 if (
self = [super init])
423 _observer = anObserver;
450 - (void)setNotifyObject:(BOOL)notify
452 _notifyObject = notify;
457 if ([anObject
class] === [
self class])
459 if (anObject._observer === _observer && [anObject._keyPath
isEqual:_keyPath] && [anObject._object
isEqual:_object])
466 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObject change:(
CPDictionary)change context:(
id)context
469 [_object observeValueForKeyPath:aKeyPath ofObject:_object change:change context:context];
471 [_observer observeValueForKeyPath:aKeyPath ofObject:_object change:change context:context];
476 return [
super description] + [
CPString stringWithFormat:
@"observation proxy for %@ on key path %@", _observer, _keyPath];
482 @implementation _CPObservableArray : _CPJavaScriptArray
484 CPArray _observationProxies;
492 var ivars = class_copyIvarList(
self),
493 count = ivars.length;
496 a[ivar_getName(ivars[count])] = nil;
503 return "<_CPObservableArray: " + [super description] + " >";
506 - (id)initWithArray:(CPArray)anArray
508 self = [
super initWithArray:anArray];
510 self.isa = [_CPObservableArray class];
511 self._observationProxies = [];
516 - (void)addObserver:(
id)anObserver forKeyPath:(
CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(
id)context
518 if (aKeyPath.charAt(0) ===
"@")
521 if ([_CPCollectionKVCOperator isSimpleCollectionOperator:aKeyPath])
524 var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self];
526 proxy._options = options;
527 proxy._context = context;
529 [_observationProxies addObject:proxy];
531 var dotIndex = aKeyPath.indexOf(
"."),
532 remaining = aKeyPath.substring(dotIndex + 1),
535 [
self addObserver:proxy toObjectsAtIndexes:indexes forKeyPath:remaining options:options context:context];
540 [
self addObserver:anObserver toObjectsAtIndexes:indexes forKeyPath:aKeyPath options:options context:context];
544 - (void)removeObserver:(
id)anObserver forKeyPath:(
CPString)aKeyPath
546 if (aKeyPath.charAt(0) ===
"@")
549 if ([_CPCollectionKVCOperator isSimpleCollectionOperator:aKeyPath])
552 var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self],
553 index = [_observationProxies indexOfObject:proxy];
555 proxy = [_observationProxies objectAtIndex:index];
557 var dotIndex = aKeyPath.indexOf(
"."),
558 remaining = aKeyPath.substring(dotIndex + 1),
561 [
self removeObserver:proxy fromObjectsAtIndexes:indexes forKeyPath:remaining];
566 [
self removeObserver:anObserver fromObjectsAtIndexes:indexes forKeyPath:aKeyPath];
570 - (void)insertObject:(
id)anObject atIndex:(CPUInteger)anIndex
572 for (var i = 0, count = [_observationProxies count]; i < count; i++)
574 var proxy = [_observationProxies objectAtIndex:i],
575 keyPath = [proxy keyPath],
576 operator = keyPath.charAt(0) ===
".";
579 [
self willChangeValueForKey:keyPath];
581 [anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
584 [
self didChangeValueForKey:keyPath];
587 [
super insertObject:anObject atIndex:anIndex];
590 - (void)removeObjectAtIndex:(CPUInteger)anIndex
592 var currentObject = [
self objectAtIndex:anIndex];
594 for (var i = 0, count = [_observationProxies count]; i < count; i++)
596 var proxy = [_observationProxies objectAtIndex:i],
597 keyPath = [proxy keyPath],
598 operator = keyPath.charAt(0) ===
".";
601 [
self willChangeValueForKey:keyPath];
603 [currentObject removeObserver:proxy forKeyPath:keyPath];
606 [
self didChangeValueForKey:keyPath];
609 [
super removeObjectAtIndex:anIndex];
612 - (CPArray)objectsAtIndexes:(
CPIndexSet)theIndexes
614 return [_CPObservableArray arrayWithArray:[
super objectsAtIndexes:theIndexes]];
617 - (void)addObject:(
id)anObject
619 [
self insertObject:anObject atIndex:[
self count]];
622 - (void)removeLastObject
624 [
self removeObjectAtIndex:[
self count]];
627 - (void)replaceObjectAtIndex:(CPUInteger)anIndex withObject:(
id)anObject
629 var currentObject = [
self objectAtIndex:anIndex];
631 for (var i = 0, count = [_observationProxies count]; i < count; i++)
633 var proxy = [_observationProxies objectAtIndex:i],
634 keyPath = [proxy keyPath],
635 operator = keyPath.charAt(0) ===
".";
638 [
self willChangeValueForKey:keyPath];
640 [currentObject removeObserver:proxy forKeyPath:keyPath];
641 [anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
644 [
self didChangeValueForKey:keyPath];
647 [
super replaceObjectAtIndex:anIndex withObject:anObject];
658 CPArray _observationProxies;
660 Object _observedObjectsByKeyPath;
663 - (id)initWithController:(
id)aController
665 if (
self = [super init])
668 _observationProxies = [CPArray array];
669 _controller = aController;
670 _observedObjectsByKeyPath = {};
676 - (id)_controllerMarkerForValues:(CPArray)theValues
678 var count = [theValues count],
682 value = CPNoSelectionMarker;
683 else if (count === 1)
684 value = [theValues objectAtIndex:0];
687 if ([_controller alwaysUsesMultipleValuesMarker])
688 value = CPMultipleValuesMarker;
691 value = [theValues objectAtIndex:0];
693 for (var i = 0, count = [theValues count]; i < count && value != CPMultipleValuesMarker; i++)
695 if (![value
isEqual:[theValues objectAtIndex:i]])
696 value = CPMultipleValuesMarker;
701 if (value === nil || value.isa && [value
isEqual:[
CPNull null]])
702 value = CPNullMarker;
709 var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath];
712 if ([values isKindOfClass:CPArray] || [values isKindOfClass:CPSet])
714 var value = [
self _controllerMarkerForValues:values];
715 [_cachedValues setObject:value forKey:theKeyPath];
728 - (void)setValue:(
id)theValue forKeyPath:(
CPString)theKeyPath
730 [[_controller selectedObjects] setValue:theValue forKeyPath:theKeyPath];
731 [_cachedValues removeObjectForKey:theKeyPath];
742 [[
CPBinder getBinding:@"contentArray" forObject:_controller] _contentArrayDidChange];
745 - (void)setValue:(
id)theValue forKey:(
CPString)theKeyPath
752 return [_cachedValues count];
757 return [_cachedValues keyEnumerator];
760 - (void)controllerWillChange
762 _keys = [_cachedValues allKeys];
767 for (var i = 0, count = _keys.length; i < count; i++)
768 [
self willChangeValueForKey:_keys[i]];
770 [_cachedValues removeAllObjects];
773 - (void)controllerDidChange
775 [_cachedValues removeAllObjects];
780 for (var i = 0, count = _keys.length; i < count; i++)
781 [
self didChangeValueForKey:_keys[i]];
786 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObject change:(
CPDictionary)change context:(
id)context
788 [_cachedValues removeObjectForKey:aKeyPath];
791 - (void)addObserver:(
id)anObject forKeyPath:(
CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(
id)context
793 var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self];
795 [proxy setNotifyObject:YES];
796 [_observationProxies addObject:proxy];
799 var observedObjects = [_controller selectedObjects];
800 _observedObjectsByKeyPath[aKeyPath] = observedObjects;
801 [observedObjects addObserver:proxy forKeyPath:aKeyPath options:options context:context];
804 - (void)removeObserver:(
id)anObject forKeyPath:(
CPString)aKeyPath
806 var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self],
807 index = [_observationProxies indexOfObject:proxy];
809 var observedObjects = _observedObjectsByKeyPath[aKeyPath];
810 [observedObjects removeObserver:[_observationProxies objectAtIndex:index] forKeyPath:aKeyPath];
812 [_observationProxies removeObjectAtIndex:index];
814 _observedObjectsByKeyPath[aKeyPath] = nil;