35 BOOL _avoidsEmptySelection;
36 BOOL _clearsFilterPredicateOnInsertion;
37 BOOL _filterRestrictsInsertion;
38 BOOL _preservesSelection;
39 BOOL _selectsInsertedObjects;
40 BOOL _alwaysUsesMultipleValuesMarker;
42 BOOL _automaticallyRearrangesObjects;
45 CPArray _sortDescriptors;
46 CPPredicate _filterPredicate;
47 CPArray _arrangedObjects;
49 BOOL _disableSetContent;
61 + (CPSet)keyPathsForValuesAffectingContentArray
63 return [CPSet setWithObjects:@"content"];
66 + (CPSet)keyPathsForValuesAffectingArrangedObjects
69 return [CPSet setWithObjects:@"content", @"sortDescriptors"];
72 + (CPSet)keyPathsForValuesAffectingSelection
74 return [CPSet setWithObjects:@"selectionIndexes"];
77 + (CPSet)keyPathsForValuesAffectingSelectionIndex
79 return [CPSet setWithObjects:@"selectionIndexes"];
82 + (CPSet)keyPathsForValuesAffectingSelectionIndexes
86 return [CPSet setWithObjects:@"arrangedObjects"];
89 + (CPSet)keyPathsForValuesAffectingSelectedObjects
92 return [CPSet setWithObjects:@"selectionIndexes"];
95 + (CPSet)keyPathsForValuesAffectingCanRemove
97 return [CPSet setWithObjects:@"selectionIndexes"];
100 + (CPSet)keyPathsForValuesAffectingCanSelectNext
102 return [CPSet setWithObjects:@"selectionIndexes"];
105 + (CPSet)keyPathsForValuesAffectingCanSelectPrevious
107 return [CPSet setWithObjects:@"selectionIndexes"];
117 _preservesSelection = YES;
118 _selectsInsertedObjects = YES;
119 _avoidsEmptySelection = YES;
120 _clearsFilterPredicateOnInsertion = YES;
121 _alwaysUsesMultipleValuesMarker = NO;
122 _automaticallyRearrangesObjects = NO;
124 _filterRestrictsInsertion = YES;
134 _sortDescriptors = [CPArray array];
135 _filterPredicate = nil;
137 [
self __setArrangedObjects:[CPArray array]];
140 - (void)prepareContent
142 [
self _setContentArray:[[
self newObject]]];
148 - (BOOL)preservesSelection
150 return _preservesSelection;
158 - (void)setPreservesSelection:(BOOL)value
160 _preservesSelection = value;
166 - (BOOL)selectsInsertedObjects
168 return _selectsInsertedObjects;
175 - (void)setSelectsInsertedObjects:(BOOL)value
177 _selectsInsertedObjects = value;
183 - (BOOL)avoidsEmptySelection
185 return _avoidsEmptySelection;
192 - (void)setAvoidsEmptySelection:(BOOL)value
194 _avoidsEmptySelection = value;
202 - (BOOL)clearsFilterPredicateOnInsertion
204 return _clearsFilterPredicateOnInsertion;
212 - (void)setClearsFilterPredicateOnInsertion:(BOOL)aFlag
214 _clearsFilterPredicateOnInsertion = aFlag;
223 - (BOOL)alwaysUsesMultipleValuesMarker
225 return _alwaysUsesMultipleValuesMarker;
234 - (void)setAlwaysUsesMultipleValuesMarker:(BOOL)aFlag
236 _alwaysUsesMultipleValuesMarker = aFlag;
248 - (BOOL)automaticallyRearrangesObjects
250 return _automaticallyRearrangesObjects;
262 - (void)setAutomaticallyRearrangesObjects:(BOOL)aFlag
264 _automaticallyRearrangesObjects = aFlag;
272 - (void)setContent:(
id)value
277 if (_disableSetContent)
283 if (![value isKindOfClass:[CPArray
class]])
286 var oldSelectedObjects = nil,
287 oldSelectionIndexes = nil;
289 if ([
self preservesSelection])
306 if (_clearsFilterPredicateOnInsertion)
313 _contentObject = value;
315 if (_clearsFilterPredicateOnInsertion && _filterPredicate != nil)
316 [
self __setFilterPredicate:nil];
318 [
self _rearrangeObjects];
320 if ([
self preservesSelection])
321 [
self __setSelectedObjects:oldSelectedObjects];
323 [
self __setSelectionIndexes:oldSelectionIndexes];
325 if (_clearsFilterPredicateOnInsertion)
332 - (void)_setContentArray:(
id)anArray
334 [
self setContent:anArray];
340 - (void)_setContentSet:(
id)aSet
342 [
self setContent:[aSet allObjects]];
361 return [CPSet setWithArray:[
self content]];
370 - (CPArray)arrangeObjects:(CPArray)objects
375 if (filterPredicate && [sortDescriptors count] > 0)
377 var sortedObjects = [objects filteredArrayUsingPredicate:filterPredicate];
378 [sortedObjects sortUsingDescriptors:sortDescriptors];
379 return sortedObjects;
381 else if (filterPredicate)
382 return [objects filteredArrayUsingPredicate:filterPredicate];
383 else if ([sortDescriptors count] > 0)
384 return [objects sortedArrayUsingDescriptors:sortDescriptors];
386 return [objects copy];
392 - (void)rearrangeObjects
395 [
self _rearrangeObjects];
403 - (void)_rearrangeObjects
409 var oldSelectedObjects = nil,
410 oldSelectionIndexes = nil;
412 if ([
self preservesSelection])
413 oldSelectedObjects = [
self selectedObjects];
415 oldSelectionIndexes = [
self selectionIndexes];
417 [
self __setArrangedObjects:[
self arrangeObjects:[
self contentArray]]];
419 if ([
self preservesSelection])
420 [
self __setSelectedObjects:oldSelectedObjects];
422 [
self __setSelectionIndexes:oldSelectionIndexes];
428 - (void)__setArrangedObjects:(
id)value
430 if (_arrangedObjects === value)
433 _arrangedObjects = [[_CPObservableArray alloc] initWithArray:value];
440 - (id)arrangedObjects
442 return _arrangedObjects;
449 - (CPArray)sortDescriptors
451 return _sortDescriptors;
459 - (void)setSortDescriptors:(CPArray)value
461 if (_sortDescriptors === value)
464 _sortDescriptors = [value copy];
467 [
self _rearrangeObjects];
476 - (CPPredicate)filterPredicate
478 return _filterPredicate;
487 - (void)setFilterPredicate:(CPPredicate)value
489 if (_filterPredicate === value)
495 [
self __setFilterPredicate:value];
503 - (void)__setFilterPredicate:(CPPredicate)value
505 if (_filterPredicate === value)
508 _filterPredicate = value;
510 [
self _rearrangeObjects];
517 - (BOOL)alwaysUsesMultipleValuesMarker
519 return _alwaysUsesMultipleValuesMarker;
527 - (unsigned)selectionIndex
529 return [_selectionIndexes firstIndex];
538 - (BOOL)setSelectionIndex:(
unsigned)index
550 return _selectionIndexes;
561 [
self _selectionWillChange];
562 var r = [
self __setSelectionIndexes:indexes avoidEmpty:NO];
563 [
self _selectionDidChange];
571 - (BOOL)__setSelectionIndex:(
int)theIndex
580 - (BOOL)__setSelectionIndexes:(
CPIndexSet)indexes
582 return [
self __setSelectionIndexes:indexes avoidEmpty:_avoidsEmptySelection];
585 - (BOOL)__setSelectionIndexes:(
CPIndexSet)indexes avoidEmpty:(BOOL)avoidEmpty
587 var newIndexes = indexes;
592 if (![newIndexes count])
594 if (avoidEmpty && [[
self arrangedObjects] count])
599 var objectsCount = [[
self arrangedObjects] count];
604 newIndexes = [newIndexes copy];
607 [newIndexes removeIndexesInRange:CPMakeRange(objectsCount, [newIndexes lastIndex] + 1)];
609 if (![newIndexes count] && avoidEmpty && objectsCount)
613 if ([_selectionIndexes isEqualToIndexSet:newIndexes])
618 _selectionIndexes = indexes === newIndexes ? [indexes
copy] : newIndexes;
622 var binderClass = [[
self class] _binderClassForBinding:@"selectionIndexes"];
623 [[binderClass getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
632 - (CPArray)selectedObjects
636 return [_CPObservableArray arrayWithArray:(objects || [])];
645 - (BOOL)setSelectedObjects:(CPArray)objects
648 [
self _selectionWillChange];
650 var r = [
self __setSelectedObjects:objects avoidEmpty:NO];
653 [
self _selectionDidChange];
661 - (BOOL)__setSelectedObjects:(CPArray)objects
663 [
self __setSelectedObjects:objects avoidEmpty:_avoidsEmptySelection];
666 - (BOOL)__setSelectedObjects:(CPArray)objects avoidEmpty:(BOOL)avoidEmpty
669 count = [objects count],
670 arrangedObjects = [
self arrangedObjects];
672 for (var i = 0; i < count; i++)
674 var index = [arrangedObjects indexOfObject:[objects objectAtIndex:i]];
677 [
set addIndex:index];
680 [
self __setSelectionIndexes:set avoidEmpty:avoidEmpty];
690 - (BOOL)canSelectPrevious
699 - (void)selectPrevious:(
id)sender
704 [
self setSelectionIndexes:[
CPIndexSet indexSetWithIndex:index]];
712 - (BOOL)canSelectNext
721 - (void)selectNext:(
id)sender
725 if (index < [[
self arrangedObjects] count])
726 [
self setSelectionIndexes:[
CPIndexSet indexSetWithIndex:index]];
736 - (void)addObject:(
id)object
741 var willClearPredicate = NO;
743 if (_clearsFilterPredicateOnInsertion && _filterPredicate)
746 willClearPredicate = YES;
758 _disableSetContent = YES;
759 [_contentObject addObject:object];
764 _disableSetContent = NO;
766 if (willClearPredicate)
769 _filterPredicate = nil;
770 [
self _rearrangeObjects];
772 else if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:
object])
775 var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors];
779 if (_selectsInsertedObjects)
780 [
self __setSelectionIndex:pos];
782 [_selectionIndexes shiftIndexesStartingAtIndex:pos by:1];
792 var proxy = [_CPKVOProxy proxyForObject:self];
793 [proxy setAdding:YES];
798 if (willClearPredicate)
799 [
self didChangeValueForKey:
@"filterPredicate"];
802 [proxy setAdding:NO];
812 - (void)insertObject:(
id)anObject atArrangedObjectIndex:(
int)anIndex
817 var willClearPredicate = NO;
819 if (_clearsFilterPredicateOnInsertion && _filterPredicate)
822 willClearPredicate = YES;
830 _disableSetContent = YES;
835 [_contentObject addObject:anObject];
839 _disableSetContent = NO;
841 if (willClearPredicate)
842 [
self __setFilterPredicate:nil];
848 if ([
self selectsInsertedObjects])
849 [
self __setSelectionIndex:anIndex];
853 if ([
self avoidsEmptySelection] && [[
self selectionIndexes] count] <= 0 && [_contentObject count] > 0)
854 [
self __setSelectionIndexes:[
CPIndexSet indexSetWithIndex:0]];
856 var proxy = [_CPKVOProxy proxyForObject:self];
857 [proxy setAdding:YES];
861 if (willClearPredicate)
862 [
self didChangeValueForKey:
@"filterPredicate"];
864 [proxy setAdding:NO];
872 - (void)removeObject:(
id)object
877 _disableSetContent = YES;
879 [_contentObject removeObject:object];
883 _disableSetContent = NO;
885 if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:
object])
889 var pos = [_arrangedObjects indexOfObject:object];
891 [_arrangedObjects removeObjectAtIndex:pos];
892 [_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1];
895 [
self __setSelectionIndexes:_selectionIndexes];
906 - (void)add:(
id)sender
920 - (void)insert:(
id)sender
922 if (![
self canInsert])
926 lastSelectedIndex = [_selectionIndexes lastIndex];
929 [
self insertObject:newObject atArrangedObjectIndex:lastSelectedIndex];
938 - (void)remove:(
id)sender
947 - (void)removeObjectAtArrangedObjectIndex:(
int)index
956 - (void)removeObjectsAtArrangedObjectIndexes:(
CPIndexSet)anIndexSet
963 _disableSetContent = YES;
967 newSelectionIndexes = [_selectionIndexes copy];
975 if ([_contentObject objectAtIndex:anIndex] === object)
976 [_contentObject removeObjectAtIndex:anIndex];
984 var contentIndex = [_contentObject indexOfObjectIdenticalTo:object];
985 [_contentObject removeObjectAtIndex:contentIndex];
989 if (!_avoidsEmptySelection || [newSelectionIndexes count] > 1)
991 [newSelectionIndexes removeIndex:anIndex];
992 [newSelectionIndexes shiftIndexesStartingAtIndex:anIndex by:-1];
994 else if ([newSelectionIndexes lastIndex] !== anIndex)
995 [newSelectionIndexes shiftIndexesStartingAtIndex:anIndex by:-1];
1000 _disableSetContent = NO;
1003 [
self __setSelectionIndexes:newSelectionIndexes];
1013 - (void)addObjects:(CPArray)objects
1019 count = [objects count];
1021 for (var i = 0; i < count; i++)
1022 [contentArray addObject:[objects objectAtIndex:i]];
1033 - (void)removeObjects:(CPArray)objects
1035 [
self _removeObjects:objects];
1041 - (void)_removeObjects:(CPArray)objects
1043 [
self willChangeValueForKey:@"content"];
1046 _disableSetContent = YES;
1048 [_contentObject removeObjectsInArray:objects];
1052 _disableSetContent = NO;
1054 var arrangedObjects = [
self arrangedObjects],
1055 position = [arrangedObjects indexOfObject:[objects objectAtIndex:0]];
1057 [arrangedObjects removeObjectsInArray:objects];
1059 var objectsCount = [arrangedObjects count],
1062 if ([
self preservesSelection] || [
self avoidsEmptySelection])
1067 if (objectsCount <= 0)
1072 selectionIndexes = [
CPIndexSet indexSetWithIndex:objectsCount - 1];
1075 _selectionIndexes = selectionIndexes;
1077 [
self didChangeValueForKey:@"content"];
1093 + (Class)_binderClassForBinding:(
CPString)aBinding
1095 if (aBinding ==
@"contentArray")
1096 return [_CPArrayControllerContentBinder
class];
1098 return [
super _binderClassForBinding:aBinding];
1102 @implementation _CPArrayControllerContentBinder :
CPBinder 1107 - (void)setValueFor:(
CPString)aBinding
1109 var destination = [_info objectForKey:CPObservedObjectKey],
1110 keyPath = [_info objectForKey:CPObservedKeyPathKey],
1111 options = [_info objectForKey:CPOptionsKey],
1112 isCompound = [
self handlesContentAsCompoundValue],
1113 dotIndex = keyPath.lastIndexOf(
"."),
1114 firstPart = dotIndex !==
CPNotFound ? keyPath.substring(0, dotIndex) : nil,
1115 isSelectionProxy = firstPart && [[destination valueForKeyPath:firstPart] isKindOfClass:CPControllerSelectionProxy],
1118 if (!isCompound && !isSelectionProxy)
1120 newValue = [destination mutableArrayValueForKeyPath:keyPath];
1132 newValue = [destination valueForKeyPath:keyPath];
1135 var isPlaceholder = CPIsControllerMarker(newValue);
1139 if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
1142 reason:@"can't transform non applicable key on: " + _source + " value: " + newValue];
1145 newValue = [
self _placeholderForMarker:newValue];
1152 newValue = [
self transformValue:newValue withOptions:options];
1158 newValue = [newValue mutableCopy];
1161 [_source setValue:newValue forKey:aBinding];
1164 - (void)_contentArrayDidChange
1173 if ([
self handlesContentAsCompoundValue])
1175 var destination = [_info objectForKey:CPObservedObjectKey],
1176 keyPath = [_info objectForKey:CPObservedKeyPathKey];
1178 [
self suppressSpecificNotificationFromObject:destination keyPath:keyPath];
1179 [
self reverseSetValueFor:@"contentArray"];
1180 [
self unsuppressSpecificNotificationFromObject:destination keyPath:keyPath];
1202 _avoidsEmptySelection = [aCoder decodeBoolForKey:CPArrayControllerAvoidsEmptySelection];
1203 _clearsFilterPredicateOnInsertion = [aCoder decodeBoolForKey:CPArrayControllerClearsFilterPredicateOnInsertion];
1204 _filterRestrictsInsertion = [aCoder decodeBoolForKey:CPArrayControllerFilterRestrictsInsertion];
1205 _preservesSelection = [aCoder decodeBoolForKey:CPArrayControllerPreservesSelection];
1206 _selectsInsertedObjects = [aCoder decodeBoolForKey:CPArrayControllerSelectsInsertedObjects];
1207 _alwaysUsesMultipleValuesMarker = [aCoder decodeBoolForKey:CPArrayControllerAlwaysUsesMultipleValuesMarker];
1208 _automaticallyRearrangesObjects = [aCoder decodeBoolForKey:CPArrayControllerAutomaticallyRearrangesObjects];
1209 _sortDescriptors = [CPArray array];
1211 if (![
self content] && [
self automaticallyPreparesContent])
1213 else if (![
self content])
1214 [
self _setContentArray:[]];
1224 [aCoder encodeBool:_avoidsEmptySelection forKey:CPArrayControllerAvoidsEmptySelection];
1225 [aCoder encodeBool:_clearsFilterPredicateOnInsertion forKey:CPArrayControllerClearsFilterPredicateOnInsertion];
1226 [aCoder encodeBool:_filterRestrictsInsertion forKey:CPArrayControllerFilterRestrictsInsertion];
1227 [aCoder encodeBool:_preservesSelection forKey:CPArrayControllerPreservesSelection];
1228 [aCoder encodeBool:_selectsInsertedObjects forKey:CPArrayControllerSelectsInsertedObjects];
1229 [aCoder encodeBool:_alwaysUsesMultipleValuesMarker forKey:CPArrayControllerAlwaysUsesMultipleValuesMarker];
1230 [aCoder encodeBool:_automaticallyRearrangesObjects forKey:CPArrayControllerAutomaticallyRearrangesObjects];
1233 - (void)awakeFromCib
1235 [
self _selectionWillChange];
1236 [
self _selectionDidChange];
Used to implement exception handling (creating & raising).
void willChangeValueForKey:(CPString aKey)
BOOL automaticallyPreparesContent()
void raise:reason:(CPString aName, [reason] CPString aReason)
A collection of unique integers.
var CPArrayControllerAvoidsEmptySelection
void setContent:(id value)
CPArray sortDescriptors()
id initWithCoder:(CPCoder aCoder)
An immutable string (collection of characters).
void encodeWithCoder:(CPCoder aCoder)
void shiftIndexesStartingAtIndex:by:(CPInteger anIndex, [by] int aDelta)
void removeObjectsAtArrangedObjectIndexes:(CPIndexSet anIndexSet)
CPPredicate filterPredicate()
CPBinder getBinding:forObject:(CPString aBinding, [forObject] id anObject)
var CPArrayControllerSelectsInsertedObjects
var CPArrayControllerFilterRestrictsInsertion
void exposeBinding:(CPString aBinding)
void didChangeValueForKey:(CPString aKey)
Defines methods for use when archiving & restoring (enc/decoding).
BOOL setSelectionIndexes:(CPIndexSet indexes)
var CPArrayControllerAlwaysUsesMultipleValuesMarker
CPArray selectedObjects()
var CPArrayControllerPreservesSelection
id indexSetWithIndex:(int anIndex)
void enumerateIndexesWithOptions:usingBlock:(CPEnumerationOptions options, [usingBlock] Function/*(int idx, @ref BOOL stop) */aFunction)
void addObject:(id object)
CPIndexSet selectionIndexes()
var CPArrayControllerAutomaticallyRearrangesObjects
var CPArrayControllerClearsFilterPredicateOnInsertion