Added support for CPTableView content binding, generally used with view-based tables.

Grouped the 3 ways to set objectValue on a dataview (content binding, column value binding or regular delegate method) under one main method: _setObjectValueFortableColumn:row:ForView:
    Also fixed a bug where the dragging rows didn't have their bindings applied. Columns and row dragging are now using the previous method for setting data view objectValue.

    Updated TableBindings example: table with content binding vs. columns with value binding.
This commit is contained in:
cacaodev
2012-05-16 15:57:26 +02:00
parent d18e77329f
commit db8f2fdf75
4 changed files with 994 additions and 3047 deletions
+64 -12
View File
@@ -239,6 +239,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
BOOL _disableAutomaticResizing @accessors(property=disableAutomaticResizing);
BOOL _lastColumnShouldSnap;
BOOL _implementsCustomDrawRow;
BOOL _contentBindingExpicitelySet;
CPTableColumn _draggedColumn;
CPArray _differedColumnDataToRemove;
@@ -305,6 +306,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_retargetedDropOperation = nil;
_dragOperationDefaultMask = nil;
_destinationDragStyle = CPTableViewDraggingDestinationFeedbackStyleRegular;
_contentBindingExpicitelySet = NO;
[self setBackgroundColor:[CPColor whiteColor]];
[self _init];
@@ -344,6 +346,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_exposedRows = [CPIndexSet indexSet];
_exposedColumns = [CPIndexSet indexSet];
_cachedDataViews = { };
_cachedRowHeights = [];
_groupRows = [CPIndexSet indexSet];
@@ -2823,11 +2826,8 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
var dataView = [self _newDataViewForRow:row tableColumn:tableColumn];
[dataView setFrame:[self frameOfDataViewAtColumn:columnIndex row:row]];
[dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]];
// If the column uses content bindings, allow them to override the objectValueForTableColumn.
[tableColumn _prepareDataView:dataView forRow:row];
[self _setObjectValueForTableColumn:tableColumn row:row forView:dataView];
[view addSubview:dataView];
row = [theDraggedRows indexGreaterThanIndex:row];
@@ -2868,7 +2868,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
dataViewFrame.origin.y = ( _CGRectGetMinY(dataViewFrame) - _CGRectGetMinY([self exposedRect]) ) + 23.0;
[dataView setFrame:dataViewFrame];
[dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]];
[self _setObjectValueForTableColumn:tableColumn row:row forView:dataView];
[dragView addSubview:dataView];
row = [_exposedRows indexGreaterThanIndex:row];
@@ -3267,11 +3267,8 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
isTextField = [dataView isKindOfClass:[CPTextField class]];
[dataView setFrame:[self frameOfDataViewAtColumn:column row:row]];
[dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]];
// This gives the table column an opportunity to apply its bindings.
// It will override the value set above if there is a binding.
[tableColumn _prepareDataView:dataView forRow:row];
[self _setObjectValueForTableColumn:tableColumn row:row forView:dataView];
if (isColumnSelected || [self isRowSelected:row])
[dataView setThemeState:CPThemeStateSelectedDataView];
@@ -3329,6 +3326,30 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
}
}
- (void)_setObjectValueForTableColumn:(CPTableColumn)aTableColumn row:(CPInteger)aRow forView:(CPView)aDataView
{
if (_implementedDataSourceMethods & CPTableViewDataSource_tableView_objectValueForTableColumn_row_)
[aDataView setObjectValue:[self _objectValueForTableColumn:aTableColumn row:aRow]];
// This gives the table column an opportunity to apply its bindings.
// It will override the value set above if there is a binding.
if (_contentBindingExpicitelySet)
[self _prepareContentBindedDataView:aDataView forRow:aRow];
else
// For both cell-based and view-based
[aTableColumn _prepareDataView:aDataView forRow:aRow];
}
- (void)_prepareContentBindedDataView:(CPView)dataView forRow:(CPInteger)aRow
{
var binder = [CPTableContentBinder getBinding:@"content" forObject:self],
content = [binder content],
rowContent = [content objectAtIndex:aRow];
[dataView setObjectValue:rowContent];
}
/*!
@ignore
*/
@@ -4707,6 +4728,14 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
@implementation CPTableView (Bindings)
+ (id)_binderClassForBinding:(CPString)aBinding
{
if (aBinding == @"content")
return [CPTableContentBinder class];
return [super _binderClassForBinding:aBinding];
}
/*!
@ignore
*/
@@ -4724,7 +4753,10 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
- (void)_establishBindingsIfUnbound:(id)destination
{
if ([[self infoForBinding:@"content"] objectForKey:CPObservedObjectKey] !== destination)
[self bind:@"content" toObject:destination withKeyPath:@"arrangedObjects" options:nil];
{
[super bind:@"content" toObject:destination withKeyPath:@"arrangedObjects" options:nil];
_contentBindingExpicitelySet = NO;
}
if ([[self infoForBinding:@"selectionIndexes"] objectForKey:CPObservedObjectKey] !== destination)
[self bind:@"selectionIndexes" toObject:destination withKeyPath:@"selectionIndexes" options:nil];
@@ -4732,9 +4764,29 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
//[self bind:@"sortDescriptors" toObject:destination withKeyPath:@"sortDescriptors" options:nil];
}
- (void)setContent:(CPArray)content
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
{
[self reloadData];
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
if (aBinding == @"content")
_contentBindingExpicitelySet = YES;
}
@end
@implementation CPTableContentBinder : CPBinder
{
id _content @accessors(property=content);
}
- (void)setValueFor:(id)aBinding
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey];
_content = [destination valueForKey:keyPath];
[_source reloadData];
}
@end
@@ -12,10 +12,11 @@
@implementation AppController : CPObject
{
CPWindow theWindow; //this "outlet" is connected automatically by the Cib
CPArrayController arrayController;
CPTextField from;
CPTextField to;
@outlet CPTextField locationField;
@outlet CPTextField lengthField;
@outlet CPPopUpButton KeyPathPopup;
CPArray rows @accessors;
}
@@ -46,11 +47,22 @@
[self setRows:theRows];
}
- (void)test:(id)sender
- (IBAction)updateOrReloadContent:(id)sender
{
var range = CPMakeRange([from intValue], [to intValue]);
var indexes = [CPIndexSet indexSetWithIndexesInRange:range];
[[rows objectsAtIndexes:indexes] setValue:@"b" forKey:@"colTwo"];
var range = CPMakeRange([locationField intValue], [lengthField intValue]),
indexes = [CPIndexSet indexSetWithIndexesInRange:range],
keyPath = [KeyPathPopup titleOfSelectedItem];
var value = String.fromCharCode(97 + Math.round(Math.random() * 26));
if ([sender tag] == 1000)
[[rows objectsAtIndexes:indexes] setValue:value forKey:keyPath];
else
{
var rowsCopy = [rows copy];
[[rowsCopy objectsAtIndexes:indexes] setValue:value forKey:keyPath];
[self setRows:rowsCopy];
}
}
@end
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff