Merge branch 'master' of github.com:280north/cappuccino

This commit is contained in:
Francisco Ryan Tolmasky I
2010-09-27 06:49:18 +05:30
5 changed files with 147 additions and 44 deletions
+17 -15
View File
@@ -111,7 +111,7 @@
return self;
}
-(void)prepareContent
- (void)prepareContent
{
[self _setContentArray:[[self newObject]]];
}
@@ -148,7 +148,7 @@
- (void)setContent:(id)value
{
if(![value isKindOfClass:[CPArray class]])
if (![value isKindOfClass:[CPArray class]])
value = [value];
var oldSelectedObjects = nil,
@@ -178,7 +178,7 @@
// We need to be in control of when notifications fire.
_contentObject = value;
if(_clearsFilterPredicateOnInsertion)
if (_clearsFilterPredicateOnInsertion)
[self __setFilterPredicate:nil]; // Causes a _rearrangeObjects.
else
[self _rearrangeObjects];
@@ -342,7 +342,9 @@
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
{
[self _selectionWillChange]
[self __setSelectionIndexes:indexes];
[self _selectionDidChange];
}
/*
@@ -365,17 +367,17 @@
if (![indexes count])
{
if(_avoidsEmptySelection && [[self arrangedObjects] count])
if (_avoidsEmptySelection && [[self arrangedObjects] count])
indexes = [CPIndexSet indexSetWithIndex:0];
}
else
{
var objectsCount = [[self arrangedObjects] count];
// Remove out of bounds indexes.
[indexes removeIndexesInRange:CPMakeRange(objectsCount, [indexes lastIndex]+1)];
[indexes removeIndexesInRange:CPMakeRange(objectsCount, [indexes lastIndex] + 1)];
// When avoiding empty selection and the deleted selection was at the bottom, select the last item.
if(![indexes count] && _avoidsEmptySelection && objectsCount)
indexes = [CPIndexSet indexSetWithIndex:objectsCount-1];
if (![indexes count] && _avoidsEmptySelection && objectsCount)
indexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
}
if ([_selectionIndexes isEqualToIndexSet:indexes])
@@ -418,7 +420,7 @@
count = [objects count],
arrangedObjects = [self arrangedObjects];
for (var i=0; i<count; i++)
for (var i = 0; i < count; i++)
{
var index = [arrangedObjects indexOfObject:[objects objectAtIndex:i]];
@@ -437,7 +439,7 @@
return [[self selectionIndexes] firstIndex] > 0
}
-(void)selectPrevious:(id)sender
- (void)selectPrevious:(id)sender
{
var index = [[self selectionIndexes] firstIndex] - 1;
@@ -545,9 +547,9 @@
[self didChangeValueForKey:@"content"];
}
-(void)add:(id)sender
- (void)add:(id)sender
{
if(![self canAdd])
if (![self canAdd])
return;
[self insert:sender];
@@ -555,7 +557,7 @@
- (void)insert:(id)sender
{
if(![self canInsert])
if (![self canInsert])
return;
var newObject = [self automaticallyPreparesContent] ? [self newObject] : [self _defaultNewObject];
@@ -576,13 +578,13 @@
- (void)addObjects:(CPArray)objects
{
if(![self canAdd])
if (![self canAdd])
return;
var contentArray = [self contentArray],
count = [objects count];
for (var i=0; i<count; i++)
for (var i = 0; i < count; i++)
[contentArray addObject:[objects objectAtIndex:i]];
[self setContent:contentArray];
@@ -590,7 +592,7 @@
- (void)removeObjects:(CPArray)objects
{
if(![self canRemove])
if (![self canRemove])
return;
[self _removeObjects:objects];
+39 -17
View File
@@ -146,10 +146,39 @@ var CPBindingOperationAnd = 0,
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
newValue = [destination valueForKeyPath:keyPath];
newValue = [destination valueForKeyPath:keyPath],
isPlaceholder = CPIsControllerMarker(newValue);
if (isPlaceholder)
{
switch (newValue)
{
case CPMultipleValuesMarker:
newValue = [options objectForKey:CPMultipleValuesPlaceholderBindingOption] || @"Multiple Values";
break;
case CPNoSelectionMarker:
newValue = [options objectForKey:CPNoSelectionPlaceholderBindingOption] || @"No Selection";
break;
case CPNotApplicableMarker:
if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
[CPException raise:CPGenericException reason:@"can't transform non applicable key on: "+_source+" value: "+newValue];
newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
break;
}
}
else
{
// Only transform the value if the current value is not a placeholder
newValue = [self transformValue:newValue withOptions:options];
}
newValue = [self transformValue:newValue withOptions:options];
[_source setValue:newValue forKey:aBinding];
if ([_source respondsToSelector:@selector(_setCurrentValueIsPlaceholder:)])
[_source _setCurrentValueIsPlaceholder:isPlaceholder];
}
- (void)reverseSetValueFor:(CPString)aBinding
@@ -200,20 +229,9 @@ var CPBindingOperationAnd = 0,
if (valueTransformer)
aValue = [valueTransformer transformedValue:aValue];
switch (aValue)
{
case CPMultipleValuesMarker: return [options objectForKey:CPMultipleValuesPlaceholderBindingOption] || @"Multiple Values";
case CPNoSelectionMarker: return [options objectForKey:CPNoSelectionPlaceholderBindingOption] || @"No Selection";
case CPNotApplicableMarker: if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
[CPException raise:CPGenericException reason:@"can't transform non applicable key on: "+_source+" value: "+aValue];
return [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
case nil:
case undefined: return [options objectForKey:CPNullPlaceholderBindingOption] || nil;
}
if (aValue === undefined || aValue === nil)
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
return aValue;
}
@@ -248,7 +266,7 @@ var CPBindingOperationAnd = 0,
var exposedBindings = [],
theClass = [self class];
while(theClass)
while (theClass)
{
var temp = [CPKeyValueBinding exposedBindingsForClass:theClass];
@@ -379,7 +397,7 @@ var invokeAction = function invokeAction(/*CPString*/targetKey, /*CPString*/argu
var invocation = [CPInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]];
[invocation setSelector:selector];
var bindingName = argumentKey
var bindingName = argumentKey,
count = 1;
while (theBinding = [bindings objectForKey:bindingName])
@@ -447,3 +465,7 @@ CPValidatesImmediatelyBindingOption = @"CPValidatesImmediatelyBi
CPValueTransformerNameBindingOption = @"CPValueTransformerNameBindingOption";
CPValueTransformerBindingOption = @"CPValueTransformerBindingOption";
CPIsControllerMarker = function(/*id*/anObject)
{
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker;
}
+45 -9
View File
@@ -86,6 +86,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPColor _textFieldBackgroundColor;
id _placeholderString;
id _originalPlaceholderString;
BOOL _currentValueIsPlaceholder;
id _delegate;
@@ -279,7 +281,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
_isEditable = shouldBeEditable;
if(shouldBeEditable)
if (shouldBeEditable)
_isSelectable = YES;
// We only allow first responder status if the field is editable and enabled.
@@ -543,7 +545,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var element = [self _inputElement];
[self setObjectValue:element.value];
if ([self stringValue] !== element.value)
[self _setStringValue:element.value];
CPTextFieldInputResigning = YES;
element.blur();
@@ -695,8 +698,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)textDidBlur:(CPNotification)note
{
//this looks to prevent false propagation of notifications for other objects
if([note object] != self)
// this looks to prevent false propagation of notifications for other objects
if ([note object] != self)
return;
[[CPNotificationCenter defaultCenter] postNotification:note];
@@ -704,13 +707,22 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)textDidFocus:(CPNotification)note
{
//this looks to prevent false propagation of notifications for other objects
if([note object] != self)
// this looks to prevent false propagation of notifications for other objects
if ([note object] != self)
return;
[[CPNotificationCenter defaultCenter] postNotification:note];
}
- (void)sendAction:(SEL)anAction to:(id)anObject
{
// Don't reverse set our empty value
if (!_currentValueIsPlaceholder)
[self _reverseSetBinding];
[CPApp sendAction:anAction to:anObject from:self];
}
/*!
Returns the string the text field.
*/
@@ -757,7 +769,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
Sets a placeholder string for the receiver. The placeholder is displayed until editing begins,
and after editing ends, if the text field has an empty string value
*/
-(void)setPlaceholderString:(CPString)aStringValue
- (void)setPlaceholderString:(CPString)aStringValue
{
if (_placeholderString === aStringValue)
return;
@@ -780,6 +792,30 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return _placeholderString;
}
- (void)_setCurrentValueIsPlaceholder:(BOOL)isPlaceholder
{
if (isPlaceholder)
{
// Save the original placeholder value so we can restore it later
// Only do this if the placeholder is not already overridden because the bindings logic might call this method
// several times and we don't want the bindings placeholder to ever become the original placeholder
if (!_currentValueIsPlaceholder)
_originalPlaceholderString = [self placeholderString];
// Set the current string value as the current placeholder and clear the string value
[self setPlaceholderString:[self stringValue]];
[self setStringValue:@""];
}
else
{
// Restore the original placeholder, the actual textfield value is already correct
// because it was set using setValue:forKey:
[self setPlaceholderString:_originalPlaceholderString];
}
_currentValueIsPlaceholder = isPlaceholder;
}
/*!
Size to fit has two behavior, depending on if the receiver is an editable text field or not.
@@ -881,7 +917,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
[self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)];
[self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
}
}
@@ -1158,7 +1194,7 @@ var secureStringForString = function(aString)
if (!aString)
return "";
return Array(aString.length+1).join(CPSecureTextFieldCharacter);
return Array(aString.length + 1).join(CPSecureTextFieldCharacter);
}
+13
View File
@@ -245,6 +245,19 @@
[self assert:[CPIndexSet indexSetWithIndex:0] equals:observation.newValue message:"new selected index should be 0"];
}
- (void)testObservationDuringSetSelectionIndexes
{
var arrayController = [self arrayController],
newContent = [self setupObservationFixture];
var newSelection = [CPIndexSet indexSetWithIndex:2];
[arrayController setSelectionIndexes:newSelection];
[self assertNotNull:[arrayController selection] message:@"a selection was made, selection proxy should be defined"];
[self assert:2 equals:[observations count] message:@"exactly 2 change notifications should be sent for new selection indexes"];
[self assert:newSelection equals:[arrayController selectionIndexes] message:@"selection was not set properly"];
}
- (void)observeValueForKeyPath:keyPath
ofObject:anActivity
change:change
+33 -3
View File
@@ -39,7 +39,7 @@
[binder setCheese:@"banana"];
[self assertTrue:[self valueForKey:@"FOO"]==="banana" message:"Bound value should have been updated to banana, was "+FOO];
[self assertTrue:[self valueForKey:@"FOO"] === "banana" message:"Bound value should have been updated to banana, was " + FOO];
}
- (void)testBindOptions
@@ -164,7 +164,7 @@
[tableColumn bind:@"value" toObject:arrayController withKeyPath:@"arrangedObjects.valueA" options:nil];
// Reset these if they were read during initialization.
for(var i=0; i<[content count];i++)
for (var i = 0; i < [content count]; i++)
[content[i] setAccesses:0];
var testView = [DataViewTester new];
[tableColumn prepareDataView:testView forRow:0];
@@ -190,6 +190,29 @@
[self assert:'value' equals:testView.lastKey];
}
- (void)testTextField
{
var textField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[textField setPlaceholderString:@"cheese"];
content = [
[BindingTester testerWithCheese:@"yellow"],
[BindingTester testerWithCheese:@"green"]
];
arrayController = [[CPArrayController alloc] initWithContent:content];
[arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, 2)]];
var options = [CPDictionary dictionaryWithJSObject:{CPMultipleValuesPlaceholderBindingOption:@"Multiple Values"}];
[textField bind:@"value" toObject:arrayController withKeyPath:@"selection.cheese" options:options];
[self assert:@"Multiple Values" equals:[textField placeholderString]];
[arrayController setSelectionIndex:0];
[self assert:@"cheese" equals:[textField placeholderString]];
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)aContext
{
CPLog(@"here: "+aKeyPath+" value: "+[anObject valueForKey:aKeyPath]);
@@ -202,6 +225,13 @@
id cheese;
}
+ (id)testerWithCheese:(id)aCheese
{
var tester = [[self alloc] init];
[tester setCheese:aCheese];
return tester;
}
- (void)setCheese:(id)aCheese
{
cheese = aCheese;
@@ -242,7 +272,7 @@
CPNumber accesses @accessors;
}
+ (AccessCounter) counterWithValueA:aValue valueB:anotherValue
+ (AccessCounter)counterWithValueA:aValue valueB:anotherValue
{
r = [self new];
[r setValueA:aValue];