From e346fd856b5e1fd688dfe2da81fac07ed16978db Mon Sep 17 00:00:00 2001 From: Christopher Lloyd Date: Mon, 14 May 2007 13:15:31 +0000 Subject: [PATCH] + Johannes Fortmann's patch: - table view editing - fine-grained bindings for table columns - NSArray objectsAtIndexes: - some fixes for KVO + Rolf Jansen's NSSortDescriptor initWithCoder/encodeWithCoder + Rolf Jansen's NSCell/NSButtonCell controlSize patch --- AppKit/NSButtonCell.m | 13 ++- AppKit/NSCell.m | 10 +- AppKit/NSController/NSArrayController.h | 4 + AppKit/NSController/NSArrayController.m | 35 +++--- .../NSArrayControllerSelectionProxy.m | 1 - AppKit/NSKeyValueBinding/NSBinder.h | 15 +-- AppKit/NSKeyValueBinding/NSBinder.m | 9 +- AppKit/NSKeyValueBinding/NSKVOBinder.m | 6 +- .../NSObject+BindingSupport.h | 2 + .../NSObject+BindingSupport.m | 5 + .../NSKeyValueBinding/NSTableColumnBinder.h | 11 +- .../NSKeyValueBinding/NSTableColumnBinder.m | 108 ++++++++++++++---- AppKit/NSTableView.m | 28 +++-- AppKit/nib.subproj/NSIBObjectData.m | 4 +- Foundation/NSArray/NSArray.m | 39 ++++--- .../NSKeyValueCoding/NSKVCMutableArray.m | 6 +- .../NSKeyValueCoding/NSKeyValueCoding.h | 1 + .../NSKeyValueCoding/NSKeyValueCoding.m | 12 ++ .../NSKeyValueCoding/NSKeyValueObserving.h | 10 +- Foundation/NSSortDescriptor.m | 47 ++++++-- 20 files changed, 273 insertions(+), 93 deletions(-) diff --git a/AppKit/NSButtonCell.m b/AppKit/NSButtonCell.m index 2d5d1200..0bd1dc22 100755 --- a/AppKit/NSButtonCell.m +++ b/AppKit/NSButtonCell.m @@ -579,12 +579,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI NSGraphicsStyle should probably do this adjustment too */ if((_bezelStyle==NSRoundedBezelStyle) && (_highlightsBy&NSPushInCellMask) && (_highlightsBy&NSChangeGrayCellMask) && (_showsStateBy==NSNoCellMask)){ - if(![self isKindOfClass:[NSPopUpButtonCell class]]){ - frame.size.height-=10; - frame.origin.y+=[control isFlipped]?-5:5; - frame.size.width-=6; - frame.origin.x+=3; - } + if (![self isKindOfClass:[NSPopUpButtonCell class]] && _controlSize <= NSSmallControlSize) + { + frame.size.width -= 10 - _controlSize*2; + frame.size.height -= 10 - _controlSize*2; + frame.origin.x += 5 - _controlSize; + frame.origin.y += [control isFlipped] ? _controlSize*2 - 3 : 7 - _controlSize*2; + } } if(_bezelStyle==NSDisclosureBezelStyle){ diff --git a/AppKit/NSCell.m b/AppKit/NSCell.m index bcd72763..36f658a7 100755 --- a/AppKit/NSCell.m +++ b/AppKit/NSCell.m @@ -75,9 +75,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI check=[keyed decodeObjectForKey:@"NSSupport"]; if([check isKindOfClass:[NSFont class]]) _font=[check retain]; - - if(_font==nil) - _font=[[NSFont userFontOfSize:0] retain]; // ? + + _controlSize=(flags2&0xE0000)>>17; + if (_font==nil) + _font=[[NSFont userFontOfSize:13 - _controlSize*2] retain]; } else { _state=[coder decodeIntForKey:@"NSCell state"]; @@ -551,6 +552,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI - (void)setControlSize:(NSControlSize)size { _controlSize = size; + [_font release]; + _font = [[NSFont userFontOfSize:13 - _controlSize*2] retain]; + [(NSControl *)[self controlView] updateCell:self]; } -(void)takeObjectValueFrom:sender { diff --git a/AppKit/NSController/NSArrayController.h b/AppKit/NSController/NSArrayController.h index bc5bd0c9..2343dc29 100644 --- a/AppKit/NSController/NSArrayController.h +++ b/AppKit/NSController/NSArrayController.h @@ -28,6 +28,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI id filterPredicate; id _selection; id arrangedObjects; + } -(NSArray *)sortDescriptors; @@ -86,4 +87,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI //-(NSArray *)arrangeObjects:(NSArray *)objects; //-(void)rearrangeObjects; +// private +-(void)_selectionMayHaveChanged; + @end diff --git a/AppKit/NSController/NSArrayController.m b/AppKit/NSController/NSArrayController.m index bc434374..264ab655 100644 --- a/AppKit/NSController/NSArrayController.m +++ b/AppKit/NSController/NSArrayController.m @@ -15,6 +15,11 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #import #import +@interface NSArrayController(forwardRefs) +-(void)_selectionMayHaveChanged; +- (void)setArrangedObjects:(id)value; +@end + @implementation NSArrayController +(void)initialize @@ -23,7 +28,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI triggerChangeNotificationsForDependentKey:@"selection"]; } --(id)initWithCoder:(id)coder +-(id)initWithCoder:(NSCoder*)coder { self=[super init]; if(self) @@ -38,8 +43,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI id declaredKeys=[coder decodeObjectForKey:@"NSDeclaredKeys"]; } - // FIX: cocotron nib loading seems not to retain top-level objects. _dirtiest_ possible hack: retain - return [self retain]; + return self; } -(void)dealloc @@ -51,24 +55,21 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI } -(id)awakeFromNib +{ + [self _selectionMayHaveChanged]; +} + +-(void)_selectionMayHaveChanged { [self willChangeValueForKey:@"selection"]; _selection=[[NSArrayControllerSelectionProxy alloc] initWithArrayController:self]; - [self didChangeValueForKey:@"selection"]; + [self didChangeValueForKey:@"selection"]; } - (id)contentArray { return [[contentArray retain] autorelease]; } -- (void)setArrangedObjects:(id)value { - if (arrangedObjects != value) - { - [arrangedObjects release]; - arrangedObjects = [[NSArray alloc] initWithArray:value]; - } -} - - (void)setContentArray:(id)value { if (contentArray != value) { [contentArray release]; @@ -82,6 +83,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI } } +- (void)setArrangedObjects:(id)value { + if (arrangedObjects != value) + { + [arrangedObjects release]; + arrangedObjects = [value copy]; + } +} + -(id)arrangedObjects { return arrangedObjects; @@ -195,6 +204,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI [self setSelectionIndexes:idxs]; } - } + @end diff --git a/AppKit/NSController/NSArrayControllerSelectionProxy.m b/AppKit/NSController/NSArrayControllerSelectionProxy.m index 25863b03..e93c0215 100644 --- a/AppKit/NSController/NSArrayControllerSelectionProxy.m +++ b/AppKit/NSController/NSArrayControllerSelectionProxy.m @@ -83,7 +83,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI -(void)setValue:(id)value forKey:(NSString *)key { - NSLog(@"setValue %@ forKey %@", value, key); [[controller selectedObjects] setValue:value forKey:key]; } diff --git a/AppKit/NSKeyValueBinding/NSBinder.h b/AppKit/NSKeyValueBinding/NSBinder.h index c026ec14..71206cbe 100644 --- a/AppKit/NSKeyValueBinding/NSBinder.h +++ b/AppKit/NSKeyValueBinding/NSBinder.h @@ -7,13 +7,14 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #import +@class NSString; @interface _NSBinder : NSObject { id source; id destination; - id keyPath; - id bindingPath; - id binding; + NSString* keyPath; + NSString* bindingPath; + NSString* binding; id options; } - (id)options; @@ -25,11 +26,11 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI - (id)destination; - (void)setDestination:(id)value; -- (id)keyPath; -- (void)setKeyPath:(id)value; +- (NSString*)keyPath; +- (void)setKeyPath:(NSString*)value; -- (id)binding; -- (void)setBinding:(id)value; +- (NSString*)binding; +- (void)setBinding:(NSString*)value; -(void)bind; -(void)unbind; diff --git a/AppKit/NSKeyValueBinding/NSBinder.m b/AppKit/NSKeyValueBinding/NSBinder.m index 4bc2ebfa..886f0a2a 100644 --- a/AppKit/NSKeyValueBinding/NSBinder.m +++ b/AppKit/NSKeyValueBinding/NSBinder.m @@ -7,6 +7,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #import "NSBinder.h" #import +#import @implementation _NSBinder @@ -35,22 +36,22 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI } } -- (id)keyPath { +- (NSString*)keyPath { return [[keyPath retain] autorelease]; } -- (void)setKeyPath:(id)value { +- (void)setKeyPath:(NSString*)value { if (keyPath != value) { [keyPath release]; keyPath = [value copy]; } } -- (id)binding { +- (NSString*)binding { return [[binding retain] autorelease]; } -- (void)setBinding:(id)value { +- (void)setBinding:(NSString*)value { if (binding != value) { [binding release]; binding = [value copy]; diff --git a/AppKit/NSKeyValueBinding/NSKVOBinder.m b/AppKit/NSKeyValueBinding/NSKVOBinder.m index ec87cdac..39b55fc3 100644 --- a/AppKit/NSKeyValueBinding/NSKVOBinder.m +++ b/AppKit/NSKeyValueBinding/NSKVOBinder.m @@ -15,7 +15,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI @implementation _NSKVOBinder -(void)startObservingChanges { - NSLog(@"binding between %@.%@ alias %@ and %@.%@ (%@)", [source className], binding, bindingPath, [destination className], keyPath, self); + //NSLog(@"binding between %@.%@ alias %@ and %@.%@ (%@)", [source className], binding, bindingPath, [destination className], keyPath, self); [source addObserver:self forKeyPath:bindingPath @@ -60,14 +60,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI if(object==source) { - NSLog(@"bind event from %@.%@ alias %@ to %@.%@ (%@)", [source className], binding, bindingPath, [destination className], keyPath, self); + //NSLog(@"bind event from %@.%@ alias %@ to %@.%@ (%@)", [source className], binding, bindingPath, [destination className], keyPath, self); [destination setValue:[change valueForKey:NSKeyValueChangeNewKey] forKeyPath:keyPath]; } else if(object==destination) { - NSLog(@"bind event from %@.%@ to %@.%@ alias %@ (%@)", [destination className], keyPath, [source className], binding, bindingPath, self); + //NSLog(@"bind event from %@.%@ to %@.%@ alias %@ (%@)", [destination className], keyPath, [source className], binding, bindingPath, self); [source setValue:[change valueForKey:NSKeyValueChangeNewKey] forKeyPath:bindingPath]; diff --git a/AppKit/NSKeyValueBinding/NSObject+BindingSupport.h b/AppKit/NSKeyValueBinding/NSObject+BindingSupport.h index 7cd9f70f..598079da 100644 --- a/AppKit/NSKeyValueBinding/NSObject+BindingSupport.h +++ b/AppKit/NSKeyValueBinding/NSObject+BindingSupport.h @@ -22,4 +22,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI -(id)_replacementKeyPathForBinding:(id)binding; -(void)_cleanupBinders; -(NSArray*)_allUsedBinders; +-(id)_binderForBinding:(id)binding create:(BOOL)create; +-(id)_binderForBinding:(id)binding; @end diff --git a/AppKit/NSKeyValueBinding/NSObject+BindingSupport.m b/AppKit/NSKeyValueBinding/NSObject+BindingSupport.m index a4eeea35..16b10051 100644 --- a/AppKit/NSKeyValueBinding/NSObject+BindingSupport.m +++ b/AppKit/NSKeyValueBinding/NSObject+BindingSupport.m @@ -20,6 +20,11 @@ NSMutableDictionary *bindersForObjects=nil; return [_NSKVOBinder class]; } +-(id)_binderForBinding:(id)binding; +{ + return [self _binderForBinding:binding create:NO]; +} + -(id)_binderForBinding:(id)binding create:(BOOL)create { if(!bindersForObjects) diff --git a/AppKit/NSKeyValueBinding/NSTableColumnBinder.h b/AppKit/NSKeyValueBinding/NSTableColumnBinder.h index fc068307..8dae50c2 100644 --- a/AppKit/NSKeyValueBinding/NSTableColumnBinder.h +++ b/AppKit/NSKeyValueBinding/NSTableColumnBinder.h @@ -7,15 +7,20 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #import "NSBinder.h" -@class NSArray; +@class NSMutableArray; @interface _NSTableColumnBinder : _NSBinder { - NSArray* rowValues; - id pathToArray; + NSMutableArray* rowValues; + NSString* arrayKeyPath; + NSString* valueKeyPath; } -(void)applyToCell:(id)cell inRow:(int)row; +-(void)applyFromCell:(id)cell inRow:(int)row; -(void)updateRowValues; +-(NSMutableArray*)rowValues; +-(BOOL)allowsEditingForRow:(int)row; +-(void)cacheArrayKeyPath; @end diff --git a/AppKit/NSKeyValueBinding/NSTableColumnBinder.m b/AppKit/NSKeyValueBinding/NSTableColumnBinder.m index a30228db..0a733bb5 100644 --- a/AppKit/NSKeyValueBinding/NSTableColumnBinder.m +++ b/AppKit/NSKeyValueBinding/NSTableColumnBinder.m @@ -14,10 +14,12 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #import #import #import +#import +#import @implementation _NSTableColumnBinder -- (NSArray *)rowValues +- (NSMutableArray *)rowValues { return [[rowValues retain] autorelease]; } @@ -34,32 +36,72 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI -(void)applyToCell:(id)cell inRow:(int)row { - [cell setValue:[rowValues objectAtIndex:row] forKey:bindingPath]; + if(!arrayKeyPath) + [self cacheArrayKeyPath]; + [cell setValue:[[rowValues objectAtIndex:row] valueForKey:valueKeyPath] forKey:bindingPath]; } +-(void)applyFromCell:(id)cell inRow:(int)row +{ + [[rowValues objectAtIndex:row] setValue:[cell valueForKeyPath:bindingPath] + forKeyPath:valueKeyPath]; +} +-(void)cacheArrayKeyPath +{ + // find content binding + id tableViewContentBinder=[[source tableView] _binderForBinding:@"content"]; + if(!tableViewContentBinder) + return; + + // this should be something like "arrangedObjects" + arrayKeyPath=[[tableViewContentBinder keyPath] copy]; + + if(![keyPath hasPrefix:arrayKeyPath]) + [NSException raise:NSInvalidArgumentException + format:@"content binding %@ of table view %@ doesn't fit value binding %@ on column %@", + arrayKeyPath, + [source tableView], + keyPath, + source]; + + // get rest of key path ("value" from "arrangedObjects.value") + valueKeyPath=[[keyPath substringFromIndex:[arrayKeyPath length]+1] retain]; +} + +-(BOOL)allowsEditingForRow:(int)row +{ + return YES; +} -(void)dealloc { + [arrayKeyPath release]; + [valueKeyPath release]; [self setRowValues:nil]; [super dealloc]; } -(void)startObservingChanges { - //NSLog(@"%@: observing path %@ on %@", [self className], keyPath, destination); NS_DURING - - //[destination addObserver:self forKeyPath:keyPath options:0 context:destination]; + [destination addObserver:self forKeyPath:arrayKeyPath options:0 context:destination]; + [rowValues addObserver:self + toObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [rowValues count])] + forKeyPath:valueKeyPath + options:0 + context:nil]; NS_HANDLER NS_ENDHANDLER - } -(void)stopObservingChanges { NS_DURING - // [destination removeObserver:self forKeyPath:keyPath]; + [destination removeObserver:self forKeyPath:arrayKeyPath]; + [rowValues removeObserver:self + fromObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [rowValues count])] + forKeyPath:valueKeyPath]; NS_HANDLER NS_ENDHANDLER } @@ -71,15 +113,15 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI - (void)observeValueForKeyPath:(NSString *)kp ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - [self stopObservingChanges]; - if(object==source) { - NSLog(@"bind event from %@.%@ alias %@ to %@.%@ (%@)", [source className], binding, bindingPath, [destination className], keyPath, self); - } + //NSLog(@"bind event from %@.%@ alias %@ to %@.%@ (%@)", [source className], binding, bindingPath, [destination className], keyPath, self); + } else if(context==destination) { - NSLog(@"bind event from %@.%@ to %@.%@ alias %@ (%@)", [destination className], keyPath, [source className], binding, bindingPath, self); + [self stopObservingChanges]; + + //NSLog(@"bind event from %@.%@ to %@.%@ alias %@ (%@)", [destination className], keyPath, [source className], binding, bindingPath, self); [self updateRowValues]; @@ -87,17 +129,45 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI [source reloadData]; if([source respondsToSelector:@selector(tableView)]) [[source tableView] reloadData]; + + [self startObservingChanges]; } - + else if(context==nil) + { + if([source respondsToSelector:@selector(reloadData)]) + [source reloadData]; + if([source respondsToSelector:@selector(tableView)]) + [[source tableView] reloadData]; + + if([destination respondsToSelector:@selector(_selectionMayHaveChanged)]) + [destination _selectionMayHaveChanged]; + + } +} + +-(void)finishBind +{ + [self cacheArrayKeyPath]; + + [self syncUp]; [self startObservingChanges]; } -(void)bind { - [self syncUp]; - [self startObservingChanges]; + [self cacheArrayKeyPath]; + + // At the time of binding, the binders for the table view may not yet be initialized. + // In that case, we cannot determine which part of our key path is the array and + // which is the value key. In that case, we defer the finishing steps. + if(!arrayKeyPath) + [self performSelector:@selector(finishBind) withObject:nil afterDelay:0.0]; + else + [self finishBind]; } + + -(void)unbind { [self stopObservingChanges]; @@ -110,20 +180,18 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI -(id)objectAtIndex:(unsigned)row { - return [rowValues objectAtIndex:row]; + return [[rowValues objectAtIndex:row] valueForKey:valueKeyPath]; } -(id)description { return [NSString stringWithFormat:@"%@ %@", [super description], [self rowValues]]; - } -(void)updateRowValues { - [self setRowValues:[destination valueForKeyPath:keyPath]]; + [self setRowValues:[destination valueForKeyPath:arrayKeyPath]]; } - @end @@ -154,7 +222,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI { [source performSelector:@selector(reloadData) withObject:nil - afterDelay:1.0]; + afterDelay:0.0]; [source reloadData]; } diff --git a/AppKit/NSTableView.m b/AppKit/NSTableView.m index c5e184a2..3bfe5d47 100755 --- a/AppKit/NSTableView.m +++ b/AppKit/NSTableView.m @@ -71,6 +71,7 @@ NSString *NSTableViewColumnDidResizeNotification=@"NSTableViewColumnDidResizeNot [_headerView setTableView:self]; _cornerView=[[keyed decodeObjectForKey:@"NSCornerView"] retain]; _tableColumns=[[NSMutableArray alloc] initWithArray:[keyed decodeObjectForKey:@"NSTableColumns"]]; + [_tableColumns makeObjectsPerformSelector:@selector(setTableView:) withObject:self]; _backgroundColor=[[keyed decodeObjectForKey:@"NSBackgroundColor"] retain]; _gridColor=[[keyed decodeObjectForKey:@"NSGridColor"] retain]; _rowHeight=[keyed decodeFloatForKey:@"NSRowHeight"]; @@ -501,11 +502,13 @@ NSString *NSTableViewColumnDidResizeNotification=@"NSTableViewColumnDidResizeNot // also.. i wonder if remove should use an isEqual method in NSTableColumn, or removeObjectIdenticalTo... -(void)addTableColumn:(NSTableColumn *)column { [_tableColumns addObject:column]; + [column setTableView:self]; [self reloadData]; [_headerView setNeedsDisplay:YES]; } -(void)removeTableColumn:(NSTableColumn *)column { + [column setTableView:nil]; [_tableColumns removeObject:column]; [self reloadData]; [_headerView setNeedsDisplay:YES]; @@ -538,9 +541,9 @@ NSString *NSTableViewColumnDidResizeNotification=@"NSTableViewColumnDidResizeNot if ([self delegateShouldEditTableColumn:editingColumn row:row] == NO) return; - if ([self dataSourceCanSetObjectValue] == NO) + if ([self dataSourceCanSetObjectValue] == NO && [[editingColumn _binderForBinding:@"value" create:NO] allowsEditingForRow:row] == NO) [NSException raise:NSInternalInconsistencyException - format:@"data source does not respond to tableView:setObjectValue:forTableColumn:row:"]; + format:@"data source does not respond to tableView:setObjectValue:forTableColumn:row: and binding is read-only"]; _editedColumn = column; _editedRow = row; @@ -552,6 +555,8 @@ NSString *NSTableViewColumnDidResizeNotification=@"NSTableViewColumnDidResizeNot [_editingCell setBordered:YES]; [(NSCell *)_editingCell setObjectValue:[self dataSourceObjectValueForTableColumn:editingColumn row:row]]; + [editingColumn prepareCell:_editingCell inRow:row]; + _currentEditor=[[self window] fieldEditor:YES forObject:self]; _currentEditor=[_editingCell setUpFieldEditorAttributes:_currentEditor]; [_currentEditor retain]; @@ -624,9 +629,7 @@ NSString *NSTableViewColumnDidResizeNotification=@"NSTableViewColumnDidResizeNot } -(void)selectRow:(int)row byExtendingSelection:(BOOL)extend { - NSLog(@"selectRow:%i extend:%i", row, extend); - - // selecting a row deselects all columns + // selecting a row deselects all columns [_selectedColumns removeAllObjects]; NSMutableIndexSet* selectedRowIndexes=[[[self selectedRowIndexes] mutableCopy] autorelease]; @@ -929,7 +932,16 @@ NSString *NSTableViewColumnDidResizeNotification=@"NSTableViewColumnDidResizeNot // avoid possible row synch issues _numberOfRows = [self numberOfRows]; if (_editedRow >= 0 && _editedRow < _numberOfRows) - [self dataSourceSetObjectValue:[_editingCell objectValue] forTableColumn:editedColumn row:_editedRow]; + { + if([self dataSourceCanSetObjectValue]) + { + [self dataSourceSetObjectValue:[_editingCell objectValue] forTableColumn:editedColumn row:_editedRow]; + } + else + { + [[editedColumn _binderForBinding:@"value" create:NO] applyFromCell:_editingCell inRow:_editedRow]; + } + } [self abortEditing]; @@ -1146,7 +1158,9 @@ NSString *NSTableViewColumnDidResizeNotification=@"NSTableViewColumnDidResizeNot } else if ([event clickCount] == 2) { // nb this logic was backwards previously - if ([self dataSourceCanSetObjectValue]) { + id binder=[[_tableColumns objectAtIndex:_clickedColumn] _binderForBinding:@"value" create:NO]; + if ([self dataSourceCanSetObjectValue] || + [binder allowsEditingForRow:_clickedRow]) { if (_clickedColumn != NSNotFound && _clickedRow != NSNotFound) [self editColumn:[self clickedColumn] row:_clickedRow withEvent:event select:YES]; } diff --git a/AppKit/nib.subproj/NSIBObjectData.m b/AppKit/nib.subproj/NSIBObjectData.m index 68618807..e4ca5873 100644 --- a/AppKit/nib.subproj/NSIBObjectData.m +++ b/AppKit/nib.subproj/NSIBObjectData.m @@ -11,6 +11,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #import #import #import +#import #import "NSNibKeyedUnarchiver.h" #import "NSCustomObject.h" #import @@ -113,7 +114,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI NS_DURING [[_connections objectAtIndex:i] establishConnection]; NS_HANDLER - // NSLog(@"Exception during -establishConnection %@",localException); + if(NSDebugEnabled) + NSLog(@"Exception during -establishConnection %@",localException); NS_ENDHANDLER } } diff --git a/Foundation/NSArray/NSArray.m b/Foundation/NSArray/NSArray.m index 1e08af2c..565d047a 100755 --- a/Foundation/NSArray/NSArray.m +++ b/Foundation/NSArray/NSArray.m @@ -212,19 +212,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI objects[i]=[self objectAtIndex:loc+i]; } --(NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { - unsigned i,count=[indexes count]; - unsigned buffer[count]; - id objects[count]; - - count=[indexes getIndexes:buffer maxCount:count inIndexRange:NULL]; -// getObjects:range: would make more sense - for(i=0;i[self count]) NSRaiseException(NSRangeException,self,_cmd,@"range %@ beyond count %d", @@ -451,6 +438,32 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI return result; } +#if 0 +// untested +-(NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + unsigned i,count=[indexes count]; + unsigned buffer[count]; + id objects[count]; + count=[indexes getIndexes:buffer maxCount:count inIndexRange:NULL]; +// getObjects:range: would make more sense + for(i=0;i -@class NSDictionary,NSArray; +#import +@class NSDictionary; FOUNDATION_EXPORT NSString *const NSKeyValueChangeKindKey; FOUNDATION_EXPORT NSString *const NSKeyValueChangeNewKey; @@ -34,6 +35,13 @@ typedef unsigned int NSKeyValueObservingOptions; -(void*)observationInfo; @end +@interface NSArray(KeyValueObserving) +-(void)addObserver:(NSObject *)observer toObjectsAtIndexes:(NSIndexSet *)indexes forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context; +-(void)removeObserver:(NSObject *)observer fromObjectsAtIndexes:(NSIndexSet *)indexes forKeyPath:(NSString *)keyPath; +-(void)addObserver:(id)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context; +-(void)removeObserver:(id)observer forKeyPath:(NSString*)keyPath; +@end + @protocol NSKeyValueObserver - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context; @end diff --git a/Foundation/NSSortDescriptor.m b/Foundation/NSSortDescriptor.m index d33581b7..b6ac1275 100644 --- a/Foundation/NSSortDescriptor.m +++ b/Foundation/NSSortDescriptor.m @@ -10,6 +10,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #import #import #import +#import +#import @implementation NSSortDescriptor @@ -29,15 +31,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI [super dealloc]; } --initWithCoder:(NSCoder *)coder { - NSUnimplementedMethod(); - return self; -} - --(void)encodeWithCoder:(NSCoder *)coder { - NSUnimplementedMethod(); -} - -copyWithZone:(NSZone *)zone { return [self retain]; } @@ -68,4 +61,40 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI return [[[isa alloc] initWithKey:_key ascending:!_ascending selector:_selector] autorelease]; } +// NSCoding protocol + +- (void)encodeWithCoder:(NSCoder *)coder { + if ([coder allowsKeyedCoding]) + { + [coder encodeObject:_key forKey:@"Key"]; + [coder encodeBool:_ascending forKey:@"Ascending"]; + [coder encodeObject:NSStringFromSelector(_selector) forKey: @"Selector"]; + } + else + { + [coder encodeObject:_key]; + [coder encodeValueOfObjCType:@encode(BOOL) at:&_ascending]; + [coder encodeObject:NSStringFromSelector(_selector)]; + } +} + +- (id)initWithCoder:(NSCoder *)coder { + if ([coder isKindOfClass:[NSKeyedUnarchiver class]]) + { + NSKeyedUnarchiver *keyed = (NSKeyedUnarchiver *)coder; + _key = [[keyed decodeObjectForKey:@"Key"] copy]; + _ascending = [keyed decodeBoolForKey:@"Ascending"]; + _selector = NSSelectorFromString([keyed decodeObjectForKey:@"Selector"]); + } + + else + { + _key = [[coder decodeObject] copy]; + [coder decodeValueOfObjCType:@encode(BOOL) at:&_ascending]; + _selector = NSSelectorFromString([coder decodeObject]); + } + + return self; +} + @end