37 BOOL _avoidsEmptySelection;
38 BOOL _clearsFilterPredicateOnInsertion;
39 BOOL _filterRestrictsInsertion;
40 BOOL _preservesSelection;
41 BOOL _selectsInsertedObjects;
42 BOOL _alwaysUsesMultipleValuesMarker;
44 BOOL _automaticallyRearrangesObjects;
47 CPArray _sortDescriptors;
48 CPPredicate _filterPredicate;
49 CPArray _arrangedObjects;
51 BOOL _disableSetContent;
59 [
self exposeBinding:@"contentArray"];
60 [
self exposeBinding:@"contentSet"];
63 + (CPSet)keyPathsForValuesAffectingContentArray
65 return [CPSet setWithObjects:@"content"];
68 + (CPSet)keyPathsForValuesAffectingArrangedObjects
71 return [CPSet setWithObjects:@"content", @"sortDescriptors"];
74 + (CPSet)keyPathsForValuesAffectingSelection
76 return [CPSet setWithObjects:@"selectionIndexes"];
79 + (CPSet)keyPathsForValuesAffectingSelectionIndex
81 return [CPSet setWithObjects:@"selectionIndexes"];
84 + (CPSet)keyPathsForValuesAffectingSelectionIndexes
88 return [CPSet setWithObjects:@"arrangedObjects"];
91 + (CPSet)keyPathsForValuesAffectingSelectedObjects
94 return [CPSet setWithObjects:@"selectionIndexes"];
97 + (CPSet)keyPathsForValuesAffectingCanRemove
99 return [CPSet setWithObjects:@"selectionIndexes"];
102 + (CPSet)keyPathsForValuesAffectingCanSelectNext
104 return [CPSet setWithObjects:@"selectionIndexes"];
107 + (CPSet)keyPathsForValuesAffectingCanSelectPrevious
109 return [CPSet setWithObjects:@"selectionIndexes"];
119 _preservesSelection = YES;
120 _selectsInsertedObjects = YES;
121 _avoidsEmptySelection = YES;
122 _clearsFilterPredicateOnInsertion = YES;
123 _alwaysUsesMultipleValuesMarker = NO;
124 _automaticallyRearrangesObjects = NO;
126 _filterRestrictsInsertion = YES;
136 _sortDescriptors = [CPArray array];
137 _filterPredicate = nil;
139 [
self __setArrangedObjects:[CPArray array]];
142 - (void)prepareContent
144 [
self _setContentArray:[[
self newObject]]];
150 - (BOOL)preservesSelection
152 return _preservesSelection;
160 - (void)setPreservesSelection:(BOOL)value
162 _preservesSelection = value;
168 - (BOOL)selectsInsertedObjects
170 return _selectsInsertedObjects;
177 - (void)setSelectsInsertedObjects:(BOOL)value
179 _selectsInsertedObjects = value;
185 - (BOOL)avoidsEmptySelection
187 return _avoidsEmptySelection;
194 - (void)setAvoidsEmptySelection:(BOOL)value
196 _avoidsEmptySelection = value;
204 - (BOOL)clearsFilterPredicateOnInsertion
206 return _clearsFilterPredicateOnInsertion;
214 - (void)setClearsFilterPredicateOnInsertion:(BOOL)aFlag
216 _clearsFilterPredicateOnInsertion = aFlag;
225 - (BOOL)alwaysUsesMultipleValuesMarker
227 return _alwaysUsesMultipleValuesMarker;
236 - (void)setAlwaysUsesMultipleValuesMarker:(BOOL)aFlag
238 _alwaysUsesMultipleValuesMarker = aFlag;
250 - (BOOL)automaticallyRearrangesObjects
252 return _automaticallyRearrangesObjects;
264 - (void)setAutomaticallyRearrangesObjects:(BOOL)aFlag
266 _automaticallyRearrangesObjects = aFlag;
274 - (void)setContent:(
id)value
279 if (_disableSetContent)
285 if (![value isKindOfClass:[CPArray
class]])
288 var oldSelectedObjects = nil,
289 oldSelectionIndexes = nil;
291 if ([
self preservesSelection])
308 if (_clearsFilterPredicateOnInsertion)
309 [
self willChangeValueForKey:@"filterPredicate"];
315 _contentObject = value;
317 if (_clearsFilterPredicateOnInsertion && _filterPredicate != nil)
318 [
self __setFilterPredicate:nil];
320 [
self _rearrangeObjects];
322 if ([
self preservesSelection])
323 [
self __setSelectedObjects:oldSelectedObjects];
325 [
self __setSelectionIndexes:oldSelectionIndexes];
327 if (_clearsFilterPredicateOnInsertion)
328 [
self didChangeValueForKey:@"filterPredicate"];
334 - (void)_setContentArray:(
id)anArray
336 [
self setContent:anArray];
342 - (void)_setContentSet:(
id)aSet
344 [
self setContent:[aSet allObjects]];
363 return [CPSet setWithArray:[
self content]];
372 - (CPArray)arrangeObjects:(CPArray)objects
377 if (filterPredicate && [sortDescriptors count] > 0)
379 var sortedObjects = [objects filteredArrayUsingPredicate:filterPredicate];
380 [sortedObjects sortUsingDescriptors:sortDescriptors];
381 return sortedObjects;
383 else if (filterPredicate)
384 return [objects filteredArrayUsingPredicate:filterPredicate];
385 else if ([sortDescriptors count] > 0)
386 return [objects sortedArrayUsingDescriptors:sortDescriptors];
388 return [objects copy];
394 - (void)rearrangeObjects
396 [
self willChangeValueForKey:@"arrangedObjects"];
397 [
self _rearrangeObjects];
398 [
self didChangeValueForKey:@"arrangedObjects"];
405 - (void)_rearrangeObjects
411 var oldSelectedObjects = nil,
412 oldSelectionIndexes = nil;
414 if ([
self preservesSelection])
415 oldSelectedObjects = [
self selectedObjects];
417 oldSelectionIndexes = [
self selectionIndexes];
419 [
self __setArrangedObjects:[
self arrangeObjects:[
self contentArray]]];
421 if ([
self preservesSelection])
422 [
self __setSelectedObjects:oldSelectedObjects];
424 [
self __setSelectionIndexes:oldSelectionIndexes];
430 - (void)__setArrangedObjects:(
id)value
432 if (_arrangedObjects === value)
435 _arrangedObjects = [[_CPObservableArray alloc] initWithArray:value];
442 - (id)arrangedObjects
444 return _arrangedObjects;
451 - (CPArray)sortDescriptors
453 return _sortDescriptors;
461 - (void)setSortDescriptors:(CPArray)value
463 if (_sortDescriptors === value)
466 _sortDescriptors = [value copy];
469 [
self _rearrangeObjects];
478 - (CPPredicate)filterPredicate
480 return _filterPredicate;
489 - (void)setFilterPredicate:(CPPredicate)value
491 if (_filterPredicate === value)
496 [
self willChangeValueForKey:@"arrangedObjects"];
497 [
self __setFilterPredicate:value];
498 [
self didChangeValueForKey:@"arrangedObjects"];
505 - (void)__setFilterPredicate:(CPPredicate)value
507 if (_filterPredicate === value)
510 _filterPredicate = value;
512 [
self _rearrangeObjects];
519 - (BOOL)alwaysUsesMultipleValuesMarker
521 return _alwaysUsesMultipleValuesMarker;
529 - (unsigned)selectionIndex
531 return [_selectionIndexes firstIndex];
540 - (BOOL)setSelectionIndex:(
unsigned)index
552 return _selectionIndexes;
563 [
self _selectionWillChange]
564 var r = [
self __setSelectionIndexes:indexes avoidEmpty:NO];
565 [
self _selectionDidChange];
573 - (BOOL)__setSelectionIndex:(
int)theIndex
582 - (BOOL)__setSelectionIndexes:(
CPIndexSet)indexes
584 return [
self __setSelectionIndexes:indexes avoidEmpty:_avoidsEmptySelection];
587 - (BOOL)__setSelectionIndexes:(
CPIndexSet)indexes avoidEmpty:(BOOL)avoidEmpty
589 var newIndexes = indexes;
594 if (![newIndexes count])
596 if (avoidEmpty && [[
self arrangedObjects] count])
601 var objectsCount = [[
self arrangedObjects] count];
606 newIndexes = [newIndexes copy];
609 [newIndexes removeIndexesInRange:CPMakeRange(objectsCount, [newIndexes lastIndex] + 1)];
611 if (![newIndexes count] && avoidEmpty && objectsCount)
615 if ([_selectionIndexes isEqualToIndexSet:newIndexes])
620 _selectionIndexes = indexes === newIndexes ? [indexes
copy] : newIndexes;
624 var binderClass = [[
self class] _binderClassForBinding:@"selectionIndexes"];
625 [[binderClass getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
634 - (CPArray)selectedObjects
638 return [_CPObservableArray arrayWithArray:(objects || [])];
647 - (BOOL)setSelectedObjects:(CPArray)objects
649 [
self willChangeValueForKey:@"selectionIndexes"];
650 [
self _selectionWillChange];
652 var r = [
self __setSelectedObjects:objects avoidEmpty:NO];
654 [
self didChangeValueForKey:@"selectionIndexes"];
655 [
self _selectionDidChange];
663 - (BOOL)__setSelectedObjects:(CPArray)objects
665 [
self __setSelectedObjects:objects avoidEmpty:_avoidsEmptySelection];
668 - (BOOL)__setSelectedObjects:(CPArray)objects avoidEmpty:(BOOL)avoidEmpty
671 count = [objects count],
672 arrangedObjects = [
self arrangedObjects];
674 for (var i = 0; i < count; i++)
676 var index = [arrangedObjects indexOfObject:[objects objectAtIndex:i]];
679 [set addIndex:index];
682 [
self __setSelectionIndexes:set avoidEmpty:avoidEmpty];
692 - (BOOL)canSelectPrevious
701 - (void)selectPrevious:(
id)sender
706 [
self setSelectionIndexes:[
CPIndexSet indexSetWithIndex:index]];
714 - (BOOL)canSelectNext
723 - (void)selectNext:(
id)sender
727 if (index < [[
self arrangedObjects] count])
728 [
self setSelectionIndexes:[
CPIndexSet indexSetWithIndex:index]];
738 - (void)addObject:(
id)object
743 var willClearPredicate = NO;
745 if (_clearsFilterPredicateOnInsertion && _filterPredicate)
747 [
self willChangeValueForKey:@"filterPredicate"];
748 willClearPredicate = YES;
751 [
self willChangeValueForKey:@"content"];
760 _disableSetContent = YES;
761 [_contentObject addObject:object];
764 [[
CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
766 _disableSetContent = NO;
768 if (willClearPredicate)
771 _filterPredicate = nil;
772 [
self _rearrangeObjects];
774 else if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:
object])
777 var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors];
781 if (_selectsInsertedObjects)
782 [
self __setSelectionIndex:pos];
784 [_selectionIndexes shiftIndexesStartingAtIndex:pos by:1];
794 var proxy = [_CPKVOProxy proxyForObject:self];
795 [proxy setAdding:YES];
798 [
self didChangeValueForKey:@"content"];
800 if (willClearPredicate)
801 [
self didChangeValueForKey:
@"filterPredicate"];
804 [proxy setAdding:NO];
814 - (void)insertObject:(
id)anObject atArrangedObjectIndex:(
int)anIndex
819 var willClearPredicate = NO;
821 if (_clearsFilterPredicateOnInsertion && _filterPredicate)
823 [
self willChangeValueForKey:@"filterPredicate"];
824 willClearPredicate = YES;
827 [
self willChangeValueForKey:@"content"];
832 _disableSetContent = YES;
837 [_contentObject addObject:anObject];
839 [[
CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
841 _disableSetContent = NO;
843 if (willClearPredicate)
844 [
self __setFilterPredicate:nil];
850 if ([
self selectsInsertedObjects])
851 [
self __setSelectionIndex:anIndex];
855 if ([
self avoidsEmptySelection] && [[
self selectionIndexes] count] <= 0 && [_contentObject count] > 0)
856 [
self __setSelectionIndexes:[
CPIndexSet indexSetWithIndex:0]];
858 var proxy = [_CPKVOProxy proxyForObject:self];
859 [proxy setAdding:YES];
861 [
self didChangeValueForKey:@"content"];
863 if (willClearPredicate)
864 [
self didChangeValueForKey:
@"filterPredicate"];
866 [proxy setAdding:NO];
874 - (void)removeObject:(
id)object
876 [
self willChangeValueForKey:@"content"];
879 _disableSetContent = YES;
881 [_contentObject removeObject:object];
883 [[
CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
885 _disableSetContent = NO;
887 if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:
object])
891 var pos = [_arrangedObjects indexOfObject:object];
893 [_arrangedObjects removeObjectAtIndex:pos];
894 [_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1];
897 [
self __setSelectionIndexes:_selectionIndexes];
900 [
self didChangeValueForKey:@"content"];
908 - (void)add:(
id)sender
922 - (void)insert:(
id)sender
924 if (![
self canInsert])
928 lastSelectedIndex = [_selectionIndexes lastIndex];
931 [
self insertObject:newObject atArrangedObjectIndex:lastSelectedIndex];
940 - (void)remove:(
id)sender
949 - (void)removeObjectAtArrangedObjectIndex:(
int)index
958 - (void)removeObjectsAtArrangedObjectIndexes:(
CPIndexSet)anIndexSet
960 [
self willChangeValueForKey:@"content"];
965 _disableSetContent = YES;
969 newSelectionIndexes = [_selectionIndexes copy];
977 if ([_contentObject objectAtIndex:anIndex] === object)
978 [_contentObject removeObjectAtIndex:anIndex];
986 var contentIndex = [_contentObject indexOfObjectIdenticalTo:object];
987 [_contentObject removeObjectAtIndex:contentIndex];
991 if (!_avoidsEmptySelection || [newSelectionIndexes count] > 1)
993 [newSelectionIndexes removeIndex:anIndex];
994 [newSelectionIndexes shiftIndexesStartingAtIndex:anIndex by:-1];
996 else if ([newSelectionIndexes lastIndex] !== anIndex)
997 [newSelectionIndexes shiftIndexesStartingAtIndex:anIndex by:-1];
1001 [[
CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
1002 _disableSetContent = NO;
1005 [
self __setSelectionIndexes:newSelectionIndexes];
1007 [
self didChangeValueForKey:@"content"];
1015 - (void)addObjects:(CPArray)objects
1021 count = [objects count];
1023 for (var i = 0; i < count; i++)
1024 [contentArray addObject:[objects objectAtIndex:i]];
1028 [[
CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
1035 - (void)removeObjects:(CPArray)objects
1037 [
self _removeObjects:objects];
1043 - (void)_removeObjects:(CPArray)objects
1045 [
self willChangeValueForKey:@"content"];
1048 _disableSetContent = YES;
1050 [_contentObject removeObjectsInArray:objects];
1052 [[
CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
1054 _disableSetContent = NO;
1056 var arrangedObjects = [
self arrangedObjects],
1057 position = [arrangedObjects indexOfObject:[objects objectAtIndex:0]];
1059 [arrangedObjects removeObjectsInArray:objects];
1061 var objectsCount = [arrangedObjects count],
1064 if ([
self preservesSelection] || [
self avoidsEmptySelection])
1069 if (objectsCount <= 0)
1073 else if (position >= objectsCount)
1074 selectionIndexes = [
CPIndexSet indexSetWithIndex:objectsCount - 1];
1077 _selectionIndexes = selectionIndexes;
1079 [
self didChangeValueForKey:@"content"];
1095 + (Class)_binderClassForBinding:(
CPString)aBinding
1097 if (aBinding ==
@"contentArray")
1098 return [_CPArrayControllerContentBinder
class];
1100 return [
super _binderClassForBinding:aBinding];
1104 @implementation _CPArrayControllerContentBinder :
CPBinder
1109 - (void)setValueFor:(
CPString)aBinding
1111 var destination = [_info objectForKey:CPObservedObjectKey],
1112 keyPath = [_info objectForKey:CPObservedKeyPathKey],
1113 options = [_info objectForKey:CPOptionsKey],
1114 isCompound = [
self handlesContentAsCompoundValue],
1115 dotIndex = keyPath.lastIndexOf(
"."),
1116 firstPart = dotIndex !==
CPNotFound ? keyPath.substring(0, dotIndex) : nil,
1117 isSelectionProxy = firstPart && [[destination valueForKeyPath:firstPart] isKindOfClass:CPControllerSelectionProxy],
1120 if (!isCompound && !isSelectionProxy)
1122 newValue = [destination mutableArrayValueForKeyPath:keyPath];
1134 newValue = [destination valueForKeyPath:keyPath];
1137 var isPlaceholder = CPIsControllerMarker(newValue);
1141 if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
1144 reason:@"can't transform non applicable key on: " + _source + " value: " + newValue];
1147 newValue = [
self _placeholderForMarker:newValue];
1154 newValue = [
self transformValue:newValue withOptions:options];
1160 newValue = [newValue mutableCopy];
1163 [_source setValue:newValue forKey:aBinding];
1166 - (void)_contentArrayDidChange
1175 if ([
self handlesContentAsCompoundValue])
1177 var destination = [_info objectForKey:CPObservedObjectKey],
1178 keyPath = [_info objectForKey:CPObservedKeyPathKey];
1180 [
self suppressSpecificNotificationFromObject:destination keyPath:keyPath];
1181 [
self reverseSetValueFor:@"contentArray"];
1182 [
self unsuppressSpecificNotificationFromObject:destination keyPath:keyPath];
1204 _avoidsEmptySelection = [aCoder decodeBoolForKey:CPArrayControllerAvoidsEmptySelection];
1205 _clearsFilterPredicateOnInsertion = [aCoder decodeBoolForKey:CPArrayControllerClearsFilterPredicateOnInsertion];
1206 _filterRestrictsInsertion = [aCoder decodeBoolForKey:CPArrayControllerFilterRestrictsInsertion];
1207 _preservesSelection = [aCoder decodeBoolForKey:CPArrayControllerPreservesSelection];
1208 _selectsInsertedObjects = [aCoder decodeBoolForKey:CPArrayControllerSelectsInsertedObjects];
1209 _alwaysUsesMultipleValuesMarker = [aCoder decodeBoolForKey:CPArrayControllerAlwaysUsesMultipleValuesMarker];
1210 _automaticallyRearrangesObjects = [aCoder decodeBoolForKey:CPArrayControllerAutomaticallyRearrangesObjects];
1211 _sortDescriptors = [CPArray array];
1213 if (![
self content] && [
self automaticallyPreparesContent])
1215 else if (![
self content])
1216 [
self _setContentArray:[]];
1226 [aCoder encodeBool:_avoidsEmptySelection forKey:CPArrayControllerAvoidsEmptySelection];
1227 [aCoder encodeBool:_clearsFilterPredicateOnInsertion forKey:CPArrayControllerClearsFilterPredicateOnInsertion];
1228 [aCoder encodeBool:_filterRestrictsInsertion forKey:CPArrayControllerFilterRestrictsInsertion];
1229 [aCoder encodeBool:_preservesSelection forKey:CPArrayControllerPreservesSelection];
1230 [aCoder encodeBool:_selectsInsertedObjects forKey:CPArrayControllerSelectsInsertedObjects];
1231 [aCoder encodeBool:_alwaysUsesMultipleValuesMarker forKey:CPArrayControllerAlwaysUsesMultipleValuesMarker];
1232 [aCoder encodeBool:_automaticallyRearrangesObjects forKey:CPArrayControllerAutomaticallyRearrangesObjects];
1235 - (void)awakeFromCib
1237 [
self _selectionWillChange];
1238 [
self _selectionDidChange];