From 10df31cbf977e73e47326f2388eab2f80d86ed95 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Tue, 22 Jun 2010 07:47:30 +0200 Subject: [PATCH 01/41] made isEqual: work on CPIndexSet and updated unit tests --- Foundation/CPIndexSet.j | 11 +++++++++++ Tests/Foundation/CPIndexSetTest.j | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/Foundation/CPIndexSet.j b/Foundation/CPIndexSet.j index 266c7273e..9975c0e11 100644 --- a/Foundation/CPIndexSet.j +++ b/Foundation/CPIndexSet.j @@ -130,6 +130,17 @@ return self; } +- (BOOL)isEqual:(id)anObject +{ + if (self === anObject) + return YES; + + if (![anObject isKindOfClass:[CPIndexSet class]]) + return NO; + + return [self isEqualToIndexSet:anObject]; +} + // Querying an Index Set /*! Compares the receiver with the provided index set. diff --git a/Tests/Foundation/CPIndexSetTest.j b/Tests/Foundation/CPIndexSetTest.j index c38778903..b63ff8cf9 100644 --- a/Tests/Foundation/CPIndexSetTest.j +++ b/Tests/Foundation/CPIndexSetTest.j @@ -368,6 +368,26 @@ function descriptionWithoutEntity(aString) [self assertTrue:[_set containsIndexes:[CPIndexSet indexSetWithIndexesInRange:startRange]]]; } +- (void)testIsEqual +{ + var differentSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 11)], + equalSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 10)]; + + [self assertFalse:[_set isEqual:differentSet]]; + [self assertTrue:[_set isEqual:equalSet]]; + [self assertTrue:[_set isEqual:_set]]; +} + +- (void)testIsEqualToIndexSet +{ + var differentSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 11)], + equalSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 10)]; + + [self assertFalse:[_set isEqualToIndexSet:differentSet]]; + [self assertTrue:[_set isEqualToIndexSet:equalSet]]; + [self assertTrue:[_set isEqualToIndexSet:_set]]; +} + - (void)tearDown { _set = nil; From 6b132c4d3b7eb44daae513001abf27a09fc7fc61 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 30 Jun 2010 11:15:38 +0200 Subject: [PATCH 02/41] added check for nil in CPIndexSet isEqual --- Foundation/CPIndexSet.j | 2 +- Tests/Foundation/CPIndexSetTest.j | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Foundation/CPIndexSet.j b/Foundation/CPIndexSet.j index 9975c0e11..af528b169 100644 --- a/Foundation/CPIndexSet.j +++ b/Foundation/CPIndexSet.j @@ -135,7 +135,7 @@ if (self === anObject) return YES; - if (![anObject isKindOfClass:[CPIndexSet class]]) + if (!anObject || ![anObject isKindOfClass:[CPIndexSet class]]) return NO; return [self isEqualToIndexSet:anObject]; diff --git a/Tests/Foundation/CPIndexSetTest.j b/Tests/Foundation/CPIndexSetTest.j index b63ff8cf9..49e3194df 100644 --- a/Tests/Foundation/CPIndexSetTest.j +++ b/Tests/Foundation/CPIndexSetTest.j @@ -373,6 +373,7 @@ function descriptionWithoutEntity(aString) var differentSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 11)], equalSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 10)]; + [self assertFalse:[_set isEqual:nil]]; [self assertFalse:[_set isEqual:differentSet]]; [self assertTrue:[_set isEqual:equalSet]]; [self assertTrue:[_set isEqual:_set]]; From 914175de70921f31a4b092a950522fa27c27ed40 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 12 Jul 2010 15:41:00 +0200 Subject: [PATCH 03/41] If CPValueTransformerNameBindingOption contains an existing class, allocate and use it in CPKeyValueBinding --- AppKit/CPKeyValueBinding.j | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/AppKit/CPKeyValueBinding.j b/AppKit/CPKeyValueBinding.j index a926cdd2b..89fd10c13 100644 --- a/AppKit/CPKeyValueBinding.j +++ b/AppKit/CPKeyValueBinding.j @@ -181,7 +181,22 @@ var CPBindingOperationAnd = 0, valueTransformer; if (valueTransformerName) + { + if (valueTransformerName === @"ESIsEmptyIndexSetValueTransformer") + debugger; + valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName]; + + if (!valueTransformer) + { + var valueTransformerClass = CPClassFromString(valueTransformerName); + if (valueTransformerClass) + { + valueTransformer = [[valueTransformerClass alloc] init]; + [valueTransformerClass setValueTransformer:valueTransformer forName:valueTransformerName]; + } + } + } else valueTransformer = [options objectForKey:CPValueTransformerBindingOption]; From c17a3533ecae63d479b285b23ac3a490ebe8bd3c Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Tue, 20 Jul 2010 14:59:18 +0200 Subject: [PATCH 04/41] fix #764 Array controller inserts object in wrong arranged object position if there are no sort descriptors defined --- AppKit/CPArrayController.j | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index c11206f79..72aab18f4 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -400,16 +400,23 @@ if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object]) { - var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors]; + var position; + if ([_sortDescriptors count] > 0) + position = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors]; + else + { + [_arrangedObjects addObject:object]; + position = [_arrangedObjects count] - 1; + } if (_selectsInsertedObjects) { - [self setSelectionIndex:pos]; + [self setSelectionIndex:position]; } else { [self willChangeValueForKey:@"selectionIndexes"]; - [_selectionIndexes shiftIndexesStartingAtIndex:pos by:1]; + [_selectionIndexes shiftIndexesStartingAtIndex:position by:1]; [self didChangeValueForKey:@"selectionIndexes"]; } } From 138888e6201d4efee04e55b159dac6122c341895 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 26 Jul 2010 14:04:05 +0200 Subject: [PATCH 05/41] implement CPArrayController insertObject:atArrangedObjectIndex: --- AppKit/CPArrayController.j | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index c11206f79..fed04b4b1 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -417,6 +417,33 @@ [self rearrangeObjects]; } +- (void)insertObject:(id)anObject atArrangedObjectIndex:(int)anIndex +{ + if (![self canAdd]) + return; + + [self willChangeValueForKey:@"content"]; + [_contentObject insertObject:anObject atIndex:anIndex]; + [self didChangeValueForKey:@"content"]; + + if (_clearsFilterPredicateOnInsertion) + [self setFilterPredicate:nil]; + + [[self arrangedObjects] insertObject:anObject atIndex:anIndex]; + + if ([self selectsInsertedObjects]) + [self setSelectionIndex:anIndex]; + else + { + [self willChangeValueForKey:@"selectionIndexes"] + [[self selectionIndexes] shiftIndexesStartingAtIndex:anIndex by:1]; + [self didChangeValueForKey:@"selectionIndexes"]; + } + + if ([self avoidsEmptySelection] && [[self selectionIndexes] count] <= 0 && [_contentObject count] > 0) + [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]]; +} + - (void)removeObject:(id)object { if (![self canRemove]) From bb3c08ce0ba6b6a52164c131b6d22b02e39f74e1 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 26 Jul 2010 14:04:26 +0200 Subject: [PATCH 06/41] add CPArrayController test --- Tests/AppKit/CPArrayControllerTest.j | 86 ++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 Tests/AppKit/CPArrayControllerTest.j diff --git a/Tests/AppKit/CPArrayControllerTest.j b/Tests/AppKit/CPArrayControllerTest.j new file mode 100644 index 000000000..4ea774920 --- /dev/null +++ b/Tests/AppKit/CPArrayControllerTest.j @@ -0,0 +1,86 @@ +@implementation CPArrayControllerTest : OJTestCase +{ + CPArrayController _arrayController @accessors(property=arrayController); + CPArray _contentArray @accessors(property=contentArray); +} + +- (void)setUp +{ + _contentArray = []; + + [_contentArray addObject:[Person personWithName:@"Francisco" age:21]]; + [_contentArray addObject:[Person personWithName:@"Ross" age:30]]; + [_contentArray addObject:[Person personWithName:@"Tom" age:15]]; + + _arrayController = [[CPArrayController alloc] initWithContent:[self contentArray]]; +} + +- (void)testInitWithContent +{ + [self assert:[self contentArray] equals:[[self arrayController] contentArray]]; + [self assert:[_CPObservableArray class] equals:[[[self arrayController] arrangedObjects] class]]; +} + +- (void)testSetContent +{ + otherContent = [@"5", @"6"]; + [[self arrayController] setContent:otherContent]; + + [self assert:otherContent equals:[[self arrayController] contentArray]]; + [self assert:[_CPObservableArray class] equals:[[[self arrayController] arrangedObjects] class]]; +} + +- (void)testInsertObjectAtArrangedObjectIndex +{ + var object = [Person personWithName:@"Klaas Pieter" age:24], + arrayController = [self arrayController]; + + [arrayController setSortDescriptors:[[CPSortDescriptor sortDescriptorWithKey:@"age" ascending:YES]]]; + [arrayController insertObject:object atArrangedObjectIndex:1]; + + [self assert:object equals:[[arrayController arrangedObjects] objectAtIndex:1]]; +} + +- (void)testContentBinding +{ + [[self arrayController] bind:@"contentArray" toObject:self withKeyPath:@"contentArray" options:0]; + + [self assert:[[self arrayController] contentArray] equals:[self contentArray]]; + + [[self mutableArrayValueForKey:@"contentArray"] addObject:@"4"]; + [self assert:[self contentArray] equals:[[self arrayController] contentArray]]; + + [[self arrayController] insertObject:@"2" atArrangedObjectIndex:1]; + [self assert:[[self arrayController] contentArray] equals:[self contentArray]]; +} + +@end + +@implementation Person : CPObject +{ + CPString _name @accessors(property=name); + int _age @accessors(property=age); +} + ++ (id)personWithName:(CPString)aName age:(int)anAge +{ + return [[self alloc] initWithName:aName age:anAge]; +} + +- (id)initWithName:(CPString)aName age:(int)anAge +{ + if (self = [super init]) + { + _name = aName; + _age = anAge; + } + + return self; +} + +- (CPString)description +{ + return [CPString stringWithFormat:@"%@ : %@", [self name], [self age]]; +} + +@end \ No newline at end of file From 4f946f267ef7a4c94a05dd88acdc41a8ade2ba19 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 26 Jul 2010 18:34:13 +0200 Subject: [PATCH 07/41] fix CPArrayController removeObject: removeObject: only shifted the selection, it never actually removes the object --- AppKit/CPArrayController.j | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index c11206f79..ad40efcd2 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -426,12 +426,14 @@ [_contentObject removeObject:object]; [self didChangeValueForKey:@"content"]; - if ([_filterPredicate evaluateWithObject:object]) + if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object]) { [self willChangeValueForKey:@"selectionIndexes"]; var pos = [_arrangedObjects indexOfObject:object]; + [_arrangedObjects removeObjectAtIndex:pos]; [_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1]; + [self didChangeValueForKey:@"selectionIndexes"]; } } From b9c2becd3e6e9eb1ed82e37d440fc6a528e19af0 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Tue, 27 Jul 2010 09:09:59 +0200 Subject: [PATCH 08/41] implement CPIndexSet isEqual: --- Foundation/CPIndexSet.j | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Foundation/CPIndexSet.j b/Foundation/CPIndexSet.j index 266c7273e..af528b169 100644 --- a/Foundation/CPIndexSet.j +++ b/Foundation/CPIndexSet.j @@ -130,6 +130,17 @@ return self; } +- (BOOL)isEqual:(id)anObject +{ + if (self === anObject) + return YES; + + if (!anObject || ![anObject isKindOfClass:[CPIndexSet class]]) + return NO; + + return [self isEqualToIndexSet:anObject]; +} + // Querying an Index Set /*! Compares the receiver with the provided index set. From 48a5d55af714a89f88269a4ced9828c1e03fcd4f Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Tue, 27 Jul 2010 09:10:41 +0200 Subject: [PATCH 09/41] fix CPArrayController selectPrevious: and selectNext: Also added unit-tests for canSelectPrevious, canSelectNext, selectPrevious: and selectNext: --- AppKit/CPArrayController.j | 24 +++++------ Tests/AppKit/CPArrayControllerTest.j | 59 ++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 12 deletions(-) diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index a799b296d..189485a8c 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -358,29 +358,29 @@ //Moving selection --(BOOL)canSelectPrevious +- (BOOL)canSelectPrevious { return [[self selectionIndexes] firstIndex] > 0 } --(BOOL)canSelectNext +-(void)selectPrevious:(id)sender { - return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] -1; -} + var index = [[self selectionIndexes] firstIndex] - 1; --(void)selectNext:(id)sender -{ - var index = [[self selectionIndexes] firstIndex] + 1 || 0; - - if (index < [[self arrangedObjects] count]) + if (index >= 0) [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; } --(void)selectPrevious:(id)sender +- (BOOL)canSelectNext { - var index = [[self selectionIndexes] firstIndex] - 1 || [[self arrangedObjects] count] - 1; + return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] - 1; +} - if (index >= 0) +- (void)selectNext:(id)sender +{ + var index = [[self selectionIndexes] firstIndex] + 1; + + if (index < [[self arrangedObjects] count]) [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; } diff --git a/Tests/AppKit/CPArrayControllerTest.j b/Tests/AppKit/CPArrayControllerTest.j index 4ea774920..532771848 100644 --- a/Tests/AppKit/CPArrayControllerTest.j +++ b/Tests/AppKit/CPArrayControllerTest.j @@ -41,6 +41,65 @@ [self assert:object equals:[[arrayController arrangedObjects] objectAtIndex:1]]; } +- (void)testSelectPrevious +{ + var arrayController = [self arrayController]; + + // Selection index: 1 + [arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndex:1]]; + [self assertTrue:[arrayController canSelectPrevious] message:@"index > 0; canSelectPrevious should return YES"] + + [arrayController selectPrevious:self]; + [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]]; + + // Selection index: 0 + [self assertFalse:[arrayController canSelectPrevious] message:@"index <= 0; canSelectPrevious should return NO"]; + + [arrayController selectPrevious:self]; + [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]]; +} + +- (void)testSelectNext +{ + var arrayController = [self arrayController], + count = [[arrayController arrangedObjects] count]; + + // Selection index: count - 2 + [arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndex:count - 2]]; + [self assertTrue:[arrayController canSelectNext] message:@"index < (count - 1); canSelectNext should return YES"]; + + [arrayController selectNext:self]; + [self assert:[CPIndexSet indexSetWithIndex:count - 1] equals:[arrayController selectionIndexes]]; + + // Selection index: count - 1 + [self assertFalse:[arrayController canSelectNext] message:@"index >= (count - 1) canSelectNext should return NO"]; + + [arrayController selectNext:self]; + [self assert:[CPIndexSet indexSetWithIndex:count - 1] equals:[arrayController selectionIndexes]]; +} +// - (void)testSelectNext +// { +// var arrayController = [self arrayController], +// arrangedObjects = [arrayController arrangedObjects], +// startIndex = 0, +// selectionIndexes = [CPIndexSet indexSetWithIndex:startIndex]; +// +// [arrayController setSelectionIndexes:selectionIndexes]; +// [arrayController selectNext:self]; +// +// [selectionIndexes shiftIndexesStartingAtIndex:startIndex by:1] +// [self assert:selectionIndexes equals:[arrayController selectionIndexes]]; +// +// // Test that the selection wraps around +// startIndex = [arrangedObjects count] - 1; +// selectionIndexes = [CPIndexSet indexSetWithIndex:startIndex]; +// +// [arrayController setSelectionIndexes:selectionIndexes]; +// [arrayController selectNext:self]; +// +// [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]]; +// } + - (void)testContentBinding { [[self arrayController] bind:@"contentArray" toObject:self withKeyPath:@"contentArray" options:0]; From 75ceeffab8068b4d136a6af8ccc575bb24a8abd5 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 28 Jul 2010 13:28:53 +0200 Subject: [PATCH 10/41] remove commented code from CPArrayControllerTest --- Tests/AppKit/CPArrayControllerTest.j | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/Tests/AppKit/CPArrayControllerTest.j b/Tests/AppKit/CPArrayControllerTest.j index 532771848..c7bf08a96 100644 --- a/Tests/AppKit/CPArrayControllerTest.j +++ b/Tests/AppKit/CPArrayControllerTest.j @@ -77,28 +77,6 @@ [arrayController selectNext:self]; [self assert:[CPIndexSet indexSetWithIndex:count - 1] equals:[arrayController selectionIndexes]]; } -// - (void)testSelectNext -// { -// var arrayController = [self arrayController], -// arrangedObjects = [arrayController arrangedObjects], -// startIndex = 0, -// selectionIndexes = [CPIndexSet indexSetWithIndex:startIndex]; -// -// [arrayController setSelectionIndexes:selectionIndexes]; -// [arrayController selectNext:self]; -// -// [selectionIndexes shiftIndexesStartingAtIndex:startIndex by:1] -// [self assert:selectionIndexes equals:[arrayController selectionIndexes]]; -// -// // Test that the selection wraps around -// startIndex = [arrangedObjects count] - 1; -// selectionIndexes = [CPIndexSet indexSetWithIndex:startIndex]; -// -// [arrayController setSelectionIndexes:selectionIndexes]; -// [arrayController selectNext:self]; -// -// [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]]; -// } - (void)testContentBinding { From ff98a9be5a011a8c754455c383e0503dd6b869d4 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 28 Jul 2010 15:02:48 +0200 Subject: [PATCH 11/41] fix preserve selection in removeObjects and added unit test --- AppKit/CPArrayController.j | 31 +++++- Tests/AppKit/CPArrayControllerTest.j | 153 +++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 Tests/AppKit/CPArrayControllerTest.j diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index 4953c3016..3830758db 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -489,13 +489,34 @@ - (void)_removeObjects:(CPArray)objects { - var contentArray = [self contentArray], - count = [objects count]; + [self willChangeValueForKey:@"content"]; + [_contentObject removeObjectsInArray:objects]; + [self didChangeValueForKey:@"content"]; - for (var i=0; i= objectsCount) + selectionIndexes = [CPIndexSet indexSetWithIndex:objectsCount - 1]; + } + + [self willChangeValueForKey:@"selectionIndexes"]; + _selectionIndexes = selectionIndexes; + [self didChangeValueForKey:@"selectionIndexes"]; } - (BOOL)canInsert diff --git a/Tests/AppKit/CPArrayControllerTest.j b/Tests/AppKit/CPArrayControllerTest.j new file mode 100644 index 000000000..dd2415e56 --- /dev/null +++ b/Tests/AppKit/CPArrayControllerTest.j @@ -0,0 +1,153 @@ +@implementation CPArrayControllerTest : OJTestCase +{ + CPArrayController _arrayController @accessors(property=arrayController); + CPArray _contentArray @accessors(property=contentArray); +} + +- (void)setUp +{ + _contentArray = []; + + [_contentArray addObject:[Person personWithName:@"Francisco" age:21]]; + [_contentArray addObject:[Person personWithName:@"Ross" age:30]]; + [_contentArray addObject:[Person personWithName:@"Tom" age:15]]; + + _arrayController = [[CPArrayController alloc] initWithContent:[self contentArray]]; +} + +- (void)testInitWithContent +{ + [self assert:[self contentArray] equals:[[self arrayController] contentArray]]; + [self assert:[_CPObservableArray class] equals:[[[self arrayController] arrangedObjects] class]]; +} + +- (void)testSetContent +{ + otherContent = [@"5", @"6"]; + [[self arrayController] setContent:otherContent]; + + [self assertFalse:otherContent === [[self arrayController] contentArray] message:@"array controller should copy it's content"]; + [self assert:otherContent equals:[[self arrayController] contentArray]]; + [self assert:[_CPObservableArray class] equals:[[[self arrayController] arrangedObjects] class]]; +} + +- (void)testInsertObjectAtArrangedObjectIndex +{ + var object = [Person personWithName:@"Klaas Pieter" age:24], + arrayController = [self arrayController]; + + [arrayController setSortDescriptors:[[CPSortDescriptor sortDescriptorWithKey:@"age" ascending:YES]]]; + [arrayController insertObject:object atArrangedObjectIndex:1]; + + [self assert:object equals:[[arrayController arrangedObjects] objectAtIndex:1]]; +} + +- (void)testSelectPrevious +{ + var arrayController = [self arrayController]; + + // Selection index: 1 + [arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndex:1]]; + [self assertTrue:[arrayController canSelectPrevious] message:@"index > 0; canSelectPrevious should return YES"] + + [arrayController selectPrevious:self]; + [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]]; + + // Selection index: 0 + [self assertFalse:[arrayController canSelectPrevious] message:@"index <= 0; canSelectPrevious should return NO"]; + + [arrayController selectPrevious:self]; + [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]]; +} + +- (void)testSelectNext +{ + var arrayController = [self arrayController], + count = [[arrayController arrangedObjects] count]; + + // Selection index: count - 2 + [arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndex:count - 2]]; + [self assertTrue:[arrayController canSelectNext] message:@"index < (count - 1); canSelectNext should return YES"]; + + [arrayController selectNext:self]; + [self assert:[CPIndexSet indexSetWithIndex:count - 1] equals:[arrayController selectionIndexes]]; + + // Selection index: count - 1 + [self assertFalse:[arrayController canSelectNext] message:@"index >= (count - 1) canSelectNext should return NO"]; + + [arrayController selectNext:self]; + [self assert:[CPIndexSet indexSetWithIndex:count - 1] equals:[arrayController selectionIndexes]]; +} + +- (void)testRemoveObjects +{ + var arrayController = [self arrayController]; + [arrayController setPreservesSelection:NO]; + + [arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(1, 2)]]; + [arrayController removeObjects:[arrayController selectedObjects]] + + [self assert:[CPIndexSet indexSet] equals:[arrayController selectionIndexes] + message:@"selection should be empty if arraycontroller doesn't preserve selection"]; + + arrayController = [[CPArrayController alloc] initWithContent:[self contentArray]]; + [arrayController setPreservesSelection:YES]; + print([self contentArray]); + + // Remove from middle + var selectionIndexes = [CPIndexSet indexSetWithIndex:1]; + [arrayController setSelectionIndexes:selectionIndexes]; + [arrayController removeObjects:[arrayController selectedObjects]]; + [self assert:selectionIndexes equals:[arrayController selectionIndexes] message:@"selection should stay the same"]; + + // Remove from end + [arrayController removeObjects:[[[arrayController content] objectAtIndex:1]]]; + [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes] + message:@"last object removed; selection should shift to first available index"]; + + // Remove from all + [arrayController removeObjects:[[[arrayController content] objectAtIndex:0]]]; + [self assert:[CPIndexSet indexSet] equals:[arrayController selectionIndexes] message:@"no objects left, selection should disappear"]; +} + +- (void)testContentBinding +{ + [[self arrayController] bind:@"contentArray" toObject:self withKeyPath:@"contentArray" options:0]; + + [self assert:[[self arrayController] contentArray] equals:[self contentArray]]; + + [[self mutableArrayValueForKey:@"contentArray"] addObject:@"4"]; + [self assert:[self contentArray] equals:[[self arrayController] contentArray] + message:@"object 4 was added; contentArray should reflect this"]; +} + +@end + +@implementation Person : CPObject +{ + CPString _name @accessors(property=name); + int _age @accessors(property=age); +} + ++ (id)personWithName:(CPString)aName age:(int)anAge +{ + return [[self alloc] initWithName:aName age:anAge]; +} + +- (id)initWithName:(CPString)aName age:(int)anAge +{ + if (self = [super init]) + { + _name = aName; + _age = anAge; + } + + return self; +} + +- (CPString)description +{ + return [CPString stringWithFormat:@"%@ : %@", [self name], [self age]]; +} + +@end \ No newline at end of file From 1a9670ae9cf755b8e2cb6a6950dfd8c5e197d413 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 17 May 2010 12:32:56 +0200 Subject: [PATCH 12/41] made sure CPViewController calls viewDidLoad if it's view property is set directly --- AppKit/CPViewController.j | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/AppKit/CPViewController.j b/AppKit/CPViewController.j index 3fffe261d..ab8c3a22e 100644 --- a/AppKit/CPViewController.j +++ b/AppKit/CPViewController.j @@ -162,8 +162,6 @@ var CPViewControllerCachedCibs; if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)]) [cibOwner viewControllerDidLoadCib:self]; - - [self viewDidLoad]; } return _view; @@ -189,7 +187,13 @@ var CPViewControllerCachedCibs; */ - (void)setView:(CPView)aView { + var viewWasLoaded = !_view; + _view = aView; + + // Make sure the viewDidLoad method is called if the view is set directly + if (viewWasLoaded) + [self viewDidLoad]; } @end From c8515225366bdf8daf91a8799854fd04ea57b771 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 12 Aug 2010 23:12:14 -0400 Subject: [PATCH 13/41] Fixed: if the CPWebView iframe was destroyed before its HTML loader timer fired, an error would occur. --- AppKit/CPWebView.j | 91 +++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/AppKit/CPWebView.j b/AppKit/CPWebView.j index bf36a7773..dca2637ab 100644 --- a/AppKit/CPWebView.j +++ b/AppKit/CPWebView.j @@ -50,23 +50,23 @@ CPWebViewScrollNative = 2; { CPScrollView _scrollView; CPView _frameView; - + IFrame _iframe; CPString _mainFrameURL; CPArray _backwardStack; CPArray _forwardStack; - + BOOL _ignoreLoadStart; BOOL _ignoreLoadEnd; - + id _downloadDelegate; id _frameLoadDelegate; id _policyDelegate; id _resourceLoadDelegate; id _UIDelegate; - + CPWebScriptObject _wso; - + CPString _url; CPString _html; @@ -95,10 +95,10 @@ CPWebViewScrollNative = 2; _backwardStack = []; _forwardStack = []; _scrollMode = CPWebViewScrollNative; - + [self _initDOMWithFrame:aFrame]; } - + return self; } @@ -106,52 +106,52 @@ CPWebViewScrollNative = 2; { _ignoreLoadStart = YES; _ignoreLoadEnd = YES; - + _iframe = document.createElement("iframe"); _iframe.name = "iframe_" + Math.floor(Math.random()*10000); _iframe.style.width = "100%"; _iframe.style.height = "100%"; _iframe.style.borderWidth = "0px"; _iframe.frameBorder = "0"; - + [self setDrawsBackground:YES]; - + _loadCallback = function() { // HACK: this block handles the case where we don't know about loads initiated by the user clicking a link if (!_ignoreLoadStart) { // post the start load notification [self _startedLoading]; - + if (_mainFrameURL) [_backwardStack addObject:_mainFrameURL]; - + // FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions. _mainFrameURL = _iframe.src; _mainFrameURL = _iframe.src; - + // clear the forward [_forwardStack removeAllObjects]; } else _ignoreLoadStart = NO; - + if (!_ignoreLoadEnd) { [self _finishedLoading]; } else _ignoreLoadEnd = NO; - + [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; } - + if (_iframe.addEventListener) _iframe.addEventListener("load", _loadCallback, false); else if (_iframe.attachEvent) _iframe.attachEvent("onload", _loadCallback); - - + + _frameView = [[CPView alloc] initWithFrame:[self bounds]]; [_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; @@ -159,9 +159,9 @@ CPWebViewScrollNative = 2; [_scrollView setAutohidesScrollers:YES]; [_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; [_scrollView setDocumentView:_frameView]; - + _frameView._DOMElement.appendChild(_iframe); - + [self _setScrollMode:_scrollMode]; [self addSubview:_scrollView]; @@ -169,7 +169,7 @@ CPWebViewScrollNative = 2; - (void)setFrameSize:(CPSize)aSize -{ +{ [super setFrameSize:aSize]; [self _resizeWebFrame]; } @@ -211,7 +211,7 @@ CPWebViewScrollNative = 2; { var visibleRect = [_frameView visibleRect]; [_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))]; - + // try to get the document size so we can correctly set the frame var win = null; try { win = [self DOMWindow]; } catch (e) {} @@ -229,7 +229,7 @@ CPWebViewScrollNative = 2; else { CPLog.warn("using default size 800*1600"); - + [_frameView setFrameSize:CGSizeMake(800, 1600)]; } @@ -242,7 +242,7 @@ CPWebViewScrollNative = 2; { if (_scrollMode == aScrollMode) return; - + [self _setScrollMode:aScrollMode]; } @@ -252,7 +252,7 @@ CPWebViewScrollNative = 2; _scrollMode = CPWebViewScrollNative; else _scrollMode = aScrollMode; - + _ignoreLoadStart = YES; _ignoreLoadEnd = YES; @@ -263,16 +263,16 @@ CPWebViewScrollNative = 2; { [_scrollView setHasHorizontalScroller:YES]; [_scrollView setHasVerticalScroller:YES]; - + _iframe.setAttribute("scrolling", "no"); } else { [_scrollView setHasHorizontalScroller:NO]; [_scrollView setHasVerticalScroller:NO]; - + _iframe.setAttribute("scrolling", "auto"); - + [_frameView setFrameSize:[_scrollView bounds].size]; } @@ -293,13 +293,13 @@ CPWebViewScrollNative = 2; [_frameView setFrameSize:[_scrollView contentSize]]; [self _startedLoading]; - + _ignoreLoadStart = YES; _ignoreLoadEnd = NO; - + _url = null; _html = aString; - + [self _load]; } @@ -308,13 +308,13 @@ CPWebViewScrollNative = 2; [self _setScrollMode:CPWebViewScrollNative]; [self _startedLoading]; - + _ignoreLoadStart = YES; _ignoreLoadEnd = NO; - + _url = _mainFrameURL; _html = null; - + [self _load]; } @@ -335,12 +335,13 @@ CPWebViewScrollNative = 2; _loadHTMLStringTimer = nil; } - // need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document + // need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document _loadHTMLStringTimer = window.setTimeout(function() { var win = [self DOMWindow]; - - win.document.write(_html); + + if (win) + win.document.write(_html); window.setTimeout(_loadCallback, 1); }, 0); @@ -372,7 +373,7 @@ CPWebViewScrollNative = 2; } - (void)setMainFrameURL:(CPString)URLString -{ +{ if (_mainFrameURL) [_backwardStack addObject:_mainFrameURL]; _mainFrameURL = URLString; @@ -389,9 +390,9 @@ CPWebViewScrollNative = 2; [_forwardStack addObject:_mainFrameURL]; _mainFrameURL = [_backwardStack lastObject]; [_backwardStack removeLastObject]; - + [self _loadMainFrameURL]; - + return YES; } return NO; @@ -405,9 +406,9 @@ CPWebViewScrollNative = 2; [_backwardStack addObject:_mainFrameURL]; _mainFrameURL = [_forwardStack lastObject]; [_forwardStack removeLastObject]; - + [self _loadMainFrameURL]; - + return YES; } return NO; @@ -630,7 +631,7 @@ CPWebViewScrollNative = 2; - (id)initWithCoder:(CPCoder)aCoder { self = [super initWithCoder:aCoder]; - + if (self) { // FIXME: encode/decode these? @@ -638,14 +639,14 @@ CPWebViewScrollNative = 2; _backwardStack = []; _forwardStack = []; _scrollMode = CPWebViewScrollNative; - + #if PLATFORM(DOM) [self _initDOMWithFrame:[self frame]]; #endif [self setBackgroundColor:[CPColor whiteColor]]; } - + return self; } From 494f39dd86cd1598cc3f2577aa7b419633f06d5e Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 12 Aug 2010 23:37:53 -0400 Subject: [PATCH 14/41] Closes #752. Removed some debug code which snuck in with the merge of fix-752-CPValueTransformerNameBindingOption. --- AppKit/CPKeyValueBinding.j | 3 --- 1 file changed, 3 deletions(-) diff --git a/AppKit/CPKeyValueBinding.j b/AppKit/CPKeyValueBinding.j index 89fd10c13..1ea547e5d 100644 --- a/AppKit/CPKeyValueBinding.j +++ b/AppKit/CPKeyValueBinding.j @@ -182,9 +182,6 @@ var CPBindingOperationAnd = 0, if (valueTransformerName) { - if (valueTransformerName === @"ESIsEmptyIndexSetValueTransformer") - debugger; - valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName]; if (!valueTransformer) From 0683b46239be4d1c904483c407f53d9c8dc9cc84 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 13 Aug 2010 14:18:25 -0400 Subject: [PATCH 15/41] Since issue #795 has not been decided on yet, make CPArrayControllerTest pass without those changes at this time. --- Tests/AppKit/CPArrayControllerTest.j | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Tests/AppKit/CPArrayControllerTest.j b/Tests/AppKit/CPArrayControllerTest.j index 2029c51ed..abdb8719c 100644 --- a/Tests/AppKit/CPArrayControllerTest.j +++ b/Tests/AppKit/CPArrayControllerTest.j @@ -12,7 +12,8 @@ [_contentArray addObject:[Person personWithName:@"Ross" age:30]]; [_contentArray addObject:[Person personWithName:@"Tom" age:15]]; - _arrayController = [[CPArrayController alloc] initWithContent:[self contentArray]]; + // Copy the array since we'll reuse the original array later. Also see issue #795. + _arrayController = [[CPArrayController alloc] initWithContent:[[self contentArray] copy]]; } - (void)testInitWithContent @@ -26,7 +27,8 @@ otherContent = [@"5", @"6"]; [[self arrayController] setContent:otherContent]; - [self assertFalse:otherContent === [[self arrayController] contentArray] message:@"array controller should copy it's content"]; + // This has not been decided on yet. See Issue #795. + // [self assertFalse:otherContent === [[self arrayController] contentArray] message:@"array controller should copy it's content"]; [self assert:otherContent equals:[[self arrayController] contentArray]]; [self assert:[_CPObservableArray class] equals:[[[self arrayController] arrangedObjects] class]]; } From bcb22c7e46853599eb37e290f6597cc45e49b239 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 13 Aug 2010 14:28:25 -0400 Subject: [PATCH 16/41] Remove debug output from CPArrayControllerTest. --- Tests/AppKit/CPArrayControllerTest.j | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/AppKit/CPArrayControllerTest.j b/Tests/AppKit/CPArrayControllerTest.j index abdb8719c..d311ccd56 100644 --- a/Tests/AppKit/CPArrayControllerTest.j +++ b/Tests/AppKit/CPArrayControllerTest.j @@ -94,7 +94,6 @@ arrayController = [[CPArrayController alloc] initWithContent:[self contentArray]]; [arrayController setPreservesSelection:YES]; - print([self contentArray]); // Remove from middle var selectionIndexes = [CPIndexSet indexSetWithIndex:1]; From 4c0057e66af505d10dc5c4b8263f3235e2f96d31 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 13 Aug 2010 14:37:26 -0400 Subject: [PATCH 17/41] Undoing this change since it is no longer necessary due to an alternative solution implemented by Ross Boucher. Revert "Merge commit 'c17a3533ecae63d479b285b23ac3a490ebe8bd3c'" This reverts commit 039f2ce449fe4767ffb5991b76732c7db5794fc4, reversing changes made to 494f39dd86cd1598cc3f2577aa7b419633f06d5e. --- AppKit/CPArrayController.j | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index 6843f79c6..b04f4e0f9 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -407,23 +407,16 @@ if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object]) { - var position; - if ([_sortDescriptors count] > 0) - position = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors]; - else - { - [_arrangedObjects addObject:object]; - position = [_arrangedObjects count] - 1; - } + var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors]; if (_selectsInsertedObjects) { - [self setSelectionIndex:position]; + [self setSelectionIndex:pos]; } else { [self willChangeValueForKey:@"selectionIndexes"]; - [_selectionIndexes shiftIndexesStartingAtIndex:position by:1]; + [_selectionIndexes shiftIndexesStartingAtIndex:pos by:1]; [self didChangeValueForKey:@"selectionIndexes"]; } } From 4eaf560ee62fe83ee73907aca7e231ed7cabfad3 Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Fri, 13 Aug 2010 15:34:28 -0700 Subject: [PATCH 18/41] Fixes two bugs in compareObjectsUsingDescriptors causing test to fail: extra semi-colon after while() and uninitized "result" variable. The former masked the latter when a single sort descriptor was used. --- Foundation/CPArray.j | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j index 14931c0bc..6ee14b6af 100755 --- a/Foundation/CPArray.j +++ b/Foundation/CPArray.j @@ -1378,12 +1378,12 @@ var selectorCompare = function selectorCompare(object1, object2, selector) // sort using sort descriptors var compareObjectsUsingDescriptors= function compareObjectsUsingDescriptors(lhs, rhs, descriptors) { - var result, + var result = CPOrderedSame, i = 0, n = [descriptors count]; - while (i < n && result == CPOrderedSame); - result = [descriptors[i++] compareObject:lhs withObject:rhs]; + while (i < n && result === CPOrderedSame) + result = [descriptors[i++] compareObject:lhs withObject:rhs]; return result; } From 6ce45d32dac642923c8d1b6f346ba01ad1bcb1dc Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Fri, 13 Aug 2010 15:40:33 -0700 Subject: [PATCH 19/41] Add comparison test for native sorting. --- Tests/Foundation/CPArrayPerformanceTest.j | 79 +++++++++++++++++------ 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/Tests/Foundation/CPArrayPerformanceTest.j b/Tests/Foundation/CPArrayPerformanceTest.j index f350e7ff5..e4d014aa5 100644 --- a/Tests/Foundation/CPArrayPerformanceTest.j +++ b/Tests/Foundation/CPArrayPerformanceTest.j @@ -3,20 +3,14 @@ @import @import +var ELEMENTS = 100, + REPEATS = 10; + @implementation CPArrayPerformanceTest : OJTestCase - (void)testSortUsingDescriptorsSpeed { - - var ELEMENTS = 1000, - REPEATS = 10, - array = []; - for (var i=0; i