* Headers/AppKit/NSKeyValueBinding.h,

* Source/externs.m: Additional binding names.
* Source/GSBindingHelpers.h,
* Source/NSKeyValueBinding.m: Additional helper methods.
* Source/NSObjectController.m: Use helper methods.
* Source/NSArrayController.m: Signal when the arranged objects
change.
* Source/NSTableColumn.m,
* Source/NSTableView.m: First attempt at support for content
binding.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@34923 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Fred Kiefer 2012-03-12 12:24:17 +00:00
parent df87a9f362
commit e8d2648aca
9 changed files with 282 additions and 83 deletions

View file

@ -1,3 +1,14 @@
2012-03-12 Fred Kiefer <FredKiefer@gmx.de>
* Headers/AppKit/NSKeyValueBinding.h,
* Source/externs.m: Additional binding names.
* Source/GSBindingHelpers.h,
* Source/NSKeyValueBinding.m: Additional helper methods.
* Source/NSObjectController.m: Use helper methods.
* Source/NSArrayController.m: Signal when the arranged objects change.
* Source/NSTableColumn.m,
* Source/NSTableView.m: First attempt at support for content binding.
2012-03-09 Eric Wasylishen <ewasylishen@gmail.com>
* Source/NSTableView.m:

View file

@ -103,6 +103,8 @@ APPKIT_EXPORT id NSNotApplicableMarker;
// Binding name constants
APPKIT_EXPORT NSString *NSAlignmentBinding;
APPKIT_EXPORT NSString *NSContentArrayBinding;
APPKIT_EXPORT NSString *NSContentBinding;
APPKIT_EXPORT NSString *NSContentObjectBinding;
APPKIT_EXPORT NSString *NSEditableBinding;
APPKIT_EXPORT NSString *NSEnabledBinding;
@ -113,6 +115,7 @@ APPKIT_EXPORT NSString *NSHiddenBinding;
APPKIT_EXPORT NSString *NSSelectedIndexBinding;
APPKIT_EXPORT NSString *NSSelectedObjectBinding;
APPKIT_EXPORT NSString *NSSelectedTagBinding;
APPKIT_EXPORT NSString *NSSelectionIndexesBinding;
APPKIT_EXPORT NSString *NSTextColorBinding;
APPKIT_EXPORT NSString *NSTitleBinding;
APPKIT_EXPORT NSString *NSToolTipBinding;

View file

@ -59,7 +59,10 @@
options: (NSDictionary *)options
fromObject: (id)source;
- (void) setValueFor: (NSString *)binding;
- (void) reverseSetValue: (id)value;
- (void) reverseSetValueFor: (NSString *)binding;
- (id) destinationValue;
- (id) sourceValueFor: (NSString *)binding;
/* Transforms the value with a value transformer, if specified and available,
* and takes care of any placeholders

View file

@ -31,6 +31,7 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSIndexSet.h>
#import <Foundation/NSKeyValueObserving.h>
#import <Foundation/NSPredicate.h>
#import <Foundation/NSSortDescriptor.h>
#import <Foundation/NSString.h>
@ -46,7 +47,7 @@
{
if (self == [NSArrayController class])
{
[self exposeBinding: @"contentArray"];
[self exposeBinding: NSContentArrayBinding];
}
}
@ -54,7 +55,7 @@
{
if ((self = [super initWithContent: content]) != nil)
{
_arranged_objects = [content copy];
[self rearrangeObjects];
[self setSelectsInsertedObjects: YES];
}
@ -124,6 +125,12 @@
return YES;
}
- (void) setContent: (id)content
{
[super setContent: content];
[self rearrangeObjects];
}
- (void) insert: (id)sender
{
id new = [self newObject];
@ -334,7 +341,9 @@
- (void) rearrangeObjects
{
[self willChangeValueForKey: @"arrangedObjects"];
ASSIGN(_arranged_objects, [self arrangeObjects: _content]);
[self didChangeValueForKey: @"arrangedObjects"];
}
- (void) setSortDescriptors: (NSArray*)desc
@ -360,15 +369,15 @@
- (void) insertObject: (id)obj
atArrangedObjectIndex: (NSUInteger)idx
{
// TODO
return;
// FIXME
[self addObject: obj];
}
- (void) insertObjects: (NSArray*)obj
atArrangedObjectIndexes: (NSIndexSet*)idx
{
// TODO
return;
// FIXME
[self addObjects: obj];
}
- (void) removeObjectAtArrangedObjectIndex: (NSUInteger)idx
@ -386,7 +395,7 @@ atArrangedObjectIndexes: (NSIndexSet*)idx
withKeyPath: (NSString *)keyPath
options: (NSDictionary *)options
{
if ([binding isEqual: @"contentArray"])
if ([binding isEqual: NSContentArrayBinding])
{
GSKeyValueBinding *kvb;
@ -409,6 +418,18 @@ atArrangedObjectIndexes: (NSIndexSet*)idx
}
}
- (Class) valueClassForBinding: (NSString *)binding
{
if ([binding isEqual: NSContentArrayBinding])
{
return [NSArray class];
}
else
{
return [super valueClassForBinding: binding];
}
}
- (void) encodeWithCoder: (NSCoder *)coder
{
[super encodeWithCoder: coder];

View file

@ -48,7 +48,7 @@
+ (void) exposeBinding: (NSString *)binding
{
[GSKeyValueBinding exposeBinding: binding forClass: [self class]];
[GSKeyValueBinding exposeBinding: binding forClass: [self class]];
}
- (NSArray *) exposedBindings
@ -76,10 +76,10 @@
return [NSString class];
}
- (void)bind: (NSString *)binding
toObject: (id)anObject
withKeyPath: (NSString *)keyPath
options: (NSDictionary *)options
- (void) bind: (NSString *)binding
toObject: (id)anObject
withKeyPath: (NSString *)keyPath
options: (NSDictionary *)options
{
if ((anObject == nil)
|| (keyPath == nil))
@ -319,7 +319,7 @@ void GSBindingInvokeAction(NSString *targetKey, NSString *argumentKey,
[super dealloc];
}
- (void) setValueFor: (NSString *)binding
- (id) destinationValue
{
id newValue;
id dest;
@ -329,26 +329,38 @@ void GSBindingInvokeAction(NSString *targetKey, NSString *argumentKey,
dest = [info objectForKey: NSObservedObjectKey];
keyPath = [info objectForKey: NSObservedKeyPathKey];
options = [info objectForKey: NSOptionsKey];
newValue = [dest valueForKeyPath: keyPath];
newValue = [self transformValue: newValue withOptions: options];
[src setValue: newValue forKey: binding];
return [self transformValue: newValue withOptions: options];
}
- (id) sourceValueFor: (NSString *)binding
{
id newValue;
NSDictionary *options;
options = [info objectForKey: NSOptionsKey];
newValue = [src valueForKeyPath: binding];
return [self reverseTransformValue: newValue withOptions: options];
}
- (void) setValueFor: (NSString *)binding
{
[src setValue: [self destinationValue] forKey: binding];
}
- (void) reverseSetValue: (id)value
{
NSString *keyPath;
id dest;
keyPath = [info objectForKey: NSObservedKeyPathKey];
dest = [info objectForKey: NSObservedObjectKey];
[dest setValue: value forKeyPath: keyPath];
}
- (void) reverseSetValueFor: (NSString *)binding
{
id newValue;
id dest;
NSString *keyPath;
NSDictionary *options;
dest = [info objectForKey: NSObservedObjectKey];
keyPath = [info objectForKey: NSObservedKeyPathKey];
options = [info objectForKey: NSOptionsKey];
newValue = [src valueForKeyPath: binding];
newValue = [self reverseTransformValue: newValue withOptions: options];
[dest setValue: newValue forKeyPath: keyPath];
[self reverseSetValue: [self sourceValueFor: binding]];
}
- (void) observeValueForKeyPath: (NSString *)keyPath
@ -508,7 +520,7 @@ void GSBindingInvokeAction(NSString *targetKey, NSString *argumentKey,
if (!objectTable)
return;
[bindingLock lock];
[bindingLock lock];
bindings = (NSDictionary *)NSMapGet(objectTable, (void *)src);
if (!bindings)
return;

View file

@ -201,19 +201,22 @@
- (void) setContent: (id)content
{
NSMutableArray *selection;
if (content != _content)
{
NSMutableArray *selection;
ASSIGN(_content, content);
if (content)
{
selection = [[NSMutableArray alloc] initWithObjects: &content count: 1];
ASSIGN(_content, content);
if (content)
{
selection = [[NSMutableArray alloc] initWithObjects: &content count: 1];
}
else
{
selection = [[NSMutableArray alloc] init];
}
ASSIGN(_selection, selection);
RELEASE(selection);
}
else
{
selection = [[NSMutableArray alloc] init];
}
ASSIGN(_selection, selection);
RELEASE(selection);
}
- (void)bind: (NSString *)binding
@ -221,7 +224,7 @@
withKeyPath: (NSString *)keyPath
options: (NSDictionary *)options
{
if ([binding isEqual:NSContentObjectBinding])
if ([binding isEqual: NSContentObjectBinding])
{
GSKeyValueBinding *kvb;
@ -290,16 +293,13 @@
- (void) addObject: (id)obj
{
NSDictionary * bindingInfo = [self infoForBinding: NSContentObjectBinding];
GSKeyValueBinding *theBinding;
[self setContent: obj];
if (bindingInfo)
{
// Change the relationship of the object that our content is bound to.
id masterObject = [bindingInfo objectForKey: NSObservedObjectKey];
NSString * keyPath = [bindingInfo objectForKey: NSObservedKeyPathKey];
[masterObject setValue: obj forKeyPath: keyPath];
}
theBinding = [GSKeyValueBinding getBinding: NSContentObjectBinding
forObject: self];
if (theBinding != nil)
[theBinding reverseSetValueFor: @"content"];
}
- (void) remove: (id)sender
@ -314,16 +314,13 @@
{
if (obj == [self content])
{
NSDictionary * bindingInfo = [self infoForBinding: NSContentObjectBinding];
GSKeyValueBinding *theBinding;
[self setContent: nil];
if (bindingInfo)
{
// Change the relationship of the object that our content is bound to.
id masterObject = [bindingInfo objectForKey: NSObservedObjectKey];
NSString * keyPath = [bindingInfo objectForKey: NSObservedKeyPathKey];
[masterObject setValue: nil forKeyPath: keyPath];
}
theBinding = [GSKeyValueBinding getBinding: NSContentObjectBinding
forObject: self];
if (theBinding != nil)
[theBinding reverseSetValueFor: @"content"];
}
}

View file

@ -63,12 +63,15 @@
*/
#import <Foundation/NSDictionary.h>
#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSNotification.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSSortDescriptor.h>
#import "AppKit/NSKeyValueBinding.h"
#import "AppKit/NSTableHeaderCell.h"
#import "AppKit/NSTableColumn.h"
#import "AppKit/NSTableView.h"
#import "GSBindingHelpers.h"
/**
<p>
@ -85,7 +88,11 @@
+ (void) initialize
{
if (self == [NSTableColumn class])
[self setVersion: 3];
{
[self setVersion: 3];
[self exposeBinding: NSValueBinding];
[self exposeBinding: NSEnabledBinding];
}
}
/*
@ -127,11 +134,14 @@
- (void) dealloc
{
RELEASE (_headerCell);
RELEASE (_headerToolTip);
RELEASE (_dataCell);
RELEASE (_sortDescriptorPrototype);
TEST_RELEASE (_identifier);
// Remove all key value bindings for this view.
[GSKeyValueBinding unbindAllForObject: self];
RELEASE(_headerCell);
RELEASE(_headerToolTip);
RELEASE(_dataCell);
RELEASE(_sortDescriptorPrototype);
TEST_RELEASE(_identifier);
[super dealloc];
}
@ -599,4 +609,37 @@ to YES. */
return self;
}
- (void) setValue: (id)anObject forKey: (NSString*)aKey
{
if ([aKey isEqual: NSValueBinding])
{
// FIXME
// Reload data
}
else if ([aKey isEqual: NSEnabledBinding])
{
// FIXME
}
else
{
[super setValue: anObject forKey: aKey];
}
}
- (id) valueForKey: (NSString*)aKey
{
if ([aKey isEqual: NSValueBinding])
{
return nil;
}
else if ([aKey isEqual: NSEnabledBinding])
{
// FIXME
return [NSNumber numberWithBool: YES];
}
else
{
return [super valueForKey: aKey];
}
}
@end

View file

@ -37,6 +37,7 @@
#import <Foundation/NSException.h>
#import <Foundation/NSFormatter.h>
#import <Foundation/NSIndexSet.h>
#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSNotification.h>
#import <Foundation/NSSet.h>
#import <Foundation/NSSortDescriptor.h>
@ -52,6 +53,7 @@
#import "AppKit/NSEvent.h"
#import "AppKit/NSImage.h"
#import "AppKit/NSGraphics.h"
#import "AppKit/NSKeyValueBinding.h"
#import "AppKit/NSScroller.h"
#import "AppKit/NSScrollView.h"
#import "AppKit/NSTableColumn.h"
@ -65,6 +67,7 @@
#import "AppKit/NSDragging.h"
#import "AppKit/NSCustomImageRep.h"
#import "GNUstepGUI/GSTheme.h"
#import "GSBindingHelpers.h"
#include <math.h>
static NSNotificationCenter *nc = nil;
@ -1992,6 +1995,9 @@ static void computeNewSelection
{
[self setVersion: currentVersion];
nc = [NSNotificationCenter defaultCenter];
// FIXME
[self exposeBinding: NSContentBinding];
[self exposeBinding: NSSelectionIndexesBinding];
}
}
@ -2296,22 +2302,31 @@ static void computeNewSelection
const SEL sel_a = @selector (numberOfRowsInTableView:);
const SEL sel_b = @selector (tableView:objectValueForTableColumn:row:);
const SEL sel_c = @selector(tableView:setObjectValue:forTableColumn:row:);
if (anObject && [anObject respondsToSelector: sel_a] == NO)
{
[NSException
raise: NSInternalInconsistencyException
format: @"Data Source doesn't respond to numberOfRowsInTableView:"];
GSKeyValueBinding *theBinding;
// If we have content binding the data source is used only
// like a delegate
theBinding = [GSKeyValueBinding getBinding: NSContentBinding
forObject: self];
if (theBinding == nil)
{
if (anObject && [anObject respondsToSelector: sel_a] == NO)
{
[NSException
raise: NSInternalInconsistencyException
format: @"Data Source doesn't respond to numberOfRowsInTableView:"];
}
if (anObject && [anObject respondsToSelector: sel_b] == NO)
{
/* This method isn't required.
[NSException raise: NSInternalInconsistencyException
format: @"Data Source doesn't respond to "
@"tableView:objectValueForTableColumn:row:"];
*/
}
}
if (anObject && [anObject respondsToSelector: sel_b] == NO)
{
/* This method isn't required.
[NSException raise: NSInternalInconsistencyException
format: @"Data Source doesn't respond to "
@"tableView:objectValueForTableColumn:row:"];
*/
}
_dataSource_editable = [anObject respondsToSelector: sel_c];
/* We do *not* retain the dataSource, it's like a delegate */
@ -2731,7 +2746,7 @@ byExtendingSelection: (BOOL)flag
* This is not just a speed up, it prevents us from sending
* a NSTableViewSelectionDidChangeNotification.
* This behaviour is required by the specifications */
if ([_selectedColumns isEqualToIndexSet: indexes])
if ([_selectedColumns isEqual: indexes])
{
if (!empty)
{
@ -2814,7 +2829,7 @@ byExtendingSelection: (BOOL)flag
* This is not just a speed up, it prevents us from sending
* a NSTableViewSelectionDidChangeNotification.
* This behaviour is required by the specifications */
if ([_selectedRows isEqualToIndexSet: indexes])
if ([_selectedRows isEqual: indexes])
{
if (!empty)
{
@ -3892,7 +3907,7 @@ if (currentRow >= 0 && currentRow < _numberOfRows) \
if (startedPeriodicEvents == YES)
[NSEvent stopPeriodicEvents];
if (![_selectedRows isEqualToIndexSet: oldSelectedRows])
if (![_selectedRows isEqual: oldSelectedRows])
{
[self _postSelectionDidChangeNotification];
}
@ -6576,8 +6591,16 @@ For a more detailed explanation, -setSortDescriptors:. */
row: (int) index
{
id result = nil;
GSKeyValueBinding *theBinding;
if ([_dataSource respondsToSelector:
theBinding = [GSKeyValueBinding getBinding: NSValueBinding
forObject: tb];
if (theBinding != nil)
{
return [(NSArray *)[theBinding sourceValueFor: NSValueBinding]
objectAtIndex: index];
}
else if ([_dataSource respondsToSelector:
@selector(tableView:objectValueForTableColumn:row:)])
{
result = [_dataSource tableView: self
@ -6608,7 +6631,26 @@ For a more detailed explanation, -setSortDescriptors:. */
*/
- (int) _numRows
{
return [_dataSource numberOfRowsInTableView:self];
GSKeyValueBinding *theBinding;
// If we have content binding the data source is used only
// like a delegate
theBinding = [GSKeyValueBinding getBinding: NSContentBinding
forObject: self];
if (theBinding != nil)
{
return [(NSArray *)[theBinding sourceValueFor: NSContentBinding] count];
}
else if ([_dataSource respondsToSelector:
@selector(numberOfRowsInTableView:)])
{
return [_dataSource numberOfRowsInTableView:self];
}
else
{
// FIXME
return 0;
}
}
- (BOOL) _isDraggingSource
@ -6766,4 +6808,68 @@ For a more detailed explanation, -setSortDescriptors:. */
_selectedColumn = -1;
}
- (void) setValue: (id)anObject forKey: (NSString*)aKey
{
if ([aKey isEqual: NSContentBinding])
{
// Reload data
[self reloadData];
NSLog(@"Setting TV content to %@", anObject);
}
else if ([aKey isEqual: NSSelectionIndexesBinding])
{
if (_selectingColumns)
{
if (nil == anObject)
{
[self _unselectAllColumns];
}
else
{
return [self selectColumnIndexes: anObject
byExtendingSelection: NO];
}
}
else
{
if (nil == anObject)
{
[self _unselectAllRows];
}
else
{
return [self selectRowIndexes: anObject
byExtendingSelection: NO];
}
}
}
else
{
[super setValue: anObject forKey: aKey];
}
}
- (id) valueForKey: (NSString*)aKey
{
if ([aKey isEqual: NSContentBinding])
{
return nil;
}
else if ([aKey isEqual: NSSelectionIndexesBinding])
{
if (_selectingColumns)
{
return [self selectedColumnIndexes];
}
else
{
return [self selectedRowIndexes];
}
}
else
{
return [super valueForKey: aKey];
}
}
@end

View file

@ -676,6 +676,8 @@ NSString *NSValueTransformerNameBindingOption = @"NSValueTransformerName";
NSString *NSValueTransformerBindingOption = @"NSValueTransformer";
NSString *NSAlignmentBinding = @"alignment";
NSString *NSContentArrayBinding = @"contentArray";
NSString *NSContentBinding = @"content";
NSString *NSContentObjectBinding = @"contentObject";
NSString *NSEditableBinding = @"editable";
NSString *NSEnabledBinding = @"enabled";
@ -686,6 +688,7 @@ NSString *NSHiddenBinding = @"hidden";
NSString *NSSelectedIndexBinding = @"selectedIndex";
NSString *NSSelectedObjectBinding = @"selectedObject";
NSString *NSSelectedTagBinding = @"selectedTag";
NSString *NSSelectionIndexesBinding = @"selectionIndexes";
NSString *NSTextColorBinding = @"textColor";
NSString *NSTitleBinding = @"title";
NSString *NSToolTipBinding = @"toolTip";