mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-11-15 03:03:50 +00:00
Added support for CPNullPlaceholderBindingOption and made some clean up of code
This commit is contained in:
1 parent
ef30e21506
commit
e5f4a7c39a
2 files changed
+339
-29
No files matched your search
+139
-29
@@ -778,7 +778,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
aBinding == CPSelectedObjectBinding ||
|
||||
aBinding == CPSelectedTagBinding ||
|
||||
aBinding == CPSelectedValueBinding)
|
||||
return [_CPPopUpButtonSelectionBinder class];
|
||||
{
|
||||
var capitalizedBinding = aBinding.charAt(0).toUpperCase() + aBinding.substr(1);
|
||||
|
||||
return [CPClassFromString(@"_CPPopUpButton" + capitalizedBinding + "Binder") class];
|
||||
}
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
@@ -788,21 +792,52 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
return [self valueForKeyPath:@"itemArray.title"];
|
||||
}
|
||||
|
||||
- (id)_valueOrNilIfCPNull:(id)aValue
|
||||
{
|
||||
if (aValue === [CPNull null])
|
||||
return nil;
|
||||
|
||||
return aValue;
|
||||
}
|
||||
|
||||
- (id)_getNullPlaceholderFromOptions:(CPDictionary)someOptions
|
||||
{
|
||||
var placeholder = [someOptions objectForKey:CPNullPlaceholderBindingOption] || @"";
|
||||
|
||||
if (placeholder === [CPNull null])
|
||||
placeholder = @"";
|
||||
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
- (void)_setContentValues:(CPArray)aValue
|
||||
{
|
||||
var count = [aValue count];
|
||||
var infoDictionary = [self infoForBinding:CPContentValuesBinding],
|
||||
options = [infoDictionary objectForKey:CPOptionsKey],
|
||||
insertNullValue = [options objectForKey:CPInsertsNullPlaceholderBindingOption],
|
||||
insertNull = [insertNullValue boolValue] ? 1 : 0,
|
||||
nullPlaceHolderValue = [self _getNullPlaceholderFromOptions:options],
|
||||
count = [aValue count];
|
||||
|
||||
if (count != [self numberOfItems])
|
||||
if (count + insertNull != [self numberOfItems])
|
||||
{
|
||||
[self removeAllItems];
|
||||
|
||||
if (insertNull)
|
||||
[self addItemWithTitle:nullPlaceHolderValue];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
[self addItemWithTitle:[aValue objectAtIndex:i]];
|
||||
[self addItemWithTitle:[self _valueOrNilIfCPNull:[aValue objectAtIndex:i]]];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (insertNull)
|
||||
[[self itemAtIndex:0] setTitle:nullPlaceHolderValue];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
[[self itemAtIndex:i] setTitle:[aValue objectAtIndex:i]];
|
||||
[[self itemAtIndex:i + insertNull] setTitle:[self _valueOrNilIfCPNull:[aValue objectAtIndex:i]]];
|
||||
}
|
||||
|
||||
[self synchronizeTitleAndSelectedItem];
|
||||
}
|
||||
|
||||
@@ -813,11 +848,22 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
|
||||
- (void)_setContent:(CPArray)aValue
|
||||
{
|
||||
var count = [aValue count];
|
||||
var infoDictionary = [self infoForBinding:CPContentBinding],
|
||||
options = [infoDictionary objectForKey:CPOptionsKey],
|
||||
insertNullValue = [options objectForKey:CPInsertsNullPlaceholderBindingOption],
|
||||
insertNull = [insertNullValue boolValue] ? 1 : 0,
|
||||
count = [aValue count];
|
||||
|
||||
if (count != [self numberOfItems])
|
||||
if (count + insertNull != [self numberOfItems])
|
||||
{
|
||||
[self removeAllItems];
|
||||
|
||||
if (insertNull)
|
||||
{
|
||||
var item = [[CPMenuItem alloc] initWithTitle:[self _getNullPlaceholderFromOptions:options] action:NULL keyEquivalent:nil];
|
||||
[self addItem:item];
|
||||
}
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var item = [[CPMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:nil];
|
||||
@@ -828,13 +874,18 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < count; i++)
|
||||
[[self itemAtIndex:i] setRepresentedObject:[aValue objectAtIndex:i]];
|
||||
{
|
||||
[[self itemAtIndex:i + insertNull] setRepresentedObject:[aValue objectAtIndex:i]];
|
||||
}
|
||||
}
|
||||
|
||||
if (![self infoForBinding:CPContentValuesBinding])
|
||||
{
|
||||
if (insertNull)
|
||||
[[self itemAtIndex:0] setTitle:[self _getNullPlaceholderFromOptions:options]];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
[[self itemAtIndex:i] setTitle:[[aValue objectAtIndex:i] description]];
|
||||
[[self itemAtIndex:i + insertNull] setTitle:[[aValue objectAtIndex:i] description]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -872,33 +923,92 @@ var binderForObject = {},
|
||||
[binder reverseSetValueFor:[binder binding]];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPSelectedIndexBinding)
|
||||
[_source selectItemAtIndex:aValue];
|
||||
else if (aBinding == CPSelectedObjectBinding)
|
||||
[_source selectItemAtIndex:[_source indexOfItemWithRepresentedObject:aValue]];
|
||||
else if (aBinding == CPSelectedTagBinding)
|
||||
[_source selectItemWithTag:aValue];
|
||||
else if (aBinding == CPSelectedValueBinding)
|
||||
[_source selectItemWithTitle:aValue];
|
||||
}
|
||||
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
{
|
||||
[self setValue:aValue forBinding:aBinding];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPPopUpButtonSelectedIndexBinder : _CPPopUpButtonSelectionBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source selectItemAtIndex:aValue];
|
||||
}
|
||||
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPSelectedIndexBinding)
|
||||
return [_source indexOfSelectedItem];
|
||||
else if (aBinding == CPSelectedObjectBinding)
|
||||
return [[_source selectedItem] representedObject];
|
||||
else if (aBinding == CPSelectedTagBinding)
|
||||
return [[_source selectedItem] tag];
|
||||
else if (aBinding == CPSelectedValueBinding)
|
||||
return [_source titleOfSelectedItem];
|
||||
return [_source indexOfSelectedItem];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPPopUpButtonSelectedObjectBinder : _CPPopUpButtonSelectionBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
var index = [_source indexOfItemWithRepresentedObject:aValue];
|
||||
|
||||
// If the content binding has the option CPNullPlaceholderBindingOption and the object to select is nil, select the first item (i.e., the placeholder).
|
||||
// Other cases to consider:
|
||||
// 1. no binding:
|
||||
// 1.1 there's no item with a represented object matching the object to select.
|
||||
// 1.2 the object to select is nil/CPNull
|
||||
// 2. there's a binding:
|
||||
// 2.1 there's a CPNullPlaceholderBindingOption:
|
||||
// 2.1.1 there's no item with a represented object matching the object to select?
|
||||
// 2.1.2 the object to select is nil/CPNull
|
||||
// 2.2 there's no CPNullPlaceholderBindingOption:
|
||||
// 2.2.1 there's no item with a represented object matching the object to select?
|
||||
// 2.2.2 the object to select is nil/CPNull
|
||||
// More cases? Behaviour that depends on array controller settings?
|
||||
|
||||
if ([[[[CPBinder infoForBinding:CPContentBinding forObject:_source] objectForKey:CPOptionsKey] objectForKey:CPInsertsNullPlaceholderBindingOption] boolValue] && index === CPNotFound)
|
||||
index = 0;
|
||||
|
||||
[_source selectItemAtIndex:index];
|
||||
}
|
||||
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
return [[_source selectedItem] representedObject];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPPopUpButtonSelectedTagBinder : _CPPopUpButtonSelectionBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source selectItemWithTag:aValue];
|
||||
}
|
||||
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
return [[_source selectedItem] tag];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPPopUpButtonSelectedValueBinder : _CPPopUpButtonSelectionBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source selectItemWithTitle:aValue];
|
||||
}
|
||||
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
return [_source titleOfSelectedItem];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
|
||||
@import <AppKit/CPKeyValueBinding.j>
|
||||
@import <AppKit/CPPopUpButton.j>
|
||||
@import <AppKit/CPApplication.j>
|
||||
|
||||
@implementation CPPopUpButtonTest : OJTestCase
|
||||
{
|
||||
CPPopUpButton button @accessors;
|
||||
id objects @accessors;
|
||||
}
|
||||
|
||||
- (void)setUp
|
||||
@@ -202,4 +204,202 @@
|
||||
[self assert:2 equals:[[self button] indexOfItemWithTitle:@"three"]];
|
||||
}
|
||||
|
||||
- (void)testSimpleStringBindingArrayController
|
||||
{
|
||||
var arrayController = [[CPArrayController alloc] init],
|
||||
objectController = [[CPObjectController alloc] init],
|
||||
testObject = [CPMutableDictionary dictionary],
|
||||
martin = @"Martin",
|
||||
malte = @"Malte",
|
||||
johan = @"Johan",
|
||||
menuObjects = [martin, malte, johan];
|
||||
|
||||
[testObject setObject:@"I'm a testObject" forKey:@"Who am I"];
|
||||
[arrayController setContent:menuObjects];
|
||||
[objectController setContent:testObject];
|
||||
|
||||
[button bind:CPContentBinding toObject:arrayController withKeyPath:@"arrangedObjects" options:nil];
|
||||
[button bind:CPSelectedObjectBinding toObject:objectController withKeyPath:@"selection.xxx" options:nil];
|
||||
|
||||
[[self button] selectItemWithTitle:@"Martin"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self]; // This has to be done to trigger the reverse set of the binding
|
||||
[self assert:martin equals:[testObject objectForKey:@"xxx"]];
|
||||
[[self button] selectItemWithTitle:@"Malte"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self];
|
||||
[self assert:malte equals:[testObject objectForKey:@"xxx"]];
|
||||
[[self button] selectItemWithTitle:@"Johan"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self];
|
||||
[self assert:johan equals:[testObject objectForKey:@"xxx"]];
|
||||
|
||||
[testObject setObject:martin forKey:@"xxx"];
|
||||
[self assert:0 equals:[[self button] indexOfSelectedItem]];
|
||||
[testObject setObject:malte forKey:@"xxx"];
|
||||
[self assert:1 equals:[[self button] indexOfSelectedItem]];
|
||||
[testObject setObject:johan forKey:@"xxx"];
|
||||
[self assert:2 equals:[[self button] indexOfSelectedItem]];
|
||||
}
|
||||
|
||||
- (void)testSimpleStringBindingNullPlaceholderOption
|
||||
{
|
||||
var arrayController = [[CPArrayController alloc] init],
|
||||
objectController = [[CPObjectController alloc] init],
|
||||
testObject = [CPMutableDictionary dictionary],
|
||||
martin = @"Martin",
|
||||
malte = @"Malte",
|
||||
johan = @"Johan",
|
||||
menuObjects = [martin, malte, johan],
|
||||
insertsNullPlaceholderOption = [CPDictionary dictionaryWithObjects:[YES, @"Null Placeholder"] forKeys:[CPInsertsNullPlaceholderBindingOption, CPNullPlaceholderBindingOption]];
|
||||
|
||||
[testObject setObject:@"I'm a testObject" forKey:@"Who am I"];
|
||||
[arrayController setContent:menuObjects];
|
||||
[objectController setContent:testObject];
|
||||
|
||||
[button bind:CPContentBinding toObject:arrayController withKeyPath:@"arrangedObjects" options:insertsNullPlaceholderOption];
|
||||
[button bind:CPSelectedObjectBinding toObject:objectController withKeyPath:@"selection.xxx" options:insertsNullPlaceholderOption];
|
||||
|
||||
[[self button] selectItemWithTitle:@"Martin"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self]; // This has to be done to trigger the reverse set of the binding
|
||||
[self assert:martin equals:[testObject objectForKey:@"xxx"]];
|
||||
[[self button] selectItemWithTitle:@"Malte"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self];
|
||||
[self assert:malte equals:[testObject objectForKey:@"xxx"]];
|
||||
[[self button] selectItemWithTitle:@"Johan"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self];
|
||||
[self assert:johan equals:[testObject objectForKey:@"xxx"]];
|
||||
|
||||
[[self button] selectItemWithTitle:@"Null Placeholder"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self];
|
||||
[self assertNull:[testObject objectForKey:@"xxx"]];
|
||||
|
||||
[testObject setObject:martin forKey:@"xxx"];
|
||||
[self assert:1 equals:[[self button] indexOfSelectedItem]];
|
||||
[testObject setObject:malte forKey:@"xxx"];
|
||||
[self assert:2 equals:[[self button] indexOfSelectedItem]];
|
||||
[testObject setObject:johan forKey:@"xxx"];
|
||||
[self assert:3 equals:[[self button] indexOfSelectedItem]];
|
||||
|
||||
[testObject removeObjectForKey:@"xxx"];
|
||||
[self assert:0 equals:[[self button] indexOfSelectedItem]];
|
||||
}
|
||||
|
||||
- (void)testSimpleObjectBindingArrayController
|
||||
{
|
||||
var arrayController = [[CPArrayController alloc] init],
|
||||
objectController = [[CPObjectController alloc] init],
|
||||
testObject = [CPMutableDictionary dictionary],
|
||||
martin = [CPDictionary dictionaryWithJSObject:{@"name": @"Martin"}],
|
||||
malte = [CPDictionary dictionaryWithJSObject:{@"name": @"Malte"}],
|
||||
johan = [CPDictionary dictionaryWithJSObject:{@"name": @"Johan"}],
|
||||
menuObjects = [martin, malte, johan];
|
||||
|
||||
[testObject setObject:@"I'm a testObject" forKey:@"Who am I"];
|
||||
[arrayController setContent:menuObjects];
|
||||
[objectController setContent:testObject];
|
||||
|
||||
[button bind:CPContentBinding toObject:arrayController withKeyPath:@"arrangedObjects" options:nil];
|
||||
[button bind:CPContentValuesBinding toObject:arrayController withKeyPath:@"arrangedObjects.name" options:nil];
|
||||
[button bind:CPSelectedObjectBinding toObject:objectController withKeyPath:@"selection.xxx" options:nil];
|
||||
|
||||
[[self button] selectItemWithTitle:@"Martin"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self]; // This has to be done to trigger the reverse set of the binding
|
||||
[self assert:martin equals:[testObject objectForKey:@"xxx"]];
|
||||
[[self button] selectItemWithTitle:@"Malte"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self];
|
||||
[self assert:malte equals:[testObject objectForKey:@"xxx"]];
|
||||
[[self button] selectItemWithTitle:@"Johan"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self];
|
||||
[self assert:johan equals:[testObject objectForKey:@"xxx"]];
|
||||
|
||||
[testObject setObject:martin forKey:@"xxx"];
|
||||
[self assert:0 equals:[[self button] indexOfSelectedItem]];
|
||||
[testObject setObject:malte forKey:@"xxx"];
|
||||
[self assert:1 equals:[[self button] indexOfSelectedItem]];
|
||||
[testObject setObject:johan forKey:@"xxx"];
|
||||
[self assert:2 equals:[[self button] indexOfSelectedItem]];
|
||||
}
|
||||
|
||||
- (void)testObjectBindingNullPlaceholderOption
|
||||
{
|
||||
var arrayController = [[CPArrayController alloc] init],
|
||||
martin = [CPDictionary dictionaryWithJSObject:{@"name": @"Martin"}],
|
||||
malte = [CPDictionary dictionaryWithJSObject:{@"name": @"Malte"}],
|
||||
johan = [CPDictionary dictionaryWithJSObject:{@"name": @"Johan"}],
|
||||
menuObjects = [martin, malte, johan],
|
||||
insertsNullPlaceholderOption = [CPDictionary dictionaryWithObjects:[YES, @"Null Placeholder"] forKeys:[CPInsertsNullPlaceholderBindingOption, CPNullPlaceholderBindingOption]];
|
||||
|
||||
[arrayController setContent:menuObjects];
|
||||
[button bind:CPContentBinding toObject:arrayController withKeyPath:@"arrangedObjects" options:insertsNullPlaceholderOption];
|
||||
[button bind:CPContentValuesBinding toObject:arrayController withKeyPath:@"arrangedObjects.name" options:insertsNullPlaceholderOption];
|
||||
|
||||
[self assert:4 equals:[[self button] numberOfItems]];
|
||||
[self assert:0 equals:[[self button] indexOfItemWithTitle:@"Null Placeholder"]];
|
||||
[self assert:1 equals:[[self button] indexOfItemWithTitle:@"Martin"]];
|
||||
[self assert:2 equals:[[self button] indexOfItemWithTitle:@"Malte"]];
|
||||
[self assert:3 equals:[[self button] indexOfItemWithTitle:@"Johan"]];
|
||||
|
||||
[button unbind:CPContentValuesBinding];
|
||||
[button unbind:CPContentBinding];
|
||||
[button bind:CPContentValuesBinding toObject: arrayController withKeyPath:@"arrangedObjects.name" options:nil];
|
||||
[button bind:CPContentBinding toObject:arrayController withKeyPath:@"arrangedObjects" options:nil];
|
||||
|
||||
[self assert:3 equals:[[self button] numberOfItems]];
|
||||
[self assert:0 equals:[[self button] indexOfItemWithTitle:@"Martin"]];
|
||||
[self assert:1 equals:[[self button] indexOfItemWithTitle:@"Malte"]];
|
||||
[self assert:2 equals:[[self button] indexOfItemWithTitle:@"Johan"]];
|
||||
}
|
||||
|
||||
- (void)testSelectedObjectBindingArrayController
|
||||
{
|
||||
var arrayController = [[CPArrayController alloc] init],
|
||||
objectController = [[CPObjectController alloc] init],
|
||||
testObject = [CPMutableDictionary dictionary],
|
||||
martin = [CPDictionary dictionaryWithJSObject:{@"name": @"Martin"}],
|
||||
malte = [CPDictionary dictionaryWithJSObject:{@"name": @"Malte"}],
|
||||
johan = [CPDictionary dictionaryWithJSObject:{@"name": @"Johan"}],
|
||||
menuObjects = [martin, malte, johan],
|
||||
insertsNullPlaceholderOption = [CPDictionary dictionaryWithObjects:[YES, @"Null Placeholder"] forKeys:[CPInsertsNullPlaceholderBindingOption, CPNullPlaceholderBindingOption]];
|
||||
|
||||
[testObject setObject:@"I'm a testObject" forKey:@"Who am I"];
|
||||
[arrayController setContent:menuObjects];
|
||||
[objectController setContent:testObject];
|
||||
|
||||
[button bind:CPContentBinding toObject:arrayController withKeyPath:@"arrangedObjects" options:insertsNullPlaceholderOption];
|
||||
[button bind:CPContentValuesBinding toObject:arrayController withKeyPath:@"arrangedObjects.name" options:insertsNullPlaceholderOption];
|
||||
[button bind:CPSelectedObjectBinding toObject:objectController withKeyPath:@"selection.xxx" options:nil];
|
||||
|
||||
[self assert:4 equals:[[self button] numberOfItems]];
|
||||
[self assert:0 equals:[[self button] indexOfItemWithTitle:@"Null Placeholder"]];
|
||||
[self assert:1 equals:[[self button] indexOfItemWithTitle:@"Martin"]];
|
||||
[self assert:2 equals:[[self button] indexOfItemWithTitle:@"Malte"]];
|
||||
[self assert:3 equals:[[self button] indexOfItemWithTitle:@"Johan"]];
|
||||
|
||||
[[self button] selectItemWithTitle:@"Martin"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self]; // This has to be done to trigger the reverse set of the binding
|
||||
[self assert:martin equals:[testObject objectForKey:@"xxx"]];
|
||||
[[self button] selectItemWithTitle:@"Malte"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self];
|
||||
[self assert:malte equals:[testObject objectForKey:@"xxx"]];
|
||||
[[self button] selectItemWithTitle:@"Johan"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self];
|
||||
[self assert:johan equals:[testObject objectForKey:@"xxx"]];
|
||||
|
||||
[[self button] selectItemWithTitle:@"Null Placeholder"];
|
||||
[[self button] sendAction:@selector(actionTest:) to:self];
|
||||
[self assertNull:[testObject objectForKey:@"xxx"]];
|
||||
|
||||
[testObject setObject:martin forKey:@"xxx"];
|
||||
[self assert:1 equals:[[self button] indexOfSelectedItem]];
|
||||
[testObject setObject:malte forKey:@"xxx"];
|
||||
[self assert:2 equals:[[self button] indexOfSelectedItem]];
|
||||
[testObject setObject:johan forKey:@"xxx"];
|
||||
[self assert:3 equals:[[self button] indexOfSelectedItem]];
|
||||
|
||||
[testObject removeObjectForKey:@"xxx"];
|
||||
[self assert:0 equals:[[self button] indexOfSelectedItem]];
|
||||
}
|
||||
|
||||
- (void)actionTest:(id)sender
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in new issue
Block a user