diff --git a/ChangeLog b/ChangeLog index 943cab4e0..5294165cd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2024-08-18 Gregory John Casamento + + * Headers/AppKit/NSTreeController.h: Update header + * Headers/AppKit/NSTreeNode.h: Update header + * Source/GNUmakefile: Add new class + * Source/GSBindingHelpers.h: Add NSString category + * Source/GSControllerTreeProxy.[hm]: Proxy class + for NSTreeController, a subclass of NSTreeNode. + * Source/GSThemeDrawing.m: Optimize code a bit and + add changes for bindings. + * Source/GSXib5KeyedUnarchiver.m: Add support for new keys + on NSTreeController. + * Source/NSKeyValueBinding.m: Add new methods to + GSKeyValueBinding + * Source/NSOutlineView.m: Add support for bindings. + * Source/NSTreeController.m: Implement new methods. + * Source/NSTreeNode.m: Implement new methods + 2024-07-25 Gregory John Casamento * Headers/AppKit/NSBrowser.h: Add declarations for @@ -16,7 +34,7 @@ * Source/GNUmakefile: Add class to build * Source/NSMenuToolbarItem.m: Implementation of NSMenuToolbarItem. - + 2024-06-07 Gregory John Casamento * Headers/Additions/GNUstepGUI/GSTheme.h: Add new methods diff --git a/Headers/AppKit/NSKeyValueBinding.h b/Headers/AppKit/NSKeyValueBinding.h index 456335724..445867e06 100644 --- a/Headers/AppKit/NSKeyValueBinding.h +++ b/Headers/AppKit/NSKeyValueBinding.h @@ -126,6 +126,7 @@ APPKIT_EXPORT NSString *NSSelectedObjectBinding; APPKIT_EXPORT NSString *NSSelectedTagBinding; APPKIT_EXPORT NSString *NSSelectedValueBinding; APPKIT_EXPORT NSString *NSSelectionIndexesBinding; +APPKIT_EXPORT NSString *NSSelectionIndexPathsBinding; APPKIT_EXPORT NSString *NSSortDescriptorsBinding; APPKIT_EXPORT NSString *NSTextColorBinding; APPKIT_EXPORT NSString *NSTitleBinding; diff --git a/Headers/AppKit/NSOutlineView.h b/Headers/AppKit/NSOutlineView.h index 7dc6ec15f..fe0b1b966 100644 --- a/Headers/AppKit/NSOutlineView.h +++ b/Headers/AppKit/NSOutlineView.h @@ -44,7 +44,6 @@ APPKIT_EXPORT_CLASS NSMapTable *_itemDict; NSMutableArray *_items; NSMutableArray *_expandedItems; - NSMutableArray *_selectedItems; /* No longer in use */ NSMapTable *_levelOfItems; BOOL _autoResizesOutlineColumn; BOOL _indentationMarkerFollowsCell; diff --git a/Headers/AppKit/NSTreeController.h b/Headers/AppKit/NSTreeController.h index ccbd70378..e38166635 100644 --- a/Headers/AppKit/NSTreeController.h +++ b/Headers/AppKit/NSTreeController.h @@ -1,4 +1,4 @@ -/* +/* NSTreeController.h The tree controller class. @@ -7,7 +7,7 @@ Author: Gregory Casamento Date: 2012 - + This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or @@ -22,10 +22,10 @@ You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. - If not, see or write to the - Free Software Foundation, 51 Franklin Street, Fifth Floor, + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ +*/ #ifndef _GNUstep_H_NSTreeController #define _GNUstep_H_NSTreeController @@ -34,6 +34,7 @@ #if OS_API_VERSION(MAC_OS_X_VERSION_10_4, GS_API_LATEST) #import +#import @class NSString; @class NSArray; @@ -47,61 +48,306 @@ APPKIT_EXPORT_CLASS NSString *_countKeyPath; NSString *_leafKeyPath; NSArray *_sortDescriptors; + NSTreeNode *_arranged_objects; + NSMutableArray *_selection_index_paths; + BOOL _alwaysUsesMultipleValuesMarker; BOOL _avoidsEmptySelection; BOOL _preservesSelection; BOOL _selectsInsertedObjects; + BOOL _canAddChild; + BOOL _canInsert; + BOOL _canInsertChild; } -- (BOOL) addSelectionIndexPaths: (NSArray*)indexPaths; +/** + * Adds the objects in the indexPaths array to the current selection. + */ +- (BOOL) addSelectionIndexPaths: (NSArray *)indexPaths; + +/** + * BOOL that indicates if the controller returns the multiple values marker when + * multiple objects have been selected. + */ - (BOOL) alwaysUsesMultipleValuesMarker; + +/** + * If YES, requires the content array to maintain a selection. + */ - (BOOL) avoidsEmptySelection; -- (BOOL) canAddChid; + +/** + * If YES, a child can be added. + */ +- (BOOL) canAddChild; + +/** + * If YES, an object can be inserted. + */ - (BOOL) canInsert; + +/** + * If YES, a child can be inserted. + */ - (BOOL) canInsertChild; -- (BOOL) preservesSelection; + +/** + * If YES, then preserve the current selection when the content changes. + */ +- (BOOL) preservesSelection; + +/** + * If YES, then when an object is inserted it is added to the selection. + */ - (BOOL) selectsInsertedObjects; -- (BOOL) setSelectionIndexPath: (NSIndexPath*)indexPath; -- (BOOL) setSelectionIndexPaths: (NSArray*)indexPaths; -- (id) arrangedObjects; -- (id) content; -- (NSArray*) selectedObjects; -- (NSIndexPath*) selectionIndexPath; -- (NSArray*) selectionIndexPaths; -- (NSArray*) sortDescriptors; -- (NSString*) childrenKeyPath; -- (NSString*) countKeyPath; -- (NSString*) leafKeyPath; -- (void) addChild: (id)sender; -- (void) add: (id)sender; -- (void) insertChild: (id)sender; -- (void) insertObject: (id)object atArrangedObjectIndexPath: (NSIndexPath*)indexPath; -- (void) insertObjects: (NSArray*)objects atArrangedObjectIndexPaths: (NSArray*)indexPaths; -- (void) insert: (id)sender; + +/** + * Makes indexPath the current selection. + */ +- (BOOL) setSelectionIndexPath: (NSIndexPath *)indexPath; + +/** + * Makes the array indexPaths the current selections. + */ +- (BOOL) setSelectionIndexPaths: (NSArray *)indexPaths; + +/** + * All objects managed by this tree controller. + */ +- (NSTreeNode *) arrangedObjects; + +/** + * An NSArray containing all selected objects. + */ +- (NSArray *) selectedObjects; + +/** + * The index path of the first selected object. + */ +- (NSIndexPath *) selectionIndexPath; + +/** + * An array containing all of the currently selected objects. + */ +- (NSArray *) selectionIndexPaths; + +/** + * An array containing sort descriptors used to arrange content. + */ +- (NSArray *) sortDescriptors; + +/** + * Key path for children of the node. This key must be key value + * compliant. + */ +- (NSString *) childrenKeyPath; + +/** + * Key value path for the flag which gives the count for the children + * of this node. The path indicated here must be key-value compliant. + * If count is enabled, then add:, addChild:, remove:, removeChild: + * and insert: are disabled. This key path is option since it can + * be determined by the array of children retuned by the + * childKeyPath. The mode the tree controller is in when this is + * not specified is called "object" mode. + */ +- (NSString *) countKeyPath; + +/** + * Key value path for the flag which determins that this is a leaf. + * The path indicated here must be key-value compliant. This + * key path is optional as it can be determined by the children + * returned by the childrenKeyPath. + */ +- (NSString *) leafKeyPath; + +/** + * Adds a child to the current selection using the newObject method. + * If the tree controller is in "object" mode, then newObject is called + * to add a new node. + */ +- (IBAction) addChild: (id)sender; + +/** + * Adds a new objeect to the tree usin the newObject method. + * If the tree controller is in "object" mode, then newObject is called + * to add a new node. + */ +- (IBAction) add: (id)sender; + +/** + * Inserts a child using the newObject method. This method + * will fail if canInsertChild returns NO. + * If the tree controller is in "object" mode, then newObject is called + * to add a new node. + */ +- (IBAction) insertChild: (id)sender; + +/** + * Inserts and object using the newObject method at the specified indexPath. + * If the tree controller is in "object" mode, then newObject is called + * to add a new node. + */ +- (void) insertObject: (id)object atArrangedObjectIndexPath: (NSIndexPath *)indexPath; + +/** + * Inserts objects into arranged objects at the specified indexPaths. These arrays are + * expected to be parallel and have the same number of objects. + * This method will only function if the tree controller is in + * "object" mode. + */ +- (void) insertObjects: (NSArray *)objects atArrangedObjectIndexPaths: (NSArray *)indexPaths; + +/** + * Insert an object created by newObject into arranged objects. + * This method will only function if the tree controller is in + * "object" mode. + */ +- (void) insertObject: (id)object atArrangedObjectIndexPath: (NSIndexPath *)indexPath; + +/** + * Inserts objects into arranged objects at the specified indexPaths. These arrays are + * expected to be parallel and have the same number of objects. + * This method will only function if the tree controller is in + * "object" mode. + */ +- (void) insertObjects: (NSArray *)objects atArrangedObjectIndexPaths: (NSArray *)indexPaths; + +/** + * Insert an object created by newObject into arranged objects. + * This method will only function if the tree controller is in + * "object" mode. + */ +- (IBAction) insert: (id)sender; + +/** + * Causes the controller to re-sort and rearrange the objects. This method + * should be called if anything has been done that affects the list of objects + * in the controller. + */ - (void) rearrangeObjects; -- (void) removeObjectAtArrangedObjectIndexPath: (NSIndexPath*)indexPath; -- (void) removeObjectsAtArrangedObjectIndexPaths: (NSArray*)indexPaths; -- (void) removeSelectionIndexPaths: (NSArray*)indexPaths; -- (void) remove: (id)sender; + +/** + * Removes object at the specified indexPath. + * This method will only function if the tree controller is in + * "object" mode. + */ +- (void) removeObjectAtArrangedObjectIndexPath: (NSIndexPath *)indexPath; + +/** + * Removes objects at the specified indexPaths. + */ +- (void) removeObjectsAtArrangedObjectIndexPaths: (NSArray *)indexPaths; + +/** + * Removes selection of objects at the specified indexPaths. + */ +- (void) removeSelectionIndexPaths: (NSArray *)indexPaths; + +/** + * Remove the currently selected object + */ +- (void) removeObjectAtArrangedObjectIndexPath: (NSIndexPath *)indexPath; + +/** + * Removes objects at the specified indexPaths. + */ +- (void) removeObjectsAtArrangedObjectIndexPaths: (NSArray *)indexPaths; + +/** + * Removes selection of objects at the specified indexPaths. + */ +- (void) removeSelectionIndexPaths: (NSArray *)indexPaths; + +/** + * Remove the currently selected object. This method will only + * function if the tree controller is in "object" mode. + */ +- (IBAction) remove: (id)sender; + +/** + * Sets the flag to always use multiple values marker. + */ - (void) setAlwaysUsesMultipleValuesMarker: (BOOL)flag; + +/** + * Sets the flag to avoid empty selection. + */ - (void) setAvoidsEmptySelection: (BOOL)flag; -- (void) setChildrenKeyPath: (NSString*)path; -- (void) setContent: (id)content; -- (void) setCountKeyPath: (NSString*)path; -- (void) setLeafPathKey: (NSString*)key; + +/** + * Sets the children key path. This needs to be key-value compliant. + */ +- (void) setChildrenKeyPath: (NSString *)path; + +/** + * Sets the count key path. This needs to be key-value compliant. + * Setting this key path will disable add:, addChild:, remove:, + * removeChild:, and insert: methods. If this is not specified, + * the tree controller is in "object" mode. + */ +- (void) setCountKeyPath: (NSString *)path; + +/** + * Sets leaf key path. This value needs to be key-value compliant. + */ +- (void) setLeafKeyPath: (NSString *)key; + +/** + * Sets the preserves selection flag. + */ - (void) setPreservesSelection: (BOOL)flag; + +/** + * Sets the flag that determines if objects inserted are automatically + * selected. + */ - (void) setSelectsInsertedObjects: (BOOL)flag; -- (void) setSortDescriptors: (NSArray*)descriptors; + +/** + * Sets the array of sort descriptors used when building arrangedObjects. + */ +- (void) setSortDescriptors: (NSArray *)descriptors; #if OS_API_VERSION(MAC_OS_X_VERSION_10_5, GS_API_LATEST) -- (NSString*) childrenKeyPathForNode: (NSTreeNode*)node; -- (NSString*) countKeyPathForNode: (NSTreeNode*)node; -- (NSString*) leafKeyPathForNode: (NSTreeNode*)node; -- (void) moveNode: (NSTreeNode*)node toIndexPath: (NSIndexPath*)indexPath; -- (void) moveNodes: (NSArray*)nodes toIndexPath: (NSIndexPath*)startingIndexPath; -- (NSArray*) selectedNodes; -#endif +/** + * children key path for the given NSTreeNode. + */ +- (NSString *) childrenKeyPathForNode: (NSTreeNode *)node; + +/** + * count key path for the given NSTreeNode. + */ +- (NSString *) countKeyPathForNode: (NSTreeNode *)node; + +/** + * leaf key path for the given NSTreeNode. + */ +- (NSString *) leafKeyPathForNode: (NSTreeNode *)node; + +/** + * Moves node to given indexPath + */ +- (void) moveNode: (NSTreeNode *)node toIndexPath: (NSIndexPath *)indexPath; + +/** + * Move nodes to position at startingIndexPath + */ +- (void) moveNodes: (NSArray *)nodes toIndexPath: (NSIndexPath *)startingIndexPath; + +/** + * Set the descriptors by which the content of this tree controller + * is sorted. + */ +- (void) setSortDescriptors: (NSArray *)descriptors; + +/** + * Array containing all selected nodes + */ +- (NSArray *) selectedNodes; +#endif // 10_5 + @end -#endif +#endif // if OS_API_VERSION... #endif /* _GNUstep_H_NSTreeController */ diff --git a/Headers/AppKit/NSTreeNode.h b/Headers/AppKit/NSTreeNode.h index 5fdce914d..4f57f685c 100644 --- a/Headers/AppKit/NSTreeNode.h +++ b/Headers/AppKit/NSTreeNode.h @@ -26,6 +26,7 @@ Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + #ifndef _GNUstep_H_NSTreeNode #define _GNUstep_H_NSTreeNode diff --git a/Source/GNUmakefile b/Source/GNUmakefile index f6ae04d33..d184a5f2a 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -304,6 +304,7 @@ NSWindowController.m \ NSWorkspace.m \ GSAnimator.m \ GSAutocompleteWindow.m \ +GSControllerTreeProxy.m \ GSDisplayServer.m \ GSHelpManagerPanel.m \ GSInfoPanel.m \ diff --git a/Source/GSBindingHelpers.h b/Source/GSBindingHelpers.h index 47bdb0f66..7d74001ad 100644 --- a/Source/GSBindingHelpers.h +++ b/Source/GSBindingHelpers.h @@ -64,6 +64,7 @@ - (void) reverseSetValueFor: (NSString *)binding; - (id) destinationValue; - (id) sourceValueFor: (NSString *)binding; +- (id) observedObject; /* Transforms the value with a value transformer, if specified and available, * and takes care of any placeholders diff --git a/Source/GSControllerTreeProxy.h b/Source/GSControllerTreeProxy.h new file mode 100644 index 000000000..a6632f5a8 --- /dev/null +++ b/Source/GSControllerTreeProxy.h @@ -0,0 +1,59 @@ +/* Definition of class GSControllerTreeProxy + Copyright (C) 2024 Free Software Foundation, Inc. + + By: Gregory John Casamento + Date: 24-06-2024 + + This file is part of the GNUstep Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110 USA. +*/ + +#ifndef _GSControllerTreeProxy_h_GNUSTEP_GUI_INCLUDE +#define _GSControllerTreeProxy_h_GNUSTEP_GUI_INCLUDE + +#import "AppKit/NSTreeNode.h" + +@class NSTreeController; + +#if defined(__cplusplus) +extern "C" { +#endif + +@interface GSControllerTreeProxy : NSTreeNode +{ + NSTreeController *_controller; +} + +- (instancetype) initWithContent: (id)content + withController: (id)controller; + +- (NSUInteger) count; + +- (NSMutableArray *) children; + +- (id) value; + +- (void) setValue: (id)value; + +@end + +#if defined(__cplusplus) +} +#endif + +#endif /* _GSControllerTreeProxy_h_GNUSTEP_GUI_INCLUDE */ + diff --git a/Source/GSControllerTreeProxy.m b/Source/GSControllerTreeProxy.m new file mode 100644 index 000000000..715a6525a --- /dev/null +++ b/Source/GSControllerTreeProxy.m @@ -0,0 +1,90 @@ +/* Implementation of class GSControllerTreeProxy + Copyright (C) 2024 Free Software Foundation, Inc. + + By: Gregory John Casamento + Date: 24-06-2024 + + This file is part of the GNUstep Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110 USA. +*/ + +#import +#import +#import + +#import "AppKit/NSTreeController.h" + +#import "GSControllerTreeProxy.h" +#import "GSBindingHelpers.h" + +@implementation GSControllerTreeProxy + +- (instancetype) initWithContent: (id)content + withController: (id)controller +{ + NSMutableDictionary *dict = + [NSMutableDictionary dictionaryWithObject: + [NSMutableArray arrayWithArray: content] + forKey: @"children"]; + + self = [super initWithRepresentedObject: dict]; + if (self != nil) + { + ASSIGN(_controller, controller); + } + + return self; +} + +- (NSUInteger) count +{ + NSArray *children = [[self representedObject] objectForKey: @"children"]; + return [children count]; +} + +// This is here so that when the path is specified as "children" it responds +- (NSMutableArray *) children +{ + NSDictionary *ro = [self representedObject]; + NSMutableArray *children = [ro objectForKey: @"children"]; + return children; +} + +- (id) value +{ + return [_representedObject objectForKey: @"value"]; +} + +- (void) setValue: (id)value +{ + [_representedObject setObject: value + forKey: @"value"]; +} + +// These return the value in the cases where the parent class method is called... +- (NSArray *) childNodes +{ + return [self children]; +} + +- (NSMutableArray *) mutableChildNodes +{ + return [self children]; +} + +@end + diff --git a/Source/GSThemeDrawing.m b/Source/GSThemeDrawing.m index 8c817a21a..6c7006742 100644 --- a/Source/GSThemeDrawing.m +++ b/Source/GSThemeDrawing.m @@ -44,6 +44,7 @@ #import "AppKit/NSGraphics.h" #import "AppKit/NSImage.h" #import "AppKit/NSImageView.h" +#import "AppKit/NSKeyValueBinding.h" #import "AppKit/NSMenuView.h" #import "AppKit/NSMenuItemCell.h" #import "AppKit/NSOutlineView.h" @@ -70,6 +71,7 @@ #import "GNUstepGUI/GSToolbarView.h" #import "GNUstepGUI/GSTitleView.h" +#import "GSBindingHelpers.h" /* a border width of 5 gives a reasonable compromise between Cocoa metrics and looking good */ /* 7.0 gives us the NeXT Look (which is 8 pix wide including the shadow) */ @@ -3284,7 +3286,7 @@ - (void) drawTableViewRect: (NSRect)aRect { endingRow = numberOfRows - 1; } - // NSLog(@"drawRect : %d-%d", startingRow, endingRow); + // NSLog(@"drawRect : %ld-%ld", startingRow, endingRow); { SEL sel = @selector(drawRow:clipRect:); void (*imp)(id, SEL, NSInteger, NSRect); @@ -3408,6 +3410,7 @@ - (void) drawTableViewRow: (NSInteger)rowIndex { const BOOL columnSelected = [tableView isColumnSelected: i]; const BOOL cellSelected = (rowSelected || columnSelected); + tb = [tableColumns objectAtIndex: i]; cell = [tb dataCellForRow: rowIndex]; [tableView _willDisplayCell: cell @@ -3529,14 +3532,8 @@ - (void) drawOutlineViewRow: (NSInteger)rowIndex NSInteger endingColumn; NSRect drawingRect; NSInteger i; - id dataSource = [outlineView dataSource]; NSTableColumn *outlineTableColumn = [outlineView outlineTableColumn]; - if (dataSource == nil) - { - return; - } - /* Using columnAtPoint: here would make it called twice per row per drawn rect - so we avoid it and do it natively */ @@ -3566,9 +3563,9 @@ - (void) drawOutlineViewRow: (NSInteger)rowIndex } else { - [cell setObjectValue: [dataSource outlineView: outlineView - objectValueForTableColumn: tb - byItem: item]]; + id value = [outlineView _objectValueForTableColumn: tb + row: rowIndex]; + [cell setObjectValue: value]; } drawingRect = [outlineView frameOfCellAtColumn: i diff --git a/Source/GSXib5KeyedUnarchiver.m b/Source/GSXib5KeyedUnarchiver.m index 80b75bfaa..75c64ba26 100644 --- a/Source/GSXib5KeyedUnarchiver.m +++ b/Source/GSXib5KeyedUnarchiver.m @@ -330,6 +330,9 @@ + (void) initialize @"shadow", @"NSViewShadow", @"blurRadius", @"NSShadowBlurRadius", @"color", @"NSShadowColor", + @"childrenKeyPath", @"NSTreeContentChildrenKey", // NSTreeController + @"countKeyPath", @"NSTreeContentCountKey", + @"leafKeyPath", @"NSTreeContentLeafKey", nil]; RETAIN(XmlKeyMapTable); diff --git a/Source/NSArrayController.m b/Source/NSArrayController.m index 80e3aaaf4..b1dfce2f2 100644 --- a/Source/NSArrayController.m +++ b/Source/NSArrayController.m @@ -147,6 +147,7 @@ + (void) initialize if (self == [NSArrayController class]) { [self exposeBinding: NSContentArrayBinding]; + [self exposeBinding: NSSelectionIndexesBinding]; [self setKeys: [NSArray arrayWithObjects: NSContentBinding, NSContentObjectBinding, nil] triggerChangeNotificationsForDependentKey: @"arrangedObjects"]; } diff --git a/Source/NSBrowser.m b/Source/NSBrowser.m index bc608750a..ccdbd5113 100644 --- a/Source/NSBrowser.m +++ b/Source/NSBrowser.m @@ -66,6 +66,7 @@ #import "GNUstepGUI/GSTheme.h" #import "GSGuiPrivate.h" +#import "GSBindingHelpers.h" /* Cache */ static CGFloat scrollerWidth; // == [NSScroller scrollerWidth]; @@ -2569,6 +2570,8 @@ - (id) initWithFrame: (NSRect)rect - (void) dealloc { + [GSKeyValueBinding unbindAllForObject: self]; + [[NSNotificationCenter defaultCenter] removeObserver: self]; if ([titleCell controlView] == self) diff --git a/Source/NSControl.m b/Source/NSControl.m index c9fab9404..f05f6e340 100644 --- a/Source/NSControl.m +++ b/Source/NSControl.m @@ -122,6 +122,7 @@ - (id) initWithFrame: (NSRect)frameRect - (void) dealloc { + [GSKeyValueBinding unbindAllForObject: self]; RELEASE(_cell); [super dealloc]; } diff --git a/Source/NSKeyValueBinding.m b/Source/NSKeyValueBinding.m index d5b9e2769..bfc9d7676 100644 --- a/Source/NSKeyValueBinding.m +++ b/Source/NSKeyValueBinding.m @@ -192,8 +192,11 @@ + (GSKeyValueBinding *) getBinding: (NSString *)binding if (!objectTable) return nil; + NSDebugLLog(@"NSBinding", @"+++ called with %@, %@", binding, anObject); [bindingLock lock]; bindings = (NSMutableDictionary *)NSMapGet(objectTable, (void *)anObject); + + NSDebugLLog(@"NSBinding", @"+++ Bindings found for %@ => %@", anObject, bindings); if (bindings != nil) { theBinding = (GSKeyValueBinding*)[bindings objectForKey: binding]; @@ -321,6 +324,11 @@ - (void)dealloc [super dealloc]; } +- (id) observedObject +{ + return [info objectForKey: NSObservedObjectKey]; +} + - (id) destinationValue { id newValue; diff --git a/Source/NSObjectController.m b/Source/NSObjectController.m index db9331ea2..71f00d785 100644 --- a/Source/NSObjectController.m +++ b/Source/NSObjectController.m @@ -99,6 +99,8 @@ + (void) initialize { if (self == [NSObjectController class]) { + [self setVersion: 1]; + [self exposeBinding: NSContentObjectBinding]; [self setKeys: [NSArray arrayWithObject: @"editable"] triggerChangeNotificationsForDependentKey: @"canAdd"]; @@ -155,11 +157,13 @@ - (void) encodeWithCoder: (NSCoder *)coder [coder encodeValueOfObjCType: @encode(BOOL) at: &_is_editable]; [coder encodeValueOfObjCType: @encode(BOOL) at: &_automatically_prepares_content]; [coder encodeConditionalObject: _managed_proxy]; + [coder encodeObject: NSStringFromClass([self objectClass])]; } } - (id) initWithCoder: (NSCoder *)coder -{ +{ + int version = [coder versionForClassName: @"NSObjectController"]; if ((self = [super initWithCoder: coder]) != nil) { if ([self automaticallyPreparesContent]) @@ -190,6 +194,11 @@ - (id) initWithCoder: (NSCoder *)coder [coder decodeValueOfObjCType: @encode(BOOL) at: &_is_editable]; [coder decodeValueOfObjCType: @encode(BOOL) at: &_automatically_prepares_content]; ASSIGN(_managed_proxy, [coder decodeObject]); + if (version > 0) + { + NSString *className = [coder decodeObject]; + [self setObjectClass: NSClassFromString(className)]; + } } } diff --git a/Source/NSOutlineView.m b/Source/NSOutlineView.m index 2bf286070..ff915c9e6 100644 --- a/Source/NSOutlineView.m +++ b/Source/NSOutlineView.m @@ -54,16 +54,22 @@ #import "AppKit/NSEvent.h" #import "AppKit/NSGraphics.h" #import "AppKit/NSImage.h" +#import "AppKit/NSKeyValueBinding.h" #import "AppKit/NSOutlineView.h" #import "AppKit/NSScroller.h" #import "AppKit/NSTableColumn.h" #import "AppKit/NSTableHeaderView.h" #import "AppKit/NSText.h" #import "AppKit/NSTextFieldCell.h" +#import "AppKit/NSTreeController.h" +#import "AppKit/NSTreeNode.h" #import "AppKit/NSWindow.h" #import "GNUstepGUI/GSTheme.h" +#import "GSBindingHelpers.h" +#import "GSFastEnumeration.h" #import "GSGuiPrivate.h" + #include static NSMapTableKeyCallBacks keyCallBacks; @@ -143,6 +149,24 @@ - (void) _drawCellViewRow: (NSInteger)rowIndex clipRect: (NSRect)clipRect; @end +@interface NSTableColumn (Private) +- (void) _applyBindingsToCell: (NSCell *)cell + atRow: (NSInteger)index; +- (NSString *) _keyPathForValueBinding; +@end + +@interface NSTreeNode (Private_NSOutlineView) +- (void) _setParentNode: (NSTreeNode*)parentNode; +@end + +@implementation NSTreeNode (Private_NSOutlineView) + +- (void) _setParentNode: (NSTreeNode*)parentNode +{ + _parentNode = parentNode; +} + +@end @implementation NSOutlineView // Initialize the class when it is loaded @@ -170,6 +194,12 @@ + (void) initialize unexpandable = [[NSImage alloc] initWithSize: [expanded size]]; #endif autoExpanded = [NSMutableSet new]; + + // Bindings.. + [self exposeBinding: NSContentBinding]; + [self exposeBinding: NSContentArrayBinding]; + [self exposeBinding: NSSelectionIndexesBinding]; + [self exposeBinding: NSSortDescriptorsBinding]; } } @@ -440,11 +470,57 @@ - (CGFloat) indentationPerLevel */ - (BOOL) isExpandable: (id)item { - if (item == nil) + BOOL result = NO; + GSKeyValueBinding *theBinding = [GSKeyValueBinding getBinding: NSContentBinding + forObject: self]; + if (theBinding != nil) { - return NO; + BOOL leaf = YES; + id observedObject = [theBinding observedObject]; + NSTreeController *tc = (NSTreeController *)observedObject; + NSString *leafKeyPath = [tc leafKeyPathForNode: item]; + + if (leafKeyPath == nil) + { + NSString *countKeyPath = [tc countKeyPathForNode: item]; + + if (countKeyPath == nil) + { + NSString *childrenKeyPath = [tc childrenKeyPathForNode: item]; + + if (childrenKeyPath == nil) + { + result = NO; + } + else + { + id children = [item valueForKeyPath: childrenKeyPath]; + + leaf = ([children count] > 0); + } + } + else + { + NSNumber *countValue = [item valueForKeyPath: countKeyPath]; + + leaf = ([countValue integerValue] > 0); + } + } + else + { + NSNumber *leafValue = [item valueForKeyPath: leafKeyPath]; + + leaf = [leafValue boolValue]; + } + + result = !leaf; // if item is a leaf, it's not expandable... } - return [_dataSource outlineView: self isItemExpandable: item]; + else if (item != nil) + { + result = [_dataSource outlineView: self isItemExpandable: item]; + } + + return result; } /** @@ -700,21 +776,34 @@ - (BOOL)shouldCollapseAutoExpandedItemsForDeposited: (BOOL)deposited */ - (void) setDataSource: (id)anObject { + GSKeyValueBinding *theBinding; + #define CHECK_REQUIRED_METHOD(selector_name) \ if (anObject && ![anObject respondsToSelector: @selector(selector_name)]) \ [NSException raise: NSInternalInconsistencyException \ format: @"data source does not respond to %@", @#selector_name] - CHECK_REQUIRED_METHOD(outlineView:child:ofItem:); - CHECK_REQUIRED_METHOD(outlineView:isItemExpandable:); - CHECK_REQUIRED_METHOD(outlineView:numberOfChildrenOfItem:); + theBinding = [GSKeyValueBinding getBinding: NSContentBinding + forObject: self]; + if (theBinding == nil) + { + CHECK_REQUIRED_METHOD(outlineView:child:ofItem:); + CHECK_REQUIRED_METHOD(outlineView:isItemExpandable:); + CHECK_REQUIRED_METHOD(outlineView:numberOfChildrenOfItem:); - // This method is @optional in NSOutlineViewDataSource as of macOS10.0 - // CHECK_REQUIRED_METHOD(outlineView:objectValueForTableColumn:byItem:); + // This method is @optional in NSOutlineViewDataSource as of macOS10.0 + // CHECK_REQUIRED_METHOD(outlineView:objectValueForTableColumn:byItem:); - // Is the data source editable? - _dataSource_editable = [anObject respondsToSelector: - @selector(outlineView:setObjectValue:forTableColumn:byItem:)]; + // Is the data source editable? + _dataSource_editable = [anObject respondsToSelector: + @selector(outlineView:setObjectValue:forTableColumn:byItem:)]; + } + else + { + /* Based on testing on macOS, this should default to YES if there is a binding... + */ + _dataSource_editable = YES; + } /* We do *not* retain the dataSource, it's like a delegate */ _dataSource = anObject; @@ -956,6 +1045,16 @@ - (void)keyDown: (NSEvent*)event */ - (void) drawRow: (NSInteger)rowIndex clipRect: (NSRect)aRect { + GSKeyValueBinding *theBinding = nil; + + theBinding = [GSKeyValueBinding getBinding: NSContentBinding + forObject: self]; + + if (_dataSource == nil && theBinding == nil) + { + return; + } + if (_viewBased) { [self _drawCellViewRow: rowIndex @@ -1642,6 +1741,85 @@ before the actual editing is started (otherwise you easily end up @end /* implementation of NSOutlineView */ @implementation NSOutlineView (NotificationRequestMethods) + +- (NSIndexPath *) _findIndexPathForItem: (id)item + parentItem: (id)pItem +{ + id parentItem = (pItem == nil) ? (id)[NSNull null] : (id)pItem; + NSArray *children = NSMapGet(_itemDict, parentItem); + NSInteger childCount = [children count]; + NSInteger index = 0; + + for (index = 0; index < childCount; index++) + { + id childItem = [children objectAtIndex: index]; + + if (childItem == item) + { + return [NSIndexPath indexPathWithIndex: index]; + } + else + { + NSIndexPath *foundPath = [self _findIndexPathForItem: item + parentItem: childItem]; + + if (foundPath != nil) + { + NSIndexPath *newPath = [NSIndexPath indexPathWithIndex: index]; + NSUInteger length = [foundPath length]; + NSUInteger indexes[length + 1]; + NSUInteger i = 0; + + [foundPath getIndexes: indexes]; + + // Iterate over existing indexes... + for (i = 0; i < length; i++) + { + newPath = [newPath indexPathByAddingIndex: indexes[i]]; + } + + return newPath; + } + } + } + + return nil; +} + +- (NSIndexPath *) _indexPathForItem: (id)item +{ + return [self _findIndexPathForItem: item + parentItem: nil]; +} + +- (NSArray *) _indexPathsFromSelectedRows +{ + NSUInteger index = [_selectedRows firstIndex]; + NSMutableArray *result = [[NSMutableArray alloc] init]; + + // Regenerate the array... + while (index != NSNotFound) + { + id item = [_items objectAtIndex: index]; + NSIndexPath *path = nil; + + if ([item respondsToSelector: @selector(indexPath)]) + { + path = [item indexPath]; + } + else + { + path = [self _indexPathForItem: item]; + } + + [result addObject: path]; + + index = [_selectedRows indexGreaterThanIndex: index]; + } + + return result; +} + /* * (NotificationRequestMethods) */ @@ -1651,12 +1829,38 @@ - (void) _postSelectionIsChangingNotification NSOutlineViewSelectionIsChangingNotification object: self]; } + - (void) _postSelectionDidChangeNotification { - [nc postNotificationName: - NSOutlineViewSelectionDidChangeNotification - object: self]; + NSTableColumn *tb = [_tableColumns objectAtIndex: 0]; + GSKeyValueBinding *theBinding; + + theBinding = [GSKeyValueBinding getBinding: NSValueBinding + forObject: tb]; + + // If there is a binding, send the indexes back + if (theBinding != nil) + { + id observedObject = [theBinding observedObject]; + + // Set the selection indexes on the controller... + theBinding = [GSKeyValueBinding getBinding: NSSelectionIndexPathsBinding + forObject: observedObject]; + if (theBinding != nil) + { + NSArray *paths = [self _indexPathsFromSelectedRows]; + if ([observedObject respondsToSelector: @selector(setSelectionIndexPaths:)]) + { + [observedObject setSelectionIndexPaths: paths]; + } + [theBinding reverseSetValue: paths]; + } + } + + [nc postNotificationName: NSOutlineViewSelectionDidChangeNotification + object: self]; } + - (void) _postColumnDidMoveNotificationWithOldIndex: (NSInteger) oldIndex newIndex: (NSInteger) newIndex { @@ -1766,10 +1970,13 @@ - (BOOL) _shouldEditTableColumn: (NSTableColumn *)tableColumn return YES; } -- (void) _willDisplayCell: (NSCell*)cell +- (void) _willDisplayCell: (NSCell *)cell forTableColumn: (NSTableColumn *)tb row: (NSInteger)index { + [tb _applyBindingsToCell: cell + atRow: index]; + if (_del_responds) { id item = [self itemAtRow: index]; @@ -1814,15 +2021,24 @@ - (id) _objectValueForTableColumn: (NSTableColumn *)tb row: (NSInteger) index { id result = nil; + NSString *keyPath = [tb _keyPathForValueBinding]; - if ([_dataSource respondsToSelector: - @selector(outlineView:objectValueForTableColumn:byItem:)]) + if (keyPath != nil) { - id item = [self itemAtRow: index]; + id theItem = [_items objectAtIndex: index]; + result = [theItem valueForKeyPath: keyPath]; + } + else + { + if ([_dataSource respondsToSelector: + @selector(outlineView:objectValueForTableColumn:byItem:)]) + { + id item = [self itemAtRow: index]; - result = [_dataSource outlineView: self - objectValueForTableColumn: tb - byItem: item]; + result = [_dataSource outlineView: self + objectValueForTableColumn: tb + byItem: item]; + } } return result; @@ -1832,15 +2048,30 @@ - (void) _setObjectValue: (id)value forTableColumn: (NSTableColumn *)tb row: (NSInteger) index { - if ([_dataSource respondsToSelector: - @selector(outlineView:setObjectValue:forTableColumn:byItem:)]) + NSString *keyPath = [tb _keyPathForValueBinding]; + + // If we have content binding the data source is used only + // like a delegate + if (keyPath != nil) { - id item = [self itemAtRow: index]; + id theItem = [_items objectAtIndex: index]; - [_dataSource outlineView: self - setObjectValue: value - forTableColumn: tb - byItem: item]; + // Set the value on the keyPath. + [theItem setValue: value + forKeyPath: keyPath]; + } + else + { + if ([_dataSource respondsToSelector: + @selector(outlineView:setObjectValue:forTableColumn:byItem:)]) + { + id item = [self itemAtRow: index]; + + [_dataSource outlineView: self + setObjectValue: value + forTableColumn: tb + byItem: item]; + } } } @@ -1953,43 +2184,131 @@ - (BOOL) _isItemLoaded: (id)item - (void) _loadDictionaryStartingWith: (id) startitem atLevel: (NSInteger) level { + GSKeyValueBinding *theBinding = nil; NSInteger num = 0; NSInteger i = 0; id sitem = (startitem == nil) ? (id)[NSNull null] : (id)startitem; NSMutableArray *anarray = nil; - /* Check to see if item is expandable and expanded before getting the number - * of items. For macos compatibility the topmost item (startitem==nil) - * is always considered expandable and must not be checked. - * We must load the item only if expanded, otherwise an outline view is not - * usable with a big tree structure. For example, an outline view to browse - * file system would try to traverse every file/directory on -reloadData. - */ - if ((startitem == nil - || [_dataSource outlineView: self isItemExpandable: startitem]) - && [self isItemExpanded: startitem]) + theBinding = [GSKeyValueBinding getBinding: NSContentBinding + forObject: self]; + if (theBinding != nil) { - num = [_dataSource outlineView: self - numberOfChildrenOfItem: startitem]; - } + id observedObject = [theBinding observedObject]; + NSTreeController *tc = (NSTreeController *)observedObject; + NSArray *children = nil; - if (num > 0) - { - anarray = [NSMutableArray array]; - NSMapInsert(_itemDict, sitem, anarray); - } + /* If there is a binding present, then allow it to be editable + * by default as editability of cells is determined in the + * NSTableColumn class based on the binding there for the + * editable property as defined in IB. + */ + _dataSource_editable = YES; - NSMapInsert(_levelOfItems, sitem, [NSNumber numberWithInteger: level]); + /* Implement logic to build the internal data structure here using + * bindings... + */ + if ([observedObject isKindOfClass: [NSTreeController class]]) + { + if (startitem == nil) + { + NSTreeNode *node = (NSTreeNode *)[theBinding destinationValue]; + + /* Per the documentation 10.4/5+ uses NSTreeNode as the return value for + * the contents of this tree node consists of a dictionary with a single + * key of "children". This is per the tests for this at + * https://github.com/gcasa/NSTreeController_test. Specifically it returns + * _NSControllerTreeProxy. The equivalent of that class in GNUstep is + * GSControllerTreeProxy. + */ + children = [node mutableChildNodes]; + num = [children count]; + } + else + { + /* Per the documentation in NSTreeController, we can determine everything + * from whether there are children present on a given node. See + * the documentation for NSTreeController for more info. + */ + if ([self isExpandable: startitem] + && [self isItemExpanded: startitem]) + { + NSString *childrenKeyPath = [tc childrenKeyPathForNode: startitem]; + + if (childrenKeyPath != nil) + { + NSString *countKeyPath = [tc countKeyPathForNode: startitem]; + + children = [sitem valueForKeyPath: childrenKeyPath]; + if (countKeyPath == nil) + { + num = [children count]; // get the count directly... + } + else + { + NSNumber *countValue = [sitem valueForKeyPath: countKeyPath]; + num = [countValue integerValue]; + } + } + } + } - for (i = 0; i < num; i++) + if (num > 0) + { + anarray = [NSMutableArray arrayWithCapacity: num]; + NSMapInsert(_itemDict, sitem, anarray); + } + + NSMapInsert(_levelOfItems, sitem, [NSNumber numberWithInteger: level]); + + for (i = 0; i < num; i++) + { + id anitem = [children objectAtIndex: i]; + + if ([anitem respondsToSelector: @selector(_setParentNode:)]) + { + [anitem _setParentNode: startitem]; + } + [anarray addObject: anitem]; + [self _loadDictionaryStartingWith: anitem + atLevel: level + 1]; + } + } + } + else { - id anitem = [_dataSource outlineView: self - child: i - ofItem: startitem]; + /* Check to see if item is expandable and expanded before getting the number + * of items. For macos compatibility the topmost item (startitem==nil) + * is always considered expandable and must not be checked. + * We must load the item only if expanded, otherwise an outline view is not + * usable with a big tree structure. For example, an outline view to browse + * file system would try to traverse every file/directory on -reloadData. + */ + if (startitem == nil + || ([self isExpandable: startitem] + && [self isItemExpanded: startitem])) + { + num = [_dataSource outlineView: self + numberOfChildrenOfItem: startitem]; + } + + if (num > 0) + { + anarray = [NSMutableArray arrayWithCapacity: num]; + NSMapInsert(_itemDict, sitem, anarray); + } - [anarray addObject: anitem]; - [self _loadDictionaryStartingWith: anitem - atLevel: level + 1]; + NSMapInsert(_levelOfItems, sitem, [NSNumber numberWithInteger: level]); + + for (i = 0; i < num; i++) + { + id anitem = [_dataSource outlineView: self + child: i + ofItem: startitem]; + [anarray addObject: anitem]; + [self _loadDictionaryStartingWith: anitem + atLevel: level + 1]; + } } } @@ -2226,7 +2545,7 @@ - (NSView *) viewAtColumn: (NSInteger)column row: (NSInteger)row makeIfNecessary drawingRect: drawingRect rowIndex: row]; } - + if (view == nil && flag == YES) { diff --git a/Source/NSTableColumn.m b/Source/NSTableColumn.m index ff99499ee..5e8418e09 100644 --- a/Source/NSTableColumn.m +++ b/Source/NSTableColumn.m @@ -97,6 +97,10 @@ + (void) initialize [self setVersion: 4]; [self exposeBinding: NSValueBinding]; [self exposeBinding: NSEnabledBinding]; + [self exposeBinding: NSEditableBinding]; + [self exposeBinding: NSFontBinding]; + [self exposeBinding: NSFontNameBinding]; + [self exposeBinding: NSFontSizeBinding]; } } @@ -650,6 +654,89 @@ - (NSString *) title return [_headerCell stringValue]; } +- (NSString *) _keyPathForValueBinding +{ + NSString *keyPath = nil; + NSDictionary *info = [GSKeyValueBinding infoForBinding: NSValueBinding + forObject: self]; + if (info != nil) + { + NSString *ikp = [info objectForKey: NSObservedKeyPathKey]; + NSUInteger location = [ikp rangeOfString: @"."].location; + + keyPath = (location == NSNotFound ? ikp : [ikp substringFromIndex: location + 1]); + } + + return keyPath; +} + +- (void) _applyBindingsToCell: (NSCell *)cell + atRow: (NSInteger)index +{ + GSKeyValueBinding *theBinding = nil; + NSFont *font = nil; + + [cell setEditable: _is_editable]; + theBinding = [GSKeyValueBinding getBinding: NSEnabledBinding + forObject: self]; + if (theBinding != nil) + { + id result = nil; + BOOL flag = NO; + + result = [(NSArray *)[theBinding destinationValue] + objectAtIndex: index]; + flag = [result boolValue]; + [cell setEnabled: flag]; + } + + /* Font bindings... According to Apple documentation, if the + * font binding is available, then name, size, and other + * font related bindings are ignored. Otherwise they are + * used + */ + theBinding = [GSKeyValueBinding getBinding: NSFontBinding + forObject: self]; + if (theBinding != nil) + { + font = [(NSArray *)[theBinding destinationValue] + objectAtIndex: index]; + } + else + { + NSString *fontName = nil; + CGFloat fontSize = 0.0; + + theBinding = [GSKeyValueBinding getBinding: NSFontNameBinding + forObject: self]; + if (theBinding != nil) + { + fontName = [(NSArray *)[theBinding destinationValue] + objectAtIndex: index]; + } + + if (fontName != nil) + { + theBinding = [GSKeyValueBinding getBinding: NSFontSizeBinding + forObject: self]; + if (theBinding != nil) + { + id num = [(NSArray *)[theBinding destinationValue] + objectAtIndex: index]; + fontSize = [num doubleValue]; + } + + font = [NSFont fontWithName: fontName + size: fontSize]; + } + } + + if (font != nil) + { + [cell setFont: font]; + } +} + - (void) setValue: (id)anObject forKey: (NSString*)aKey { if ([aKey isEqual: NSValueBinding]) @@ -661,6 +748,13 @@ - (void) setValue: (id)anObject forKey: (NSString*)aKey { // FIXME } + else if ([aKey isEqual: NSEditableBinding]) + { + if ([anObject isKindOfClass: [NSNumber class]]) + { + _is_editable = [anObject boolValue]; + } + } else { [super setValue: anObject forKey: aKey]; @@ -678,6 +772,10 @@ - (id) valueForKey: (NSString*)aKey // FIXME return [NSNumber numberWithBool: YES]; } + else if ([aKey isEqual: NSEditableBinding]) + { + return [NSNumber numberWithBool: _is_editable]; + } else { return [super valueForKey: aKey]; diff --git a/Source/NSTableView.m b/Source/NSTableView.m index abf8c4f1d..eae550bf3 100644 --- a/Source/NSTableView.m +++ b/Source/NSTableView.m @@ -4,7 +4,7 @@ Author: Nicola Pero Date: March 2000, June 2000, August 2000, September 2000 - + Author: Pierre-Yves Rivaille Date: August 2001, January 2002 @@ -25,10 +25,10 @@ You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. - If not, see or write to the - Free Software Foundation, 51 Franklin Street, Fifth Floor, + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ +*/ #import #import @@ -47,6 +47,7 @@ #import "AppKit/NSTableView.h" #import "AppKit/NSApplication.h" +#import "AppKit/NSArrayController.h" #import "AppKit/NSCell.h" #import "AppKit/NSClipView.h" #import "AppKit/NSColor.h" @@ -88,7 +89,7 @@ static NSDragOperation currentDragOperation; /* - * Nib compatibility struct. This structure is used to + * Nib compatibility struct. This structure is used to * pull the attributes out of the nib that we need to fill * in the flags. */ @@ -155,9 +156,9 @@ - (void)_setObjectValue: (id)value row: (NSInteger)index; - (BOOL) _isEditableColumn: (NSInteger)columnIndex - row: (NSInteger)rowIndex; + row: (NSInteger)rowIndex; - (BOOL) _isCellSelectableColumn: (NSInteger)columnIndex - row: (NSInteger)rowIndex; + row: (NSInteger)rowIndex; - (BOOL) _isCellEditableColumn: (NSInteger)columnIndex row: (NSInteger)rowIndex; - (NSInteger) _numRows; @@ -182,6 +183,9 @@ - (BOOL) _startDragOperationWithEvent:(NSEvent *)theEvent; @interface NSTableColumn (Private) - (NSArray *) _prototypeCellViews; +- (void) _applyBindingsToCell: (NSCell *)cell + atRow: (NSInteger)index; +- (NSString *) _keyPathForValueBinding; @end /* @@ -209,9 +213,9 @@ void quick_sort_internal(columnSorting *data, int p, int r) while (1) { j--; - for (; + for (; (data[j].width > x) - || ((data[j].width == x) + || ((data[j].width == x) && (data[j].isMax == YES) && (y == NO)); j--) @@ -220,7 +224,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) i++; for (; (data[i].width < x) - || ((data[i].width == x) + || ((data[i].width == x) && (data[i].isMax == NO) && (y == YES)); i++) @@ -243,8 +247,8 @@ void quick_sort_internal(columnSorting *data, int p, int r) } } -/* - * Now some auxiliary functions used to manage real-time user selections. +/* + * Now some auxiliary functions used to manage real-time user selections. * */ @@ -260,12 +264,12 @@ void quick_sort_internal(columnSorting *data, int p, int r) { if (!(selectionMode & ALLOWS_MULTIPLE)) { - if ((selectionMode & SHIFT_DOWN) && - (selectionMode & ALLOWS_EMPTY) && + if ((selectionMode & SHIFT_DOWN) && + (selectionMode & ALLOWS_EMPTY) && !(selectionMode & ADDING_ROW)) // we will unselect the selected row // ic, sc : ok - { + { NSUInteger count = [_selectedRows count]; if ((count == 0) && (_oldRow == -1)) @@ -283,18 +287,18 @@ void quick_sort_internal(columnSorting *data, int p, int r) else if (_currentRow != _originalRow) { if (*_selectedRow == _originalRow) - { + { // we are already selected, don't do anything } else - { + { //begin checking code if (count > 0) { NSLog(@"There should not be any row selected"); } //end checking code - + if ([tv _selectRow: _originalRow]) { [tv _postSelectionIsChangingNotification]; @@ -304,31 +308,31 @@ void quick_sort_internal(columnSorting *data, int p, int r) else if (_currentRow == _originalRow) { if (count == 0) - { + { // the row is already deselected // nothing to do ! } else - { + { [tv _unselectRow: _originalRow]; [tv _postSelectionIsChangingNotification]; } } } - else //(!(selectionMode & ALLOWS_MULTIPLE) && - //(!(selectionMode & SHIFT_DOWN) || + else //(!(selectionMode & ALLOWS_MULTIPLE) && + //(!(selectionMode & SHIFT_DOWN) || //!(selectionMode & ALLOWS_EMPTY) || //(selectionMode & ADDING_ROW))) // we'll be selecting exactly one row // ic, sc : ok - { + { NSUInteger count = [_selectedRows count]; - + if ([tv _shouldSelectRow: _currentRow] == NO) { return; } - + if ((count != 1) || (_oldRow == -1)) { // this is the first call that goes thru shouldSelectRow @@ -337,20 +341,20 @@ void quick_sort_internal(columnSorting *data, int p, int r) [tv _unselectAllRows]; [_selectedRows addIndex: _currentRow]; *_selectedRow = _currentRow; - + if (notified == YES) - { + { [tv setNeedsDisplayInRect: [tv rectOfRow: _currentRow]]; } else - { + { if (count > 1) { notified = YES; } } if (notified == YES) - { + { [tv _postSelectionIsChangingNotification]; } } @@ -361,18 +365,18 @@ void quick_sort_internal(columnSorting *data, int p, int r) //begin checking code if (![_selectedRows containsIndex: *_selectedRow]) - { + { NSLog(@"*_selectedRow is not the only selected row!"); } //end checking code - + if (*_selectedRow == _currentRow) - { + { // currentRow is already selecteed return; } else - { + { [tv _unselectRow: *_selectedRow]; // CHANGE: This does a check more [tv _selectRow: _currentRow]; @@ -425,7 +429,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) } } else // new multiple selection, after first pass - { + { NSInteger oldDiff, newDiff, i; oldDiff = _oldRow - _originalRow; newDiff = _currentRow - _originalRow; @@ -463,9 +467,9 @@ void quick_sort_internal(columnSorting *data, int p, int r) // leave it selected continue; } - + if ([tv _unselectRow: i]) - { + { notified = YES; } } @@ -549,7 +553,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) else if (oldDiff <= 0 && newDiff >= 0) { BOOL notified = NO; - + // we're reducing the selection { for (i = _oldRow; i < _originalRow; i++) @@ -560,7 +564,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) // leave it selected continue; } - + if ([tv _unselectRow: i]) { notified = YES; @@ -569,7 +573,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) } // then we're extending it for (i = _originalRow + 1; i <= _currentRow; i++) - { + { if ([_selectedRows containsIndex: i] || [tv _selectRow: i]) { @@ -602,14 +606,14 @@ void quick_sort_internal(columnSorting *data, int p, int r) // we're reducing the selection for (i = _oldRow; i > _originalRow; i--) - { + { if ([_oldSelectedRows containsIndex: i]) { // this row was in the old selection // leave it selected continue; } - + if ([tv _unselectRow: i]) { notified = YES; @@ -617,7 +621,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) } // then we're extending it for (i = _originalRow - 1; i >= _currentRow; i--) - { + { if ([_selectedRows containsIndex: i] || [tv _selectRow: i]) { @@ -661,7 +665,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) NSInteger diff, i; NSUInteger count = [_selectedRows count]; BOOL notified = NO; - diff = _currentRow - _originalRow; + diff = _currentRow - _originalRow; if (count > 0) { @@ -697,7 +701,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) } } else // new multiple selection, after first pass - { + { NSInteger oldDiff, newDiff, i; oldDiff = _oldRow - _originalRow; newDiff = _currentRow - _originalRow; @@ -761,7 +765,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) { notified = YES; } - } + } if (notified == YES) { [tv _postSelectionIsChangingNotification]; @@ -801,10 +805,10 @@ void quick_sort_internal(columnSorting *data, int p, int r) else if (oldDiff <= 0 && newDiff >= 0) { BOOL notified = NO; - + // we're reducing the selection for (i = _oldRow; i < _originalRow; i++) - { + { if ([tv _unselectRow: i]) { notified = YES; @@ -812,7 +816,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) } // then we're extending it for (i = _originalRow + 1; i <= _currentRow; i++) - { + { if ([tv _selectRow: i]) { notified = YES; @@ -843,7 +847,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) // we're reducing the selection for (i = _oldRow; i > _originalRow; i--) - { + { if ([tv _unselectRow: i]) { notified = YES; @@ -851,7 +855,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) } // then we're extending it for (i = _originalRow - 1; i >= _currentRow; i--) - { + { if ([tv _selectRow: i]) { notified = YES; @@ -882,7 +886,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) && ((selectionMode & SHIFT_DOWN) == 0) && ((selectionMode & ALLOWS_EMPTY) == 0) && (selectionMode & ADDING_ROW)) - // the following case can be assimilated to the + // the following case can be assimilated to the // one before, although it will lead to an // extra redraw // TODO: solve this issue @@ -906,38 +910,38 @@ void quick_sort_internal(columnSorting *data, int p, int r) NSUInteger count = [_selectedRows count]; BOOL notified = NO; diff = _currentRow - _originalRow; - + if (count > 0) { notified = YES; } - + [tv _unselectAllRows]; - + if (diff >= 0) { for (i = _originalRow; i <= _currentRow; i++) { if ([tv _selectRow: i]) - { + { notified = YES; } - } + } } else { for (i = _originalRow; i >= _currentRow; i--) { if ([tv _selectRow: i]) - { + { notified = YES; } - } + } + } + if (notified == YES) + { + [tv _postSelectionIsChangingNotification]; } - if (notified == YES) - { - [tv _postSelectionIsChangingNotification]; - } } else { @@ -947,12 +951,12 @@ void quick_sort_internal(columnSorting *data, int p, int r) NSInteger diff, i; BOOL notified = NO; diff = _currentRow - _originalRow; - + if (diff >= 0) { for (i = _originalRow; i <= _currentRow; i++) { - if ([_selectedRows containsIndex: i] || + if ([_selectedRows containsIndex: i] || [tv _selectRow: i]) { *_selectedRow = i; @@ -965,7 +969,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) // this case does happen (sometimes) for (i = _originalRow; i >= _currentRow; i--) { - if ([_selectedRows containsIndex: i] || + if ([_selectedRows containsIndex: i] || [tv _selectRow: i]) { *_selectedRow = i; @@ -996,7 +1000,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) for (i = _oldRow + 1; i <= _currentRow; i++) { if ([tv _selectRow: i]) - { + { notified = YES; } } @@ -1012,20 +1016,20 @@ void quick_sort_internal(columnSorting *data, int p, int r) for (i = _oldRow; i > _currentRow; i--) { if ([tv _unselectRow: i]) - { + { notified = YES; } } if (*_selectedRow == -1) { NSUInteger last = [_selectedRows lastIndex]; - + if (last == NSNotFound) - { + { *_selectedRow = -1; } else - { + { *_selectedRow = last; } } @@ -1045,10 +1049,10 @@ void quick_sort_internal(columnSorting *data, int p, int r) for (i = _oldRow - 1; i >= _currentRow; i--) { if ([tv _selectRow: i]) - { + { notified = YES; } - } + } if (notified == YES) { [tv _postSelectionIsChangingNotification]; @@ -1062,7 +1066,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) for (i = _oldRow; i < _currentRow; i++) { if ([tv _unselectRow: i]) - { + { notified = YES; } } @@ -1089,10 +1093,10 @@ void quick_sort_internal(columnSorting *data, int p, int r) else if (oldDiff <= 0 && newDiff >= 0) { BOOL notified = NO; - + // we're reducing the selection for (i = _oldRow; i < _originalRow; i++) - { + { if ([tv _unselectRow: i]) { notified = YES; @@ -1100,7 +1104,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) } // then we're extending it for (i = _originalRow + 1; i <= _currentRow; i++) - { + { if ([tv _selectRow: i]) { notified = YES; @@ -1131,7 +1135,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) // we're reducing the selection for (i = _oldRow; i > _originalRow; i--) - { + { if ([tv _unselectRow: i]) { notified = YES; @@ -1139,7 +1143,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) } // then we're extending it for (i = _originalRow - 1; i >= _currentRow; i--) - { + { if ([tv _selectRow: i]) { notified = YES; @@ -1166,7 +1170,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) } } else - // as the originalRow is not selection, + // as the originalRow is not selection, // we are adding to the old selection { // this code is copied from another case @@ -1183,7 +1187,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) BOOL notified = NO; for (i = _oldRow + 1; i <= _currentRow; i++) { - if ([_selectedRows containsIndex: i] || + if ([_selectedRows containsIndex: i] || [tv _selectRow: i]) { *_selectedRow = i; @@ -1208,9 +1212,9 @@ void quick_sort_internal(columnSorting *data, int p, int r) // leave it selected continue; } - + if ([tv _unselectRow: i]) - { + { notified = YES; } } @@ -1220,11 +1224,11 @@ void quick_sort_internal(columnSorting *data, int p, int r) NSUInteger last = [_selectedRows lastIndex]; if (last == NSNotFound) - { + { *_selectedRow = -1; } else - { + { *_selectedRow = last; } } @@ -1242,7 +1246,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) BOOL notified = NO; for (i = _oldRow - 1; i >= _currentRow; i--) { - if ([_selectedRows containsIndex: i] || + if ([_selectedRows containsIndex: i] || [tv _selectRow: i]) { *_selectedRow = i; @@ -1269,7 +1273,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) continue; } if ([tv _unselectRow: i]) - { + { notified = YES; } } @@ -1295,10 +1299,10 @@ void quick_sort_internal(columnSorting *data, int p, int r) else if (oldDiff <= 0 && newDiff >= 0) { BOOL notified = NO; - + // we're reducing the selection for (i = _oldRow; i < _originalRow; i++) - { + { if ([_oldSelectedRows containsIndex: i]) { // this row was in the old selection @@ -1312,7 +1316,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) } // then we're extending it for (i = _originalRow + 1; i <= _currentRow; i++) - { + { if ([_selectedRows containsIndex: i] || [tv _selectRow: i]) { @@ -1324,7 +1328,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) if (*_selectedRow == -1) { NSUInteger first = [_selectedRows firstIndex]; - + if (first == NSNotFound) { *_selectedRow = -1; @@ -1345,14 +1349,14 @@ void quick_sort_internal(columnSorting *data, int p, int r) // we're reducing the selection for (i = _oldRow; i > _originalRow; i--) - { + { if ([_oldSelectedRows containsIndex: i]) { // this row was in the old selection // leave it selected continue; } - + if ([tv _unselectRow: i]) { notified = YES; @@ -1361,7 +1365,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) // then we're extending it for (i = _originalRow - 1; i >= _currentRow; i--) - { + { if ([_selectedRows containsIndex: i] || [tv _selectRow: i]) { @@ -1401,7 +1405,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) NSInteger diff, i; BOOL notified = NO; - diff = _currentRow - _originalRow; + diff = _currentRow - _originalRow; if (diff >= 0) { @@ -1415,7 +1419,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) if (*_selectedRow == -1) { NSUInteger first = [_selectedRows firstIndex]; - + if (first == NSNotFound) { *_selectedRow = -1; @@ -1439,7 +1443,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) if (*_selectedRow == -1) { NSUInteger first = [_selectedRows firstIndex]; - + if (first == NSNotFound) { *_selectedRow = -1; @@ -1456,7 +1460,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) } } else // new multiple antiselection, after first pass - { + { NSInteger oldDiff, newDiff, i; oldDiff = _oldRow - _originalRow; @@ -1478,7 +1482,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) if (*_selectedRow == -1) { NSUInteger first = [_selectedRows firstIndex]; - + if (first == NSNotFound) { *_selectedRow = -1; @@ -1534,13 +1538,13 @@ void quick_sort_internal(columnSorting *data, int p, int r) if (*_selectedRow == -1) { NSUInteger first = [_selectedRows firstIndex]; - + if (first == NSNotFound) - { + { *_selectedRow = -1; } else - { + { *_selectedRow = first; } } @@ -1578,7 +1582,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) else if (oldDiff <= 0 && newDiff >= 0) { BOOL notified = NO; - + // we're reducing the selection { for (i = _oldRow; i < _originalRow; i++) @@ -1609,7 +1613,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) if (*_selectedRow == -1) { NSUInteger first = [_selectedRows firstIndex]; - + if (first == NSNotFound) { *_selectedRow = -1; @@ -1628,7 +1632,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) else if (oldDiff >= 0 && newDiff <= 0) { BOOL notified = NO; - + // we're reducing the selection { for (i = _oldRow; i > _originalRow; i--) @@ -1659,7 +1663,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) if (*_selectedRow == -1) { NSUInteger first = [_selectedRows firstIndex]; - + if (first == NSNotFound) { *_selectedRow = -1; @@ -1688,7 +1692,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) NSInteger diff, i; NSUInteger count = [_selectedRows count]; BOOL notified = NO; - diff = _currentRow - _originalRow; + diff = _currentRow - _originalRow; if (diff >= 0) { @@ -1703,7 +1707,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) if (*_selectedRow == -1) { NSUInteger first = [_selectedRows firstIndex]; - + if (first == NSNotFound) { NSLog(@"error!"); @@ -1729,7 +1733,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) if (*_selectedRow == -1) { NSUInteger first = [_selectedRows firstIndex]; - + if (first == NSNotFound) { NSLog(@"error!"); @@ -1747,7 +1751,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) } } else // new multiple antiselection, after first pass - { + { NSInteger oldDiff, newDiff, i; NSUInteger count = [_selectedRows count]; oldDiff = _oldRow - _originalRow; @@ -1761,7 +1765,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) for (i = _oldRow + 1; i <= _currentRow; i++) { if ((count > 1) && [tv _unselectRow: i]) - { + { notified = YES; count--; } @@ -1770,14 +1774,14 @@ void quick_sort_internal(columnSorting *data, int p, int r) if (*_selectedRow == -1) { NSUInteger first = [_selectedRows firstIndex]; - + if (first == NSNotFound) - { + { NSLog(@"error!"); *_selectedRow = -1; } else - { + { *_selectedRow = first; } } @@ -1819,7 +1823,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) for (i = _oldRow - 1; i >= _currentRow; i--) { if ((count > 1) && [tv _unselectRow: i]) - { + { notified = YES; count--; } @@ -1828,14 +1832,14 @@ void quick_sort_internal(columnSorting *data, int p, int r) if (*_selectedRow == -1) { NSUInteger first = [_selectedRows firstIndex]; - + if (first == NSNotFound) - { + { NSLog(@"error!"); *_selectedRow = -1; } else - { + { *_selectedRow = first; } } @@ -1873,7 +1877,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) else if (oldDiff <= 0 && newDiff >= 0) { BOOL notified = NO; - + // we're reducing the selection { for (i = _oldRow; i < _originalRow; i++) @@ -1904,7 +1908,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) if (*_selectedRow == -1) { NSUInteger first = [_selectedRows firstIndex]; - + if (first == NSNotFound) { NSLog(@"error!"); @@ -1924,7 +1928,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) else if (oldDiff >= 0 && newDiff <= 0) { BOOL notified = NO; - + // we're reducing the selection { for (i = _oldRow; i > _originalRow; i--) @@ -1955,7 +1959,7 @@ void quick_sort_internal(columnSorting *data, int p, int r) if (*_selectedRow == -1) { NSUInteger first = [_selectedRows firstIndex]; - + if (first == NSNotFound) { NSLog(@"error!"); @@ -2006,7 +2010,7 @@ - (void) _autoloadTableColumns; @end -@implementation NSTableView +@implementation NSTableView + (void) initialize { @@ -2022,7 +2026,7 @@ + (void) initialize } /* - * Initializing/Releasing + * Initializing/Releasing */ - (void) _initDefaults @@ -2048,7 +2052,7 @@ - (void) _initDefaults _selectedColumn = -1; _selectedRow = -1; _highlightedTableColumn = nil; - _draggingSourceOperationMaskForLocal = NSDragOperationCopy + _draggingSourceOperationMaskForLocal = NSDragOperationCopy | NSDragOperationLink | NSDragOperationGeneric | NSDragOperationPrivate; _draggingSourceOperationMaskForRemote = NSDragOperationNone; ASSIGN(_sortDescriptors, [NSArray array]); @@ -2058,6 +2062,7 @@ - (void) _initDefaults _registeredNibs = [[NSMutableDictionary alloc] init]; _registeredViews = [[NSMutableDictionary alloc] init]; _rowViews = [[NSMutableDictionary alloc] init]; + _dataSource_editable = YES; } - (id) initWithFrame: (NSRect)frameRect @@ -2067,8 +2072,8 @@ - (id) initWithFrame: (NSRect)frameRect return self; [self _initDefaults]; - ASSIGN(_gridColor, [NSColor gridColor]); - ASSIGN(_backgroundColor, [NSColor controlBackgroundColor]); + ASSIGN(_gridColor, [NSColor gridColor]); + ASSIGN(_backgroundColor, [NSColor controlBackgroundColor]); ASSIGN(_tableColumns, [NSMutableArray array]); _headerView = [NSTableHeaderView new]; @@ -2098,7 +2103,7 @@ - (void) dealloc TEST_RELEASE (_cornerView); if (_autosaveTableColumns == YES) { - [nc removeObserver: self + [nc removeObserver: self name: NSTableViewColumnDidResizeNotification object: self]; } @@ -2121,7 +2126,7 @@ - (BOOL) isFlipped } /* - * Table Dimensions + * Table Dimensions */ - (NSInteger) numberOfColumns @@ -2134,8 +2139,8 @@ - (NSInteger) numberOfRows return [self _numRows]; } -/* - * Columns +/* + * Columns */ - (void) addTableColumn: (NSTableColumn *)aColumn @@ -2148,10 +2153,10 @@ - (void) addTableColumn: (NSTableColumn *)aColumn _columnOrigins = NSZoneRealloc (NSDefaultMallocZone (), _columnOrigins, (sizeof (CGFloat)) * _numberOfColumns); } - else + else { _columnOrigins = NSZoneMalloc (NSDefaultMallocZone (), sizeof (CGFloat)); - } + } [self tile]; } @@ -2187,16 +2192,16 @@ - (void) removeTableColumn: (NSTableColumn *)aColumn _columnOrigins = NSZoneRealloc (NSDefaultMallocZone (), _columnOrigins, (sizeof (CGFloat)) * _numberOfColumns); } - else + else { NSZoneFree (NSDefaultMallocZone (), _columnOrigins); - } + } [self tile]; } - (void) moveColumn: (NSInteger)columnIndex toColumn: (NSInteger)newIndex { - /* The range of columns which need to be shifted, + /* The range of columns which need to be shifted, extremes included */ NSInteger minRange, maxRange; /* Amount of shift for these columns */ @@ -2235,7 +2240,7 @@ - (void) moveColumn: (NSInteger)columnIndex toColumn: (NSInteger)newIndex { _selectedColumn = newIndex; } - else if ((_selectedColumn >= minRange) && (_selectedColumn <= maxRange)) + else if ((_selectedColumn >= minRange) && (_selectedColumn <= maxRange)) { _selectedColumn += shift; } @@ -2256,7 +2261,7 @@ - (void) moveColumn: (NSInteger)columnIndex toColumn: (NSInteger)newIndex { _editedColumn = newIndex; } - else if ((_editedColumn >= minRange) && (_editedColumn <= maxRange)) + else if ((_editedColumn >= minRange) && (_editedColumn <= maxRange)) { _editedColumn += shift; } @@ -2280,14 +2285,14 @@ - (void) moveColumn: (NSInteger)columnIndex toColumn: (NSInteger)newIndex /* Post notification */ [self _postColumnDidMoveNotificationWithOldIndex: columnIndex - newIndex: newIndex]; + newIndex: newIndex]; [self _autosaveTableColumns]; } - (NSArray *) tableColumns { - return AUTORELEASE ([_tableColumns mutableCopyWithZone: + return AUTORELEASE ([_tableColumns mutableCopyWithZone: NSDefaultMallocZone ()]); } @@ -2296,15 +2301,15 @@ - (NSInteger) columnWithIdentifier: (id)identifier NSEnumerator *enumerator = [_tableColumns objectEnumerator]; NSTableColumn *tb; NSInteger return_value = 0; - + while ((tb = [enumerator nextObject]) != nil) { // Also handle a nil identifier. - if ((identifier == [tb identifier]) || - [[tb identifier] isEqual: identifier]) - return return_value; + if ((identifier == [tb identifier]) || + [[tb identifier] isEqual: identifier]) + return return_value; else - return_value++; + return_value++; } return -1; } @@ -2315,12 +2320,12 @@ - (NSTableColumn *) tableColumnWithIdentifier:(id)anObject if (indexOfColumn == -1) return nil; - else + else return [_tableColumns objectAtIndex: indexOfColumn]; } -/* - * Data Source +/* + * Data Source */ - (id) dataSource @@ -2338,28 +2343,35 @@ - (void) setDataSource: (id)anObject // If we have content binding the data source is used only // like a delegate - theBinding = [GSKeyValueBinding getBinding: NSContentBinding - forObject: self]; + 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:"]; - */ - } - } - - _dataSource_editable = [anObject respondsToSelector: sel_c]; + { + 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:"]; + */ + } + + _dataSource_editable = [anObject respondsToSelector: sel_c]; + } + else + { + /* Based on testing on macOS, this should default to YES if there is a binding... + */ + _dataSource_editable = YES; + } + /* We do *not* retain the dataSource, it's like a delegate */ _dataSource = anObject; @@ -2368,8 +2380,8 @@ - (void) setDataSource: (id)anObject [self reloadData]; } -/* - * Loading data +/* + * Loading data */ - (void) reloadData @@ -2380,13 +2392,13 @@ - (void) reloadData [_pathsToViews removeAllObjects]; [_rowViews removeAllObjects]; } - + [self noteNumberOfRowsChanged]; [self setNeedsDisplay: YES]; } -/* - * Target-action +/* + * Target-action */ - (void) setAction: (SEL)aSelector @@ -2437,15 +2449,15 @@ - (void) _sendDoubleActionForColumn: (NSInteger)columnIndex { _clickedColumn = columnIndex; _clickedRow = -1; - [self sendAction: _doubleAction to: _target]; + [self sendAction: _doubleAction to: _target]; } /* - * And this when it gets a simple click which turns out to be for + * And this when it gets a simple click which turns out to be for * selecting/deselecting a column. - * We don't support subtracting a column from the selection (Cocoa doesn't + * We don't support subtracting a column from the selection (Cocoa doesn't * either). - * However we support adding a distinct column with the control key (unlike + * However we support adding a distinct column with the control key (unlike * Cocoa where the user can only make column range selection). */ - (void) _selectColumn: (NSInteger)columnIndex @@ -2456,7 +2468,7 @@ - (void) _selectColumn: (NSInteger)columnIndex && _allowsMultipleSelection && [oldIndexes count] > 0); BOOL addSingle = ((modifiers & NSControlKeyMask) && _allowsMultipleSelection); - BOOL shouldSelect = ([self _shouldSelectionChange] + BOOL shouldSelect = ([self _shouldSelectionChange] && [self _shouldSelectTableColumn: [_tableColumns objectAtIndex: columnIndex]]); NSIndexSet *newIndexes = [NSIndexSet indexSetWithIndex: columnIndex]; @@ -2472,7 +2484,7 @@ - (void) _selectColumn: (NSInteger)columnIndex /* Single select has priority over range select when both modifiers are pressed */ if (addSingle) - { + { [self selectColumnIndexes: newIndexes byExtendingSelection: YES]; } else if (addRange) @@ -2481,19 +2493,19 @@ - (void) _selectColumn: (NSInteger)columnIndex NSUInteger lastIndex = [oldIndexes lastIndex]; NSRange range; - /* We extend the selection to the left or the right of the last selected - column. */ + /* We extend the selection to the left or the right of the last selected + column. */ if (columnIndex > [self selectedColumn]) - { - lastIndex = columnIndex; - } + { + lastIndex = columnIndex; + } else - { - firstIndex = columnIndex; - } + { + firstIndex = columnIndex; + } range = NSMakeRange(firstIndex, lastIndex - firstIndex + 1); - newIndexes = [NSIndexSet indexSetWithIndexesInRange: range]; + newIndexes = [NSIndexSet indexSetWithIndexesInRange: range]; [self selectColumnIndexes: newIndexes byExtendingSelection: YES]; } else @@ -2504,8 +2516,8 @@ - (void) _selectColumn: (NSInteger)columnIndex /* - *Configuration - */ + *Configuration + */ - (void) setAllowsColumnReordering: (BOOL)flag { @@ -2557,8 +2569,8 @@ - (BOOL) allowsColumnSelection return _allowsColumnSelection; } -/* - * Drawing Attributes +/* + * Drawing Attributes */ - (void) setIntercellSpacing: (NSSize)aSize @@ -2626,7 +2638,7 @@ - (NSTableViewSelectionHighlightStyle) selectionHighlightStyle /* * Selecting Columns and Rows */ -- (void) selectColumn: (NSInteger)columnIndex +- (void) selectColumn: (NSInteger)columnIndex byExtendingSelection: (BOOL)flag { if (columnIndex < 0 || columnIndex > _numberOfColumns) @@ -2651,9 +2663,9 @@ - (void) selectColumn: (NSInteger)columnIndex { [self validateEditing]; [self abortEditing]; - } + } return; - } + } /* If _numberOfColumns == 1, we can skip trying to deselect the only column - because we have been called to select it. */ @@ -2667,7 +2679,7 @@ - (void) selectColumn: (NSInteger)columnIndex if (_allowsMultipleSelection == NO) { [NSException raise: NSInternalInconsistencyException - format: @"Can not extend selection in table view when multiple selection is disabled"]; + format: @"Can not extend selection in table view when multiple selection is disabled"]; } } @@ -2678,7 +2690,7 @@ - (void) selectColumn: (NSInteger)columnIndex [self abortEditing]; } - /* Now select the column and post notification only if needed */ + /* Now select the column and post notification only if needed */ if ([_selectedColumns containsIndex: columnIndex] == NO) { [_selectedColumns addIndex: columnIndex]; @@ -2687,7 +2699,7 @@ - (void) selectColumn: (NSInteger)columnIndex [self setNeedsDisplayInRect: [self rectOfColumn: columnIndex]]; if (_headerView) { - [_headerView setNeedsDisplayInRect: + [_headerView setNeedsDisplayInRect: [_headerView headerRectOfColumn: columnIndex]]; } [self _postSelectionDidChangeNotification]; @@ -2735,7 +2747,7 @@ - (void) selectRow: (NSInteger)rowIndex /* reset the _clickedRow for keyboard navigation */ _clickedRow = rowIndex; return; - } + } /* If _numberOfRows == 1, we can skip trying to deselect the only row - because we have been called to select it. */ @@ -2749,7 +2761,7 @@ - (void) selectRow: (NSInteger)rowIndex if (_allowsMultipleSelection == NO) { [NSException raise: NSInternalInconsistencyException - format: @"Can not extend selection in table view when multiple selection is disabled"]; + format: @"Can not extend selection in table view when multiple selection is disabled"]; } } @@ -2758,12 +2770,12 @@ - (void) selectRow: (NSInteger)rowIndex { [self validateEditing]; [self abortEditing]; - } + } /* * Now select the row and post notification only if needed * also update the _clickedRow for keyboard navigation. - */ + */ if ([self _selectUnselectedRow: rowIndex]) { _clickedRow = rowIndex; @@ -2781,7 +2793,7 @@ - (void) selectColumnIndexes: (NSIndexSet *)indexes byExtendingSelection: (BOOL) BOOL empty = ([indexes firstIndex] == NSNotFound); BOOL changed = NO; NSUInteger col; - + if (!_selectingColumns) { _selectingColumns = YES; @@ -2797,7 +2809,7 @@ - (void) selectColumnIndexes: (NSIndexSet *)indexes byExtendingSelection: (BOOL) [self validateEditing]; [self abortEditing]; } - + if (extend == NO) { /* If the current selection is the one we want, just ends editing @@ -2805,7 +2817,7 @@ - (void) selectColumnIndexes: (NSIndexSet *)indexes byExtendingSelection: (BOOL) * a NSTableViewSelectionDidChangeNotification. * This behaviour is required by the specifications */ if ([_selectedColumns isEqual: indexes]) - { + { if (!empty) { _selectedColumn = [indexes lastIndex]; @@ -2820,31 +2832,31 @@ - (void) selectColumnIndexes: (NSIndexSet *)indexes byExtendingSelection: (BOOL) if (!empty) { if ([indexes lastIndex] >= _numberOfColumns) - { - // Cocoa returns in this case... - NSDebugLLog(@"NSTableView", @"Column index %lu out of table in selectColumn", - [indexes lastIndex]); - return; + { + // Cocoa returns in this case... + NSDebugLLog(@"NSTableView", @"Column index %lu out of table in selectColumn", + [indexes lastIndex]); + return; } - /* This check is not fully correct, as both sets may contain just + /* This check is not fully correct, as both sets may contain just the same entry, but works according to the old specification. */ - if (_allowsMultipleSelection == NO && + if (_allowsMultipleSelection == NO && [_selectedColumns count] + [indexes count] > 1) - { + { [NSException raise: NSInternalInconsistencyException - format: @"Can not set multiple selection in table view when multiple selection is disabled"]; + format: @"Can not set multiple selection in table view when multiple selection is disabled"]; } col = [indexes firstIndex]; while (col != NSNotFound) - { + { if (![_selectedColumns containsIndex: col]) { [self setNeedsDisplayInRect: [self rectOfColumn: col]]; if (_headerView) - { - [_headerView setNeedsDisplayInRect: + { + [_headerView setNeedsDisplayInRect: [_headerView headerRectOfColumn: col]]; } changed = YES; @@ -2866,7 +2878,7 @@ - (void) selectRowIndexes: (NSIndexSet *)indexes byExtendingSelection: (BOOL)ext BOOL empty = ([indexes firstIndex] == NSNotFound); BOOL changed = NO; NSUInteger row; - + if (_selectingColumns) { _selectingColumns = NO; @@ -2882,7 +2894,7 @@ - (void) selectRowIndexes: (NSIndexSet *)indexes byExtendingSelection: (BOOL)ext [self validateEditing]; [self abortEditing]; } - + if (extend == NO) { /* If the current selection is the one we want, just ends editing @@ -2890,7 +2902,7 @@ - (void) selectRowIndexes: (NSIndexSet *)indexes byExtendingSelection: (BOOL)ext * a NSTableViewSelectionDidChangeNotification. * This behaviour is required by the specifications */ if ([_selectedRows isEqual: indexes]) - { + { if (!empty) { _selectedRow = [indexes lastIndex]; @@ -2905,23 +2917,23 @@ - (void) selectRowIndexes: (NSIndexSet *)indexes byExtendingSelection: (BOOL)ext if (!empty) { if ([indexes lastIndex] >= _numberOfRows) - { + { [NSException raise: NSInvalidArgumentException - format: @"Row index out of table in selectRow"]; + format: @"Row index out of table in selectRow"]; } - /* This check is not fully correct, as both sets may contain just + /* This check is not fully correct, as both sets may contain just the same entry, but works according to the old specification. */ - if (_allowsMultipleSelection == NO && + if (_allowsMultipleSelection == NO && [_selectedRows count] + [indexes count] > 1) - { + { [NSException raise: NSInternalInconsistencyException - format: @"Can not set multiple selection in table view when multiple selection is disabled"]; + format: @"Can not set multiple selection in table view when multiple selection is disabled"]; } row = [indexes firstIndex]; while (row != NSNotFound) - { + { if (![_selectedRows containsIndex: row]) { [self setNeedsDisplayInRect: [self rectOfRow: row]]; @@ -2964,7 +2976,7 @@ - (void) deselectColumn: (NSInteger)columnIndex [self validateEditing]; [self abortEditing]; } - + _selectingColumns = YES; [_selectedColumns removeIndex: columnIndex]; @@ -2975,34 +2987,34 @@ - (void) deselectColumn: (NSInteger)columnIndex NSUInteger greater = [_selectedColumns indexGreaterThanIndex: columnIndex]; if (less == NSNotFound) - { + { if (greater == NSNotFound) { _selectedColumn = -1; } else { - _selectedColumn = greater; - } + _selectedColumn = greater; + } } else if (greater == NSNotFound) - { + { _selectedColumn = less; } else if (columnIndex - less > greater - columnIndex) - { - _selectedColumn = greater; + { + _selectedColumn = greater; } - else - { + else + { _selectedColumn = less; } } - + [self setNeedsDisplayInRect: [self rectOfColumn: columnIndex]]; if (_headerView) { - [_headerView setNeedsDisplayInRect: + [_headerView setNeedsDisplayInRect: [_headerView headerRectOfColumn: columnIndex]]; } @@ -3032,26 +3044,26 @@ - (void) deselectRow: (NSInteger)rowIndex NSUInteger greater = [_selectedRows indexGreaterThanIndex: rowIndex]; if (less == NSNotFound) - { + { if (greater == NSNotFound) { _selectedRow = -1; } else { - _selectedRow = greater; - } + _selectedRow = greater; + } } else if (greater == NSNotFound) - { + { _selectedRow = less; } else if (rowIndex - less > greater - rowIndex) - { - _selectedRow = greater; + { + _selectedRow = greater; } - else - { + else + { _selectedRow = less; } } @@ -3134,8 +3146,8 @@ - (void) selectAll: (id) sender } { - NSInteger row; - + NSInteger row; + for (row = 0; row < _numberOfRows; row++) { if ([self _shouldSelectRow: row] == NO) @@ -3149,7 +3161,7 @@ - (void) selectAll: (id) sender { [self validateEditing]; [self abortEditing]; - } + } /* Do the real selection */ if (_selectingColumns == YES) @@ -3162,7 +3174,7 @@ - (void) selectAll: (id) sender [_selectedRows removeAllIndexes]; [_selectedRows addIndexesInRange: NSMakeRange(0, _numberOfRows)]; } - + [self setNeedsDisplay: YES]; [self _postSelectionDidChangeNotification]; } @@ -3176,13 +3188,13 @@ - (void) deselectAll: (id) sender { return; } - + if (_textObject != nil) { [self validateEditing]; [self abortEditing]; } - + if (([_selectedColumns count] > 0) || ([_selectedRows count] > 0)) { [_selectedColumns removeAllIndexes]; @@ -3201,8 +3213,8 @@ - (void) deselectAll: (id) sender } } -/* - * Grid Drawing attributes +/* + * Grid Drawing attributes */ - (void) setDrawsGrid: (BOOL)flag @@ -3245,10 +3257,10 @@ - (NSCell *) preparedCellAtColumn: (NSInteger)columnIndex row: (NSInteger)rowInd NSCell *cell = nil; if (_viewBased == NO) - { + { NSTableColumn *tb = [_tableColumns objectAtIndex: columnIndex]; - if ([_delegate respondsToSelector: + if ([_delegate respondsToSelector: @selector(tableView:dataCellForTableColumn:row:)]) { cell = [_delegate tableView: self dataCellForTableColumn: tb @@ -3259,21 +3271,21 @@ - (NSCell *) preparedCellAtColumn: (NSInteger)columnIndex row: (NSInteger)rowInd cell = [tb dataCellForRow: rowIndex]; } } - + return cell; } -/* - * Editing Cells +/* + * Editing Cells */ - (BOOL) abortEditing -{ +{ if (_textObject) { [_editedCell endEditing: _textObject]; DESTROY(_editedCell); - [self setNeedsDisplayInRect: + [self setNeedsDisplayInRect: [self frameOfCellAtColumn: _editedColumn row: _editedRow]]; _editedRow = -1; _editedColumn = -1; @@ -3303,77 +3315,75 @@ - (void) validateEditing // Avoid potential recursive sequences... _isValidating = YES; - + formatter = [_editedCell formatter]; string = AUTORELEASE([[_textObject text] copy]); if (formatter != nil) - { - NSString *error; - - if ([formatter getObjectValue: &newObjectValue - forString: string - errorDescription: &error] == YES) - { - [_editedCell setObjectValue: newObjectValue]; - - if (_dataSource_editable) - { - NSTableColumn *tb; - - tb = [_tableColumns objectAtIndex: _editedColumn]; - - [self _setObjectValue: newObjectValue - forTableColumn: tb - row: _editedRow]; - } - - _isValidating = NO; - return; - } - else - { - SEL sel = @selector(control:didFailToFormatString:errorDescription:); - - if ([_delegate respondsToSelector: sel]) - { - validatedOK = [_delegate control: self - didFailToFormatString: string - errorDescription: error]; - } - // Allow an empty string to fall through - else if (![string isEqualToString: @""]) - { - validatedOK = NO; - } - } - } + { + NSString *error; + + if ([formatter getObjectValue: &newObjectValue + forString: string + errorDescription: &error] == YES) + { + NSTableColumn *tb; + + [_editedCell setObjectValue: newObjectValue]; + tb = [_tableColumns objectAtIndex: _editedColumn]; + + if (_dataSource_editable) + { + [self _setObjectValue: newObjectValue + forTableColumn: tb + row: _editedRow]; + } + + _isValidating = NO; + return; + } + else + { + SEL sel = @selector(control:didFailToFormatString:errorDescription:); + + if ([_delegate respondsToSelector: sel]) + { + validatedOK = [_delegate control: self + didFailToFormatString: string + errorDescription: error]; + } + // Allow an empty string to fall through + else if (![string isEqualToString: @""]) + { + validatedOK = NO; + } + } + } if (validatedOK) - { - [_editedCell setStringValue: string]; - - if (_dataSource_editable) - { - NSTableColumn *tb; - - tb = [_tableColumns objectAtIndex: _editedColumn]; - - [self _setObjectValue: string // newObjectValue - forTableColumn: tb - row: _editedRow]; - } - } + { + NSTableColumn *tb; + + [_editedCell setStringValue: string]; + tb = [_tableColumns objectAtIndex: _editedColumn]; + + if (_dataSource_editable) + { + [self _setObjectValue: string + forTableColumn: tb + row: _editedRow]; + } + } // Avoid potential recursive sequences... _isValidating = NO; } } -- (void) editColumn: (NSInteger) columnIndex - row: (NSInteger) rowIndex - withEvent: (NSEvent *) theEvent - select: (BOOL) flag +- (void) editColumn: (NSInteger) columnIndex + row: (NSInteger) rowIndex + withEvent: (NSEvent *) theEvent + select: (BOOL) flag { NSText *t; NSTableColumn *tb; @@ -3386,13 +3396,13 @@ - (void) editColumn: (NSInteger) columnIndex format:@"Attempted to edit unselected row"]; } - if (rowIndex < 0 || rowIndex >= _numberOfRows + if (rowIndex < 0 || rowIndex >= _numberOfRows || columnIndex < 0 || columnIndex >= _numberOfColumns) { [NSException raise: NSInvalidArgumentException format: @"Row/column out of index in edit"]; } - + [self scrollRowToVisible: rowIndex]; [self scrollColumnToVisible: columnIndex]; @@ -3413,7 +3423,7 @@ - (void) editColumn: (NSInteger) columnIndex return; } } - + _editedRow = rowIndex; _editedColumn = columnIndex; @@ -3424,7 +3434,7 @@ - (void) editColumn: (NSInteger) columnIndex tb = [_tableColumns objectAtIndex: columnIndex]; [_editedCell setObjectValue: [self _objectValueForTableColumn: tb row: rowIndex]]; - + // But of course the delegate can mess it up if it wants [self _willDisplayCell: _editedCell forTableColumn: tb @@ -3468,12 +3478,12 @@ before the actual editing is started (otherwise you easily end up delegate: self event: theEvent]; } - return; + return; } - (NSInteger) editedRow { - return _editedRow; + return _editedRow; } - (NSInteger) editedColumn @@ -3483,29 +3493,29 @@ - (NSInteger) editedColumn static inline NSTimeInterval computePeriod(NSPoint mouseLocationWin, - CGFloat minYVisible, - CGFloat maxYVisible) + CGFloat minYVisible, + CGFloat maxYVisible) { - /* We have three zones of speed. + /* We have three zones of speed. 0 - 50 pixels: period 0.2 50 - 100 pixels: period 0.1 100 - 150 pixels: period 0.01 */ CGFloat distance = 0; - - if (mouseLocationWin.y < minYVisible) + + if (mouseLocationWin.y < minYVisible) { - distance = minYVisible - mouseLocationWin.y; + distance = minYVisible - mouseLocationWin.y; } else if (mouseLocationWin.y > maxYVisible) { distance = mouseLocationWin.y - maxYVisible; } - + if (distance < 50) return 0.2; else if (distance < 100) return 0.1; - else + else return 0.01; } @@ -3517,25 +3527,25 @@ - (void) _trackCellAtColumn: (NSInteger) columnIndex { return; } - + /* we should copy the cell here, as we do on editing. otherwise validation on a cell being edited could cause the cell we are selecting to get it's objectValue */ NSCell *cell = [[self preparedCellAtColumn: columnIndex row: rowIndex] copy]; NSTableColumn *tb = [_tableColumns objectAtIndex: columnIndex]; id originalValue = RETAIN([self _objectValueForTableColumn: tb - row: rowIndex]); - [cell setObjectValue: originalValue]; + row: rowIndex]); + [cell setObjectValue: originalValue]; NSRect cellFrame = [self frameOfCellAtColumn: columnIndex - row: rowIndex]; + row: rowIndex]; [cell setHighlighted: YES]; [self setNeedsDisplayInRect: cellFrame]; /* give delegate a chance to i.e set target */ [self _willDisplayCell: cell forTableColumn: tb - row: rowIndex]; - - if ([cell trackMouse: theEvent + row: rowIndex]; + + if ([cell trackMouse: theEvent inRect: cellFrame ofView: self untilMouseUp: [[cell class] @@ -3546,13 +3556,13 @@ - (void) _trackCellAtColumn: (NSInteger) columnIndex /* don't check editability that only pertains to editColumn:... */ if (originalValue != newValue && ![originalValue isEqual: newValue]) - { - [self _setObjectValue: newValue + { + [self _setObjectValue: newValue forTableColumn: tb row: rowIndex]; } } - RELEASE(originalValue); + RELEASE(originalValue); [cell setHighlighted: NO]; [self setNeedsDisplayInRect: cellFrame]; RELEASE(cell); @@ -3561,8 +3571,8 @@ - (void) _trackCellAtColumn: (NSInteger) columnIndex - (BOOL) _startDragOperationWithEvent: (NSEvent *) theEvent { NSPasteboard *pboard = [NSPasteboard pasteboardWithName: NSDragPboard]; - NSPoint startPoint = [self convertPoint: [theEvent locationInWindow] - fromView: nil]; + NSPoint startPoint = [self convertPoint: [theEvent locationInWindow] + fromView: nil]; if ([self canDragRowsWithIndexes: _selectedRows atPoint: startPoint] && [self _writeRows: _selectedRows toPasteboard: pboard]) @@ -3574,9 +3584,9 @@ - (BOOL) _startDragOperationWithEvent: (NSEvent *) theEvent NSArray *cols = nil; dragImage = [self dragImageForRowsWithIndexes: _selectedRows - tableColumns: cols - event: theEvent - offset: &p]; + tableColumns: cols + event: theEvent + offset: &p]; /* * Store image offset in s ... the returned @@ -3597,14 +3607,14 @@ - (BOOL) _startDragOperationWithEvent: (NSEvent *) theEvent p = startPoint; p.x += s.width; p.y += s.height; - + [self dragImage: dragImage at: p offset: NSMakeSize(0, 0) event: theEvent pasteboard: pboard - source: self + source: self slideBack: YES]; return YES; } @@ -3625,56 +3635,56 @@ - (void) mouseDown: (NSEvent *)theEvent // Pathological case -- ignore mouse down if ((_numberOfRows == 0) || (_numberOfColumns == 0)) { - return; + return; } - + /* Stop editing if any */ if (_textObject != nil) { - if (_editedCell != nil - && [_editedCell isEntryAcceptable:[_textObject text]] == NO) - { - NSBeep(); - return; - } + if (_editedCell != nil + && [_editedCell isEntryAcceptable:[_textObject text]] == NO) + { + NSBeep(); + return; + } [self validateEditing]; [self abortEditing]; - } + } // Determine row and column which were clicked location = [self convertPoint: initialLocation fromView: nil]; _clickedRow = [self rowAtPoint: location]; _clickedColumn = [self columnAtPoint: location]; - + if ([theEvent type] == NSLeftMouseDown && clickCount > 1) { // Double-click event if (![self isRowSelected: _clickedRow]) - { + { return; } if (![self _isCellSelectableColumn: _clickedColumn row: _clickedRow]) - { + { // Send double-action but don't edit [self _trackCellAtColumn: _clickedColumn - row: _clickedRow - withEvent: theEvent]; + row: _clickedRow + withEvent: theEvent]; if (_clickedRow != -1) [self sendAction: _doubleAction to: _target]; } else if (clickCount == 2) // if < 2, dont want to abort editing - { + { // It is OK to edit column. Go on, do it. - [self editColumn: _clickedColumn + [self editColumn: _clickedColumn row: _clickedRow withEvent: theEvent select: YES]; } } - else + else { #define COMPUTE_NEW_SELECTION do { \ if (originalRow == -1) \ @@ -3697,9 +3707,9 @@ - (void) mouseDown: (NSEvent *)theEvent // Selection NSUInteger modifiers = [theEvent modifierFlags]; - NSUInteger eventMask = (NSLeftMouseUpMask + NSUInteger eventMask = (NSLeftMouseUpMask | NSLeftMouseDownMask - | NSLeftMouseDraggedMask + | NSLeftMouseDraggedMask | NSPeriodicMask); unsigned selectionMode = 0; NSPoint mouseLocationWin; @@ -3733,12 +3743,12 @@ - (void) mouseDown: (NSEvent *)theEvent { selectionMode |= ALLOWS_EMPTY; } - + if (modifiers & NSShiftKeyMask) { selectionMode |= SHIFT_DOWN; } - + if (![_selectedRows containsIndex: _clickedRow]) { selectionMode |= ADDING_ROW; @@ -3754,7 +3764,7 @@ - (void) mouseDown: (NSEvent *)theEvent selectionMode |= ADDING_ROW; } } - + // is the delegate ok for a new selection ? if ([self _shouldSelectionChange] == NO) { @@ -3777,15 +3787,15 @@ - (void) mouseDown: (NSEvent *)theEvent */ CREATE_AUTORELEASE_POOL(arp); NSEventType eventType = [lastEvent type]; - - mouseLocationWin = [lastEvent locationInWindow]; - mouseLocationView = [self convertPoint: mouseLocationWin + + mouseLocationWin = [lastEvent locationInWindow]; + mouseLocationView = [self convertPoint: mouseLocationWin fromView: nil]; - + switch (eventType) { case NSLeftMouseUp: - if ((mouseLocationWin.y > minYVisible) + if ((mouseLocationWin.y > minYVisible) && (mouseLocationWin.y < maxYVisible)) { // mouse up within table @@ -3797,19 +3807,19 @@ - (void) mouseDown: (NSEvent *)theEvent mouseLocationView.x = _bounds.origin.x; oldRow = currentRow; currentRow = [self rowAtPoint: mouseLocationView]; - + if (oldRow != currentRow) { COMPUTE_NEW_SELECTION; } - + if (!didTrackCell && currentRow == _clickedRow) { /* * a dragging operation is still possible so * selections were never dragged, * and a drag operation was never attempted. - * the cell was clicked, + * the cell was clicked, * track the cell with the old mouseDown event * then it will get the current event mouseUp. */ @@ -3829,7 +3839,7 @@ - (void) mouseDown: (NSEvent *)theEvent case NSLeftMouseDown: case NSLeftMouseDragged: if (fabs(mouseLocationWin.x - initialLocation.x) > 1 - || fabs(mouseLocationWin.y - initialLocation.y) > 1) + || fabs(mouseLocationWin.y - initialLocation.y) > 1) { mouseMoved = YES; } @@ -3837,19 +3847,19 @@ - (void) mouseDown: (NSEvent *)theEvent if (dragOperationPossible == YES) { if ([_selectedRows containsIndex:_clickedRow] == NO - || (_verticalMotionDrag == NO - && fabs(mouseLocationWin.y - initialLocation.y) > 2)) + || (_verticalMotionDrag == NO + && fabs(mouseLocationWin.y - initialLocation.y) > 2)) { dragOperationPossible = NO; } - else if ((fabs(mouseLocationWin.x - initialLocation.x) >= 4) - || (_verticalMotionDrag - && fabs(mouseLocationWin.y - initialLocation.y) >= 4)) + else if ((fabs(mouseLocationWin.x - initialLocation.x) >= 4) + || (_verticalMotionDrag + && fabs(mouseLocationWin.y - initialLocation.y) >= 4)) { if ([self _startDragOperationWithEvent: theEvent]) { - RELEASE(oldSelectedRows); - IF_NO_GC(DESTROY(arp)); + RELEASE(oldSelectedRows); + IF_NO_GC(DESTROY(arp)); return; } else @@ -3858,7 +3868,7 @@ - (void) mouseDown: (NSEvent *)theEvent } } } - else if ((mouseLocationWin.y > minYVisible) + else if ((mouseLocationWin.y > minYVisible) && (mouseLocationWin.y < maxYVisible)) { // mouse dragged within table @@ -3875,25 +3885,25 @@ - (void) mouseDown: (NSEvent *)theEvent { COMPUTE_NEW_SELECTION; } - + if (eventType == NSLeftMouseDown) { /* * Can never get here from a dragging source * so they need to track in mouse up. */ - NSCell *cell = [self preparedCellAtColumn: _clickedColumn + NSCell *cell = [self preparedCellAtColumn: _clickedColumn row: _clickedRow]; - + [self _trackCellAtColumn: _clickedColumn row: _clickedRow withEvent: theEvent]; didTrackCell = YES; - + if ([[cell class] prefersTrackingUntilMouseUp]) { /* the mouse could have gone up outside of the cell - * avoid selecting the row under mouse cursor */ + * avoid selecting the row under mouse cursor */ sendAction = YES; done = YES; } @@ -3909,13 +3919,13 @@ - (void) mouseDown: (NSEvent *)theEvent else { // Mouse dragged out of the table - NSTimeInterval period = computePeriod(mouseLocationWin, - minYVisible, + NSTimeInterval period = computePeriod(mouseLocationWin, + minYVisible, maxYVisible); if (startedPeriodicEvents == YES) { - /* Check - if the mouse did not change zone, + /* Check - if the mouse did not change zone, we do nothing */ if (period == oldPeriod) break; @@ -3927,7 +3937,7 @@ - (void) mouseDown: (NSEvent *)theEvent [NSEvent startPeriodicEventsAfterDelay: 0 withPeriod: oldPeriod]; startedPeriodicEvents = YES; - if (mouseLocationWin.y <= minYVisible) + if (mouseLocationWin.y <= minYVisible) mouseBelowView = YES; else mouseBelowView = NO; @@ -3966,7 +3976,7 @@ - (void) mouseDown: (NSEvent *)theEvent default: break; } - + if (done == NO) { /* in certain cases we are working with events that have already @@ -3974,11 +3984,11 @@ - (void) mouseDown: (NSEvent *)theEvent * getNextEvent is set to NO, use the current event. */ if (getNextEvent == YES) - { - lastEvent = [NSApp nextEventMatchingMask: eventMask + { + lastEvent = [NSApp nextEventMatchingMask: eventMask untilDate: distantFuture - inMode: NSEventTrackingRunLoopMode - dequeue: YES]; + inMode: NSEventTrackingRunLoopMode + dequeue: YES]; } else { @@ -3996,11 +4006,11 @@ - (void) mouseDown: (NSEvent *)theEvent { [self _postSelectionDidChangeNotification]; } - + RELEASE(oldSelectedRows); if (!mouseMoved) - sendAction = YES; + sendAction = YES; /* If this was a simple click (ie. no dragging), we send our action. */ if (sendAction) @@ -4016,7 +4026,7 @@ - (void) mouseDown: (NSEvent *)theEvent [self sendAction: _action to: _target]; } } - + _clickedRow = _selectedRow; } @@ -4030,7 +4040,7 @@ - (void) mouseDown: (NSEvent *)theEvent } \ } static BOOL selectContiguousRegion(NSTableView *self, - NSIndexSet *_selectedRows, + NSIndexSet *_selectedRows, NSInteger originalRow, NSInteger oldRow, NSInteger currentRow) @@ -4047,7 +4057,7 @@ static BOOL selectContiguousRegion(NSTableView *self, } /* - * check if the old row is not between the current row and the original row + * check if the old row is not between the current row and the original row * and not the original or current rows */ if (((!((oldRow < currentRow @@ -4060,18 +4070,18 @@ static BOOL selectContiguousRegion(NSTableView *self, || oldRow == originalRow)))) { CHECK_CHANGING(notified); - [self _unselectRow: oldRow]; + [self _unselectRow: oldRow]; } - /* - * there is an off by one here it could be on either end of the loop + /* + * there is an off by one here it could be on either end of the loop * but its either oldRow or currentRow so above we select the currentRow * and possibly unselect the oldRow, one of the two will then - * be selected or deselected again in in this loop + * be selected or deselected again in in this loop */ for (row = first; row < last; row++) { - + /* check if the old row is between the current row and the original row */ if ((row < currentRow && row > originalRow @@ -4098,13 +4108,13 @@ static BOOL selectContiguousRegion(NSTableView *self, { if ([_selectedRows containsIndex: row]) { - CHECK_CHANGING(notified); + CHECK_CHANGING(notified); [self _unselectRow: row]; } } } return notified; -} +} - (void) keyDown: (NSEvent *)theEvent { @@ -4121,13 +4131,13 @@ - (void) keyDown: (NSEvent *)theEvent NSInteger visRows; NSUInteger i; BOOL gotMovementKey = NO; - + // will not contain partial rows. - visRows = visRect.size.height / [self rowHeight]; + visRows = visRect.size.height / [self rowHeight]; - // _clickedRow is stored between calls as the first selected row + // _clickedRow is stored between calls as the first selected row // when doing multiple selection, so the selection may grow and shrink. - + /* * do a contiguous selection on shift */ @@ -4139,7 +4149,7 @@ - (void) keyDown: (NSEvent *)theEvent oldRow = _selectedRow; } } - + /* just scroll don't modify any selection */ if (modifiers & NSControlKeyMask) { @@ -4151,12 +4161,12 @@ - (void) keyDown: (NSEvent *)theEvent unichar c = [characters characterAtIndex: i]; switch (c) - { + { case NSUpArrowFunctionKey: gotMovementKey = YES; - if (modifySelection == NO) + if (modifySelection == NO) { - noModPoint.x = visRect.origin.x; + noModPoint.x = visRect.origin.x; noModPoint.y = NSMinY(visRect) - rowHeight; } else @@ -4166,25 +4176,25 @@ - (void) keyDown: (NSEvent *)theEvent break; case NSDownArrowFunctionKey: gotMovementKey = YES; - if (modifySelection == NO) + if (modifySelection == NO) { - noModPoint.x = visRect.origin.x; + noModPoint.x = visRect.origin.x; noModPoint.y = NSMinY(visRect) + rowHeight; } else { - currentRow++; + currentRow++; } break; case NSPageDownFunctionKey: gotMovementKey = YES; - if (modifySelection == NO) + if (modifySelection == NO) { - noModPoint.x = visRect.origin.x; + noModPoint.x = visRect.origin.x; noModPoint.y = NSMinY(visRect) + (rowHeight * visRows) - rowHeight; } else - { + { currentRow += visRows; } break; @@ -4192,12 +4202,12 @@ - (void) keyDown: (NSEvent *)theEvent gotMovementKey = YES; if (modifySelection == NO) { - noModPoint.x = visRect.origin.x; + noModPoint.x = visRect.origin.x; noModPoint.y = NSMinY(visRect) - (rowHeight * visRows) + rowHeight; } - else + else { - currentRow -= visRows; + currentRow -= visRows; } break; case NSHomeFunctionKey: @@ -4209,7 +4219,7 @@ - (void) keyDown: (NSEvent *)theEvent } else { - currentRow = 0; + currentRow = 0; } break; case NSEndFunctionKey: @@ -4226,9 +4236,9 @@ - (void) keyDown: (NSEvent *)theEvent break; default: break; - } + } } - + /* * if scrolled off the bottom or top the selection. * the modifiers might have changed so recompute the selection. @@ -4247,90 +4257,90 @@ - (void) keyDown: (NSEvent *)theEvent { currentRow = _numberOfRows - 1; } - + if (_numberOfRows) { if (modifySelection) - { + { BOOL notified = NO; - [self _setSelectingColumns: NO]; - - if (originalRow == -1) - { + [self _setSelectingColumns: NO]; + + if (originalRow == -1) + { /* we're not extending any selection */ - originalRow = currentRow; - _clickedRow = currentRow; + originalRow = currentRow; + _clickedRow = currentRow; } - if (_clickedRow == -1) - { + if (_clickedRow == -1) + { /* user must have hit a key with no selected rows */ - _clickedRow = currentRow; + _clickedRow = currentRow; } - + if ((!(modifiers & NSShiftKeyMask && _allowsMultipleSelection))) { NSUInteger first = [_selectedRows firstIndex]; NSUInteger last = [_selectedRows lastIndex]; if ((first == last && first == currentRow) == 0) - { + { CHECK_CHANGING(notified) [self _unselectAllRows]; [self _selectRow: currentRow]; - _selectedRow = currentRow; + _selectedRow = currentRow; } } else - { + { notified = selectContiguousRegion(self, _selectedRows, - originalRow, oldRow, currentRow); + originalRow, oldRow, currentRow); _selectedRow = currentRow; } - + if (notified) - { - [self _postSelectionDidChangeNotification]; + { + [self _postSelectionDidChangeNotification]; } - + [self scrollRowToVisible: currentRow]; [self displayIfNeeded]; - } + } else - { + { noModPoint = [self convertPoint: noModPoint - toView: _super_view]; - noModPoint = + toView: _super_view]; + noModPoint = [(NSClipView *)_super_view constrainScrollPoint: noModPoint]; [(NSClipView *)_super_view scrollToPoint: noModPoint]; } } } -/* - * Auxiliary Components +/* + * Auxiliary Components */ - (void) setHeaderView: (NSTableHeaderView*)aHeaderView { - + if ([_headerView respondsToSelector:@selector(setTableView:)]) [_headerView setTableView: nil]; - + ASSIGN (_headerView, aHeaderView); - + if ([_headerView respondsToSelector:@selector(setTableView:)]) [_headerView setTableView: self]; - + [self tile]; // resizes corner and header views, then displays - + if (_super_view != nil) { id ssv = [_super_view superview]; if ([ssv isKindOfClass: [NSScrollView class]]) - [ssv tile]; // draws any border type over corner and header views - } + [ssv tile]; // draws any border type over corner and header views + } } - (NSTableHeaderView*) headerView @@ -4346,7 +4356,7 @@ - (void) setCornerView: (NSView*)aView { id ssv = [_super_view superview]; if ([ssv isKindOfClass: [NSScrollView class]]) - [ssv tile]; // draws any border type over corner and header views + [ssv tile]; // draws any border type over corner and header views } } @@ -4355,8 +4365,8 @@ - (NSView*) cornerView return _cornerView; } -/* - * Layout +/* + * Layout */ - (NSRect) rectOfColumn: (NSInteger)columnIndex @@ -4409,11 +4419,11 @@ - (NSIndexSet *) columnIndexesInRect: (NSRect)aRect NSTableColumn *tableColumn = [_tableColumns objectAtIndex: i]; if ([tableColumn isHidden]) - [indexes removeIndex: i]; + [indexes removeIndex: i]; } return indexes; -} +} /** Returns the index range of the table columns which intersects the given rect. @@ -4427,7 +4437,7 @@ - (NSRange) columnsInRect: (NSRect)aRect NSRange range; range.location = [self columnAtPoint: aRect.origin]; - range.length = [self columnAtPoint: + range.length = [self columnAtPoint: NSMakePoint (NSMaxX (aRect), _bounds.origin.y)]; range.length -= range.location; range.length += 1; @@ -4440,14 +4450,14 @@ - (NSRange) rowsInRect: (NSRect)aRect NSInteger lastRowInRect; range.location = [self rowAtPoint: aRect.origin]; - lastRowInRect = [self rowAtPoint: + lastRowInRect = [self rowAtPoint: NSMakePoint (_bounds.origin.x, NSMaxY (aRect))]; - + if (lastRowInRect == -1) { lastRowInRect = _numberOfRows - 1; } - + range.length = lastRowInRect; range.length -= range.location; range.length += 1; @@ -4463,7 +4473,7 @@ - (NSInteger) columnAtPoint: (NSPoint)aPoint else { NSInteger i = 0; - + while ((i < _numberOfColumns) && (aPoint.x >= _columnOrigins[i])) { i++; @@ -4498,17 +4508,17 @@ - (NSInteger) rowAtPoint: (NSPoint)aPoint } } -- (NSRect) frameOfCellAtColumn: (NSInteger)columnIndex +- (NSRect) frameOfCellAtColumn: (NSInteger)columnIndex row: (NSInteger)rowIndex { NSRect frameRect; - if ((columnIndex < 0) + if ((columnIndex < 0) || (rowIndex < 0) || (columnIndex > (_numberOfColumns - 1)) || (rowIndex > (_numberOfRows - 1))) return NSZeroRect; - + frameRect.origin.y = _bounds.origin.y + (rowIndex * _rowHeight); frameRect.origin.y += _intercellSpacing.height / 2; frameRect.size.height = _rowHeight - _intercellSpacing.height; @@ -4528,7 +4538,7 @@ - (NSRect) frameOfCellAtColumn: (NSInteger)columnIndex // Safety check if (frameRect.size.width < 0) frameRect.size.width = 0; - + return frameRect; } @@ -4563,10 +4573,10 @@ - (void) sizeLastColumnToFit lastColumn = [_tableColumns objectAtIndex: (_numberOfColumns - 1)]; if ([lastColumn isResizable] == NO) - { - return; - } - excess_width = NSMaxX([self convertRect: [_super_view bounds] + { + return; + } + excess_width = NSMaxX([self convertRect: [_super_view bounds] fromView: _super_view]) - NSMaxX(_bounds); last_column_width = [lastColumn width] + excess_width; // This will automatically retile the table @@ -4582,15 +4592,15 @@ - (void) setFrame: (NSRect)frameRect { CGFloat rowsHeight = ((_numberOfRows * _rowHeight) + 1); NSRect docRect = [(NSClipView *)_super_view documentVisibleRect]; - + if (rowsHeight < docRect.size.height) { tmpRect.size.height = docRect.size.height; } - else - { + else + { tmpRect.size.height = rowsHeight; - } + } // TODO width? } [super setFrame: tmpRect]; @@ -4599,20 +4609,20 @@ - (void) setFrame: (NSRect)frameRect - (void) setFrameSize: (NSSize)frameSize { NSSize tmpSize = frameSize; - + if ([_super_view respondsToSelector: @selector(documentVisibleRect)]) { CGFloat rowsHeight = ((_numberOfRows * _rowHeight) + 1); NSRect docRect = [(NSClipView *)_super_view documentVisibleRect]; - + if (rowsHeight < docRect.size.height) { tmpSize.height = docRect.size.height; } else - { - tmpSize.height = rowsHeight; - } + { + tmpSize.height = rowsHeight; + } // TODO width? } [super setFrameSize: tmpSize]; @@ -4644,7 +4654,7 @@ - (void) sizeToFit return; columnInfo = NSZoneMalloc(NSDefaultMallocZone(), - sizeof(columnSorting) * 2 + sizeof(columnSorting) * 2 * _numberOfColumns); currentWidth = NSZoneMalloc(NSDefaultMallocZone(), sizeof(CGFloat) * _numberOfColumns); @@ -4655,7 +4665,7 @@ - (void) sizeToFit isResizable = NSZoneMalloc(NSDefaultMallocZone(), sizeof(BOOL) * _numberOfColumns); - remainingWidth = NSMaxX([self convertRect: [_super_view bounds] + remainingWidth = NSMaxX([self convertRect: [_super_view bounds] fromView: _super_view]); /* @@ -4671,7 +4681,7 @@ - (void) sizeToFit { minWidth[i] = [tb minWidth]; maxWidth[i] = [tb maxWidth]; - + if (minWidth[i] < 0) minWidth[i] = 0; if (minWidth[i] > maxWidth[i]) @@ -4683,7 +4693,7 @@ - (void) sizeToFit columnInfo[i * 2].isMax = 0; currentWidth[i] = minWidth[i]; remainingWidth -= minWidth[i]; - + columnInfo[i * 2 + 1].width = maxWidth[i]; columnInfo[i * 2 + 1].isMax = 1; } @@ -4694,35 +4704,35 @@ - (void) sizeToFit columnInfo[i * 2].isMax = 0; currentWidth[i] = minWidth[i]; remainingWidth -= minWidth[i]; - + maxWidth[i] = minWidth[i]; columnInfo[i * 2 + 1].width = maxWidth[i]; columnInfo[i * 2 + 1].isMax = 1; } - } + } // sort the info we have quick_sort_internal(columnInfo, 0, 2 * _numberOfColumns - 1); previousPoint = columnInfo[0].width; numberOfCurrentColumns = 1; - + if (remainingWidth >= 0.) { for (i = 1; i < 2 * _numberOfColumns; i++) { nextPoint = columnInfo[i].width; - - if (numberOfCurrentColumns > 0 && + + if (numberOfCurrentColumns > 0 && (nextPoint - previousPoint) > 0.) { NSInteger verification = 0; - + if ((nextPoint - previousPoint) * numberOfCurrentColumns <= remainingWidth) { toAddToCurrentColumns = nextPoint - previousPoint; - remainingWidth -= + remainingWidth -= (nextPoint - previousPoint) * numberOfCurrentColumns; for (j = 0; j < _numberOfColumns; j++) @@ -4752,7 +4762,7 @@ - (void) sizeToFit && maxWidth[j] >= nextPoint) { currentWidth[j] += quotient; - if (remainder > 0 + if (remainder > 0 && maxWidth[j] >= currentWidth[j] + 1) { remainder--; @@ -4768,14 +4778,14 @@ - (void) sizeToFit if (minWidth[j] <= previousPoint && maxWidth[j] >= nextPoint) { - if (remainder > 0 + if (remainder > 0 && maxWidth[j] >= currentWidth[j] + 1) { remainder--; currentWidth[j]++; } } - + } } if (remainder > 0) @@ -4784,20 +4794,20 @@ - (void) sizeToFit else remainingWidth = 0.; } - - + + } else if (numberOfCurrentColumns < 0) { NSLog(@"[NSTableView sizeToFit]: unexpected error"); } - + if (columnInfo[i].isMax) numberOfCurrentColumns--; else numberOfCurrentColumns++; previousPoint = nextPoint; - + if (remainingWidth == 0.) { break; @@ -4831,166 +4841,85 @@ - (void) sizeToFit [self tile]; } -/* -- (void) sizeToFit -{ - NSCell *cell; - NSEnumerator *enumerator; - NSTableColumn *tb; - float table_width; - float width; - float candidate_width; - int row; - - _tilingDisabled = YES; - - // First Step - // Resize Each Column to its Minimum Width - table_width = _bounds.origin.x; - enumerator = [_tableColumns objectEnumerator]; - while ((tb = [enumerator nextObject]) != nil) - { - // Compute min width of column - width = [[tb headerCell] cellSize].width; - for (row = 0; row < _numberOfRows; row++) - { - cell = [self preparedCellAtColumn: [_tableColumns indexOfObject: tb] - row: row]; - [cell setObjectValue: [_dataSource tableView: self - objectValueForTableColumn: tb - row: row]]; - [self _willDisplayCell: cell - forTableColumn: tb - row: row]; - candidate_width = [cell cellSize].width; - - if (_drawsGrid) - candidate_width += 4; - - if (candidate_width > width) - { - width = candidate_width; - } - } - width += _intercellSpacing.width; - [tb setWidth: width]; - // It is necessary to ask the column for the width, since it might have - // been changed by the column to constrain it to a min or max width - table_width += [tb width]; - } - - // Second Step - // If superview (clipview) is bigger than that, divide remaining space - // between all columns - if ((_super_view != nil) && (_numberOfColumns > 0)) - { - float excess_width; - - excess_width = NSMaxX ([self convertRect: [_super_view bounds] - fromView: _super_view]); - excess_width -= table_width; - // Since we resized each column at its minimum width, - // it's useless to try shrinking more: we can't - if (excess_width <= 0) - { - _tilingDisabled = NO; - [self tile]; - NSLog(@"exiting sizeToFit"); - return; - } - excess_width = excess_width / _numberOfColumns; - - enumerator = [_tableColumns objectEnumerator]; - while ((tb = [enumerator nextObject]) != nil) - { - [tb setWidth: ([tb width] + excess_width)]; - } - } - - _tilingDisabled = NO; - [self tile]; - NSLog(@"exiting sizeToFit"); -} -*/ - (void) noteNumberOfRowsChanged { NSRect newFrame; _numberOfRows = [self _numRows]; - + /* If we are selecting rows, we have to check that we have no selected rows below the new end of the table */ if (!_selectingColumns) { NSUInteger row = [_selectedRows lastIndex]; - + if (row == NSNotFound) - { - if (!_allowsEmptySelection) - { - /* We shouldn't allow empty selection - try - selecting the last row */ - NSInteger lastRow = _numberOfRows - 1; - - if (lastRow > -1) - { - [self _postSelectionIsChangingNotification]; - [_selectedRows addIndex: lastRow]; - _selectedRow = lastRow; - [self _postSelectionDidChangeNotification]; - } - else - { - /* problem - there are no rows at all */ - _selectedRow = -1; - } - } - } + { + if (!_allowsEmptySelection) + { + /* We shouldn't allow empty selection - try + selecting the last row */ + NSInteger lastRow = _numberOfRows - 1; + + if (lastRow > -1) + { + [self _postSelectionIsChangingNotification]; + [_selectedRows addIndex: lastRow]; + _selectedRow = lastRow; + [self _postSelectionDidChangeNotification]; + } + else + { + /* problem - there are no rows at all */ + _selectedRow = -1; + } + } + } /* Check that all selected rows are in the new range of rows */ else if (row >= _numberOfRows) - { - [_selectedRows removeIndexesInRange: - NSMakeRange(_numberOfRows, row + 1 - _numberOfRows)]; - if (_selectedRow >= _numberOfRows) - { - row = [_selectedRows lastIndex]; - [self _postSelectionIsChangingNotification]; - - if (row != NSNotFound) - { - _selectedRow = row; - } - else - { - /* Argh - all selected rows were outside the table */ - if (_allowsEmptySelection) - { - _selectedRow = -1; - } - else - { - /* We shouldn't allow empty selection - try - selecting the last row */ - NSInteger lastRow = _numberOfRows - 1; - - if (lastRow > -1) - { - [_selectedRows addIndex: lastRow]; - _selectedRow = lastRow; - } - else - { - /* problem - there are no rows at all */ - _selectedRow = -1; - } - } - } - [self _postSelectionDidChangeNotification]; - } - } + { + [_selectedRows removeIndexesInRange: + NSMakeRange(_numberOfRows, row + 1 - _numberOfRows)]; + if (_selectedRow >= _numberOfRows) + { + row = [_selectedRows lastIndex]; + [self _postSelectionIsChangingNotification]; + + if (row != NSNotFound) + { + _selectedRow = row; + } + else + { + /* Argh - all selected rows were outside the table */ + if (_allowsEmptySelection) + { + _selectedRow = -1; + } + else + { + /* We shouldn't allow empty selection - try + selecting the last row */ + NSInteger lastRow = _numberOfRows - 1; + + if (lastRow > -1) + { + [_selectedRows addIndex: lastRow]; + _selectedRow = lastRow; + } + else + { + /* problem - there are no rows at all */ + _selectedRow = -1; + } + } + } + [self _postSelectionDidChangeNotification]; + } + } } - + newFrame = _frame; newFrame.size.height = (_numberOfRows * _rowHeight) + 1; if (NO == NSEqualRects(newFrame, NSUnionRect(newFrame, _frame))) @@ -5005,11 +4934,11 @@ - (void) noteNumberOfRowsChanged { NSRect superviewBounds; // Get this *after* [self setFrame:] superviewBounds = [_super_view bounds]; - if ((superviewBounds.origin.x <= _frame.origin.x) - && (NSMaxY(superviewBounds) >= NSMaxY(_frame))) - { - [self setNeedsDisplay: YES]; - } + if ((superviewBounds.origin.x <= _frame.origin.x) + && (NSMaxY(superviewBounds) >= NSMaxY(_frame))) + { + [self setNeedsDisplay: YES]; + } } } @@ -5025,7 +4954,7 @@ - (void) tile { NSInteger i; CGFloat width; - + _columnOrigins[0] = _bounds.origin.x; width = [[_tableColumns objectAtIndex: 0] width]; table_width += width; @@ -5046,31 +4975,31 @@ - (void) tile CGFloat innerBorderWidth = [[NSUserDefaults standardUserDefaults] boolForKey: @"GSScrollViewNoInnerBorder"] ? 0.0 : 1.0; - [_headerView setFrameSize: + [_headerView setFrameSize: NSMakeSize (_frame.size.width, [_headerView frame].size.height)]; - [_cornerView setFrameSize: + [_cornerView setFrameSize: NSMakeSize ([NSScroller scrollerWidth] + innerBorderWidth, [_headerView frame].size.height)]; [_headerView setNeedsDisplay: YES]; [_cornerView setNeedsDisplay: YES]; - } + } } -/* - * Drawing +/* + * Drawing */ - (void) _calculatedStartingColumn: (NSInteger *)startingColumn endingColumn: (NSInteger *)endingColumn inClipRect: (NSRect)clipRect - + { CGFloat x_pos = 0.0; NSInteger i = 0; NSInteger numberOfColumns = [self numberOfColumns]; CGFloat *columnOrigins = [self _columnOrigins]; - - /* Using columnAtPoint: here would make it called twice per row per drawn + + /* Using columnAtPoint: here would make it called twice per row per drawn rect - so we avoid it and do it natively */ /* Determine starting column as fast as possible */ @@ -5102,11 +5031,11 @@ - (void) _drawCellViewRow: (NSInteger)rowIndex clipRect: (NSRect)clipRect { NSInteger numberOfRows = [self numberOfRows]; - NSInteger startingColumn; + NSInteger startingColumn; NSInteger endingColumn; NSInteger columnIndex; id dataSource = [self dataSource]; - + // If we have no data source, there is nothing to do... if (dataSource == nil) { @@ -5118,20 +5047,20 @@ - (void) _drawCellViewRow: (NSInteger)rowIndex { return; } - + [self _calculatedStartingColumn: &startingColumn endingColumn: &endingColumn inClipRect: clipRect]; - + /* Draw the row between startingColumn and endingColumn */ for (columnIndex = startingColumn; columnIndex <= endingColumn; columnIndex++) { id rowView = [self rowViewAtRow: rowIndex - makeIfNecessary: YES]; + makeIfNecessary: YES]; NSView *view = [self viewAtColumn: columnIndex row: rowIndex makeIfNecessary: YES]; - + // If the view is already part of the table, don't re-add it... if (rowView != nil && [[self subviews] containsObject: rowView] == NO) @@ -5142,23 +5071,23 @@ - (void) _drawCellViewRow: (NSInteger)rowIndex CGFloat y = cellFrame.origin.y; CGFloat w = [self frame].size.width; CGFloat h = [self rowHeight]; - + NSRect rvFrame = NSMakeRect(x, y, w, h); NSAutoresizingMaskOptions options = NSViewWidthSizable | NSViewMinYMargin; - + [self addSubview: rowView]; [rowView setAutoresizingMask: options]; [rowView setFrame: rvFrame]; } - + // Create the view if needed... if (view != nil && [[rowView subviews] containsObject: view] == NO) { // Add the view to the row... [rowView addSubview: view]; - + // Place the view... NSRect newRect = [view frame]; newRect.origin.y = 0.0; @@ -5218,8 +5147,8 @@ - (BOOL) isOpaque return YES; } -/* - * Scrolling +/* + * Scrolling */ - (void) scrollRowToVisible: (NSInteger)rowIndex @@ -5228,14 +5157,14 @@ - (void) scrollRowToVisible: (NSInteger)rowIndex { NSRect rowRect = [self rectOfRow: rowIndex]; NSRect visibleRect = [self visibleRect]; - - // If the row is over the top, or it is partially visible + + // If the row is over the top, or it is partially visible // on top, - if ((rowRect.origin.y < visibleRect.origin.y)) + if ((rowRect.origin.y < visibleRect.origin.y)) { // Then make it visible on top - NSPoint newOrigin; - + NSPoint newOrigin; + newOrigin.x = visibleRect.origin.x; newOrigin.y = rowRect.origin.y; newOrigin = [self convertPoint: newOrigin toView: _super_view]; @@ -5247,8 +5176,8 @@ - (void) scrollRowToVisible: (NSInteger)rowIndex if (NSMaxY (rowRect) > NSMaxY (visibleRect)) { // Then make it visible on bottom - NSPoint newOrigin; - + NSPoint newOrigin; + newOrigin.x = visibleRect.origin.x; newOrigin.y = visibleRect.origin.y; newOrigin.y += NSMaxY (rowRect) - NSMaxY (visibleRect); @@ -5267,13 +5196,13 @@ - (void) scrollColumnToVisible: (NSInteger)columnIndex NSRect visibleRect = [self visibleRect]; CGFloat diff; - // If the row is out on the left, or it is partially visible + // If the row is out on the left, or it is partially visible // on the left - if ((columnRect.origin.x < visibleRect.origin.x)) + if ((columnRect.origin.x < visibleRect.origin.x)) { // Then make it visible on the left - NSPoint newOrigin; - + NSPoint newOrigin; + newOrigin.x = columnRect.origin.x; newOrigin.y = visibleRect.origin.y; newOrigin = [self convertPoint: newOrigin toView: _super_view]; @@ -5299,8 +5228,8 @@ - (void) scrollColumnToVisible: (NSInteger)columnIndex } -/* - * Text delegate methods +/* + * Text delegate methods */ - (void) textDidBeginEditing: (NSNotification *)aNotification @@ -5311,7 +5240,7 @@ - (void) textDidBeginEditing: (NSNotification *)aNotification - (void) textDidChange: (NSNotification *)aNotification { // MacOS-X asks us to inform the cell if possible. - if ((_editedCell != nil) && [_editedCell respondsToSelector: + if ((_editedCell != nil) && [_editedCell respondsToSelector: @selector(textDidChange:)]) [_editedCell textDidChange: aNotification]; @@ -5377,20 +5306,20 @@ - (BOOL) textShouldEndEditing: (NSText*)textObject NSBeep (); return NO; } - + return YES; } - if ([_delegate respondsToSelector: + if ([_delegate respondsToSelector: @selector(control:isValidObject:)] == YES) { NSFormatter *formatter; id newObjectValue; - + formatter = [_editedCell formatter]; - - if ([formatter getObjectValue: &newObjectValue - forString: [_textObject text] + + if ([formatter getObjectValue: &newObjectValue + forString: [_textObject text] errorDescription: NULL] == YES) { if ([_delegate control: self @@ -5402,8 +5331,8 @@ - (BOOL) textShouldEndEditing: (NSText*)textObject return [_editedCell isEntryAcceptable: [textObject text]]; } -/* - * Persistence +/* + * Persistence */ - (NSString *) autosaveName @@ -5433,32 +5362,32 @@ - (void) setAutosaveTableColumns: (BOOL)flag if (flag) { [self _autoloadTableColumns]; - [nc addObserver: self - selector: @selector(_autosaveTableColumns) + [nc addObserver: self + selector: @selector(_autosaveTableColumns) name: NSTableViewColumnDidResizeNotification object: self]; } else { - [nc removeObserver: self + [nc removeObserver: self name: NSTableViewColumnDidResizeNotification - object: self]; + object: self]; } } -/* - * Delegate +/* + * Delegate */ - (void) setDelegate: (id)anObject { const SEL sel = @selector(tableView:willDisplayCell:forTableColumn:row:); const SEL vbsel = @selector(tableView:viewForTableColumn:row:); - + if (_delegate) [nc removeObserver: _delegate name: nil object: self]; _delegate = anObject; - + #define SET_DELEGATE_NOTIFICATION(notif_name) \ if ([_delegate respondsToSelector: @selector(tableView##notif_name:)]) \ [nc addObserver: _delegate \ @@ -5469,7 +5398,7 @@ - (void) setDelegate: (id)anObject SET_DELEGATE_NOTIFICATION(ColumnDidResize); SET_DELEGATE_NOTIFICATION(SelectionDidChange); SET_DELEGATE_NOTIFICATION(SelectionIsChanging); - + /* Cache */ _del_responds = [_delegate respondsToSelector: sel]; @@ -5528,8 +5457,8 @@ - (void) setHighlightedTableColumn: (NSTableColumn *)aTableColumn /* dragging rows */ - (NSImage*) dragImageForRows: (NSArray*)dragRows - event: (NSEvent*)dragEvent - dragImageOffset: (NSPoint*)dragImageOffset + event: (NSEvent*)dragEvent + dragImageOffset: (NSPoint*)dragImageOffset { // FIXME NSImage *dragImage = [[NSImage alloc] @@ -5539,24 +5468,24 @@ - (NSImage*) dragImageForRows: (NSArray*)dragRows } - (NSImage *) dragImageForRowsWithIndexes: (NSIndexSet*)rows - tableColumns: (NSArray*)cols - event: (NSEvent*)event - offset: (NSPoint*)offset + tableColumns: (NSArray*)cols + event: (NSEvent*)event + offset: (NSPoint*)offset { // FIXME NSArray *rowArray; rowArray = [self _indexSetToArray: rows]; - return [self dragImageForRows: rowArray - event: event - dragImageOffset: offset]; + return [self dragImageForRows: rowArray + event: event + dragImageOffset: offset]; } - (void) setDropRow: (NSInteger)row dropOperation: (NSTableViewDropOperation)operation { - if (row < -1 || row > _numberOfRows - || (operation == NSTableViewDropOn && row == _numberOfRows)) + if (row < -1 || row > _numberOfRows + || (operation == NSTableViewDropOn && row == _numberOfRows)) { currentDropRow = -1; currentDropOperation = NSTableViewDropOn; @@ -5581,11 +5510,11 @@ - (BOOL) verticalMotionCanBeginDrag - (NSArray*) namesOfPromisedFilesDroppedAtDestination: (NSURL *)dropDestination { if ([_dataSource respondsToSelector: - @selector(tableView:namesOfPromisedFilesDroppedAtDestination:forDraggedRowsWithIndexes:)]) + @selector(tableView:namesOfPromisedFilesDroppedAtDestination:forDraggedRowsWithIndexes:)]) { return [_dataSource tableView: self - namesOfPromisedFilesDroppedAtDestination: dropDestination - forDraggedRowsWithIndexes: _selectedRows]; + namesOfPromisedFilesDroppedAtDestination: dropDestination + forDraggedRowsWithIndexes: _selectedRows]; } else { @@ -5601,13 +5530,13 @@ - (void) encodeWithCoder: (NSCoder*)aCoder { if ([aCoder allowsKeyedCoding]) { - unsigned int vFlags = 0; + unsigned int vFlags = 0; NSSize intercellSpacing = [self intercellSpacing]; GSTableViewFlags tableViewFlags; // make sure the corner view is properly encoded... [super encodeWithCoder: aCoder]; - + if ([self dataSource]) { [aCoder encodeObject: [self dataSource] forKey: @"NSDataSource"]; @@ -5637,28 +5566,28 @@ - (void) encodeWithCoder: (NSCoder*)aCoder [aCoder encodeObject: [self tableColumns] forKey: @"NSTableColumns"]; if (_headerView) - { - [aCoder encodeObject: _headerView forKey: @"NSHeaderView"]; - } + { + [aCoder encodeObject: _headerView forKey: @"NSHeaderView"]; + } if (_cornerView) - { - [aCoder encodeObject: _cornerView forKey: @"NSCornerView"]; - } + { + [aCoder encodeObject: _cornerView forKey: @"NSCornerView"]; + } if ([[self sortDescriptors] count] > 0) - { - [aCoder encodeObject: _sortDescriptors forKey: @"NSSortDescriptors"]; - } + { + [aCoder encodeObject: _sortDescriptors forKey: @"NSSortDescriptors"]; + } tableViewFlags.columnSelection = [self allowsColumnSelection]; tableViewFlags.multipleSelection = [self allowsMultipleSelection]; tableViewFlags.emptySelection = [self allowsEmptySelection]; - tableViewFlags.drawsGrid = [self drawsGrid]; + tableViewFlags.drawsGrid = [self drawsGrid]; tableViewFlags.columnResizing = [self allowsColumnResizing]; tableViewFlags.columnOrdering = [self allowsColumnReordering]; tableViewFlags.columnAutosave = [self autosaveTableColumns]; tableViewFlags.alternatingRowBackgroundColors = [self usesAlternatingRowBackgroundColors]; - + memcpy((void *)&vFlags,(void *)&tableViewFlags,sizeof(unsigned int)); // encode.. @@ -5686,13 +5615,13 @@ - (void) encodeWithCoder: (NSCoder*)aCoder [aCoder encodeValueOfObjCType: @encode(int) at: &number]; number = _numberOfColumns; [aCoder encodeValueOfObjCType: @encode(int) at: &number]; - + [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_drawsGrid]; rowHeight = _rowHeight; [aCoder encodeValueOfObjCType: @encode(float) at: &rowHeight]; [aCoder encodeValueOfObjCType: @encode(SEL) at: &_doubleAction]; [aCoder encodeSize: _intercellSpacing]; - + [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_allowsMultipleSelection]; [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_allowsEmptySelection]; [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_allowsColumnSelection]; @@ -5720,22 +5649,22 @@ - (id) initWithCoder: (NSCoder*)aDecoder // assign defaults, so that there's color in case none is specified [self _initDefaults]; - ASSIGN(_gridColor, [NSColor gridColor]); - ASSIGN(_backgroundColor, [NSColor controlBackgroundColor]); + ASSIGN(_gridColor, [NSColor gridColor]); + ASSIGN(_backgroundColor, [NSColor controlBackgroundColor]); ASSIGN(_tableColumns, [NSMutableArray array]); ASSIGN(_sortDescriptors, [NSArray array]); // // Check for nil on some of these, since they are usually set // in NSIBOutletConnector objects we don't want to override - // that setting unless they're directly encoded with the - // object. - // + // that setting unless they're directly encoded with the + // object. + // // I'm not sure why IB encodes nil values for these, but // the behaviour here should match that on Mac OS X. // if ([aDecoder containsValueForKey: @"NSDataSource"]) - { + { id obj = [aDecoder decodeObjectForKey: @"NSDataSource"]; if(obj != nil) { @@ -5743,7 +5672,7 @@ - (id) initWithCoder: (NSCoder*)aDecoder } } if ([aDecoder containsValueForKey: @"NSDelegate"]) - { + { id obj = [aDecoder decodeObjectForKey: @"NSDelegate"]; if(obj != nil) { @@ -5751,7 +5680,7 @@ - (id) initWithCoder: (NSCoder*)aDecoder } } if ([aDecoder containsValueForKey: @"NSTarget"]) - { + { id obj = [aDecoder decodeObjectForKey: @"NSTarget"]; if(obj != nil) { @@ -5759,16 +5688,16 @@ - (id) initWithCoder: (NSCoder*)aDecoder } } if ([aDecoder containsValueForKey: @"NSAction"]) - { - NSString *action = [aDecoder decodeObjectForKey: @"NSAction"]; + { + NSString *action = [aDecoder decodeObjectForKey: @"NSAction"]; if(action != nil) { [self setAction: NSSelectorFromString(action)]; } } if ([aDecoder containsValueForKey: @"NSDoubleAction"]) - { - NSString *action = [aDecoder decodeObjectForKey: @"NSDoubleAction"]; + { + NSString *action = [aDecoder decodeObjectForKey: @"NSDoubleAction"]; if(action != nil) { [self setDoubleAction: NSSelectorFromString(action)]; @@ -5776,80 +5705,80 @@ - (id) initWithCoder: (NSCoder*)aDecoder } if ([aDecoder containsValueForKey: @"NSBackgroundColor"]) - { - [self setBackgroundColor: [aDecoder decodeObjectForKey: @"NSBackgroundColor"]]; - } + { + [self setBackgroundColor: [aDecoder decodeObjectForKey: @"NSBackgroundColor"]]; + } if ([aDecoder containsValueForKey: @"NSGridColor"]) - { - [self setGridColor: [aDecoder decodeObjectForKey: @"NSGridColor"]]; - } + { + [self setGridColor: [aDecoder decodeObjectForKey: @"NSGridColor"]]; + } intercellSpacing = [self intercellSpacing]; if ([aDecoder containsValueForKey: @"NSIntercellSpacingHeight"]) - { - intercellSpacing.height = [aDecoder decodeFloatForKey: @"NSIntercellSpacingHeight"]; - } + { + intercellSpacing.height = [aDecoder decodeFloatForKey: @"NSIntercellSpacingHeight"]; + } if ([aDecoder containsValueForKey: @"NSIntercellSpacingWidth"]) - { - intercellSpacing.width = [aDecoder decodeFloatForKey: @"NSIntercellSpacingWidth"]; - } + { + intercellSpacing.width = [aDecoder decodeFloatForKey: @"NSIntercellSpacingWidth"]; + } [self setIntercellSpacing: intercellSpacing]; if ([aDecoder containsValueForKey: @"NSDraggingSourceMaskForLocal"]) - { - [self setDraggingSourceOperationMask: - [aDecoder decodeIntForKey: @"NSDraggingSourceMaskForLocal"] - forLocal: YES]; - } + { + [self setDraggingSourceOperationMask: + [aDecoder decodeIntForKey: @"NSDraggingSourceMaskForLocal"] + forLocal: YES]; + } if ([aDecoder containsValueForKey: @"NSDraggingSourceMaskForNonLocal"]) - { - [self setDraggingSourceOperationMask: - [aDecoder decodeIntForKey: @"NSDraggingSourceMaskForNonLocal"] - forLocal: NO]; - } + { + [self setDraggingSourceOperationMask: + [aDecoder decodeIntForKey: @"NSDraggingSourceMaskForNonLocal"] + forLocal: NO]; + } if ([aDecoder containsValueForKey: @"NSRowHeight"]) - { - [self setRowHeight: [aDecoder decodeFloatForKey: @"NSRowHeight"]]; - } + { + [self setRowHeight: [aDecoder decodeFloatForKey: @"NSRowHeight"]]; + } if ([aDecoder containsValueForKey: @"NSCornerView"]) - { + { NSView *aView = [aDecoder decodeObjectForKey: @"NSCornerView"]; - [self setCornerView: aView]; + [self setCornerView: aView]; [aView setHidden: NO]; - } + } else - { - _cornerView = [GSTableCornerView new]; - } + { + _cornerView = [GSTableCornerView new]; + } if ([aDecoder containsValueForKey: @"NSHeaderView"]) - { - [self setHeaderView: [aDecoder decodeObjectForKey: @"NSHeaderView"]]; - } + { + [self setHeaderView: [aDecoder decodeObjectForKey: @"NSHeaderView"]]; + } if ([aDecoder containsValueForKey: @"NSSortDescriptors"]) - { - ASSIGN(_sortDescriptors, [aDecoder decodeObjectForKey: @"NSSortDescriptors"]); - } + { + ASSIGN(_sortDescriptors, [aDecoder decodeObjectForKey: @"NSSortDescriptors"]); + } if ([aDecoder containsValueForKey: @"NSTvFlags"]) - { - unsigned int flags = [aDecoder decodeIntForKey: @"NSTvFlags"]; - GSTableViewFlags tableViewFlags; - memcpy((void *)&tableViewFlags,(void *)&flags,sizeof(struct _tableViewFlags)); - - [self setAllowsColumnSelection: tableViewFlags.columnSelection]; - [self setAllowsMultipleSelection: tableViewFlags.multipleSelection]; - [self setAllowsEmptySelection: tableViewFlags.emptySelection]; - [self setDrawsGrid: tableViewFlags.drawsGrid]; - [self setAllowsColumnResizing: tableViewFlags.columnResizing]; - [self setAllowsColumnReordering: tableViewFlags.columnOrdering]; - [self setAutosaveTableColumns: tableViewFlags.columnAutosave]; - [self setUsesAlternatingRowBackgroundColors: tableViewFlags.alternatingRowBackgroundColors]; - } - + { + unsigned int flags = [aDecoder decodeIntForKey: @"NSTvFlags"]; + GSTableViewFlags tableViewFlags; + memcpy((void *)&tableViewFlags,(void *)&flags,sizeof(struct _tableViewFlags)); + + [self setAllowsColumnSelection: tableViewFlags.columnSelection]; + [self setAllowsMultipleSelection: tableViewFlags.multipleSelection]; + [self setAllowsEmptySelection: tableViewFlags.emptySelection]; + [self setDrawsGrid: tableViewFlags.drawsGrid]; + [self setAllowsColumnResizing: tableViewFlags.columnResizing]; + [self setAllowsColumnReordering: tableViewFlags.columnOrdering]; + [self setAutosaveTableColumns: tableViewFlags.columnAutosave]; + [self setUsesAlternatingRowBackgroundColors: tableViewFlags.alternatingRowBackgroundColors]; + } + if ([aDecoder containsValueForKey: @"NSViewBased"]) { _viewBased = [aDecoder decodeBoolForKey: @"NSViewBased"]; @@ -5859,18 +5788,18 @@ - (id) initWithCoder: (NSCoder*)aDecoder columns = [aDecoder decodeObjectForKey: @"NSTableColumns"]; e = [columns objectEnumerator]; while ((col = [e nextObject]) != nil) - { - /* Will initialize -[NSTableColumn tableView], _numberOfColumns and - allocate _columnsOrigins */ - [self addTableColumn: col]; - } + { + /* Will initialize -[NSTableColumn tableView], _numberOfColumns and + allocate _columnsOrigins */ + [self addTableColumn: col]; + } [self tile]; /* Initialize _columnOrigins */ } else { - int version = [aDecoder versionForClassName: - @"NSTableView"]; + int version = [aDecoder versionForClassName: + @"NSTableView"]; id aDelegate; float rowHeight; int number; @@ -5888,7 +5817,7 @@ - (id) initWithCoder: (NSCoder*)aDecoder [self setDelegate: aDelegate]; [_headerView setTableView: self]; [_tableColumns makeObjectsPerformSelector: @selector(setTableView:) - withObject: self]; + withObject: self]; [aDecoder decodeValueOfObjCType: @encode(int) at: &number]; _numberOfRows = number; @@ -5899,26 +5828,26 @@ - (id) initWithCoder: (NSCoder*)aDecoder _rowHeight = rowHeight; [aDecoder decodeValueOfObjCType: @encode(SEL) at: &_doubleAction]; _intercellSpacing = [aDecoder decodeSize]; - + [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_allowsMultipleSelection]; [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_allowsEmptySelection]; [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_allowsColumnSelection]; [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_allowsColumnResizing]; if (version >= 3) - { - [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_allowsColumnReordering]; - } + { + [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_allowsColumnReordering]; + } if (version >= 2) - { - [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_autoresizesAllColumnsToFit]; - } - + { + [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_autoresizesAllColumnsToFit]; + } + if (version >= 4) - { - [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_verticalMotionDrag]; - } + { + [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_verticalMotionDrag]; + } if (version >= 5) { @@ -5927,17 +5856,17 @@ - (id) initWithCoder: (NSCoder*)aDecoder if (version >= 6) { - [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_viewBased]; + [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_viewBased]; } - + if (_numberOfColumns > 0) - { - _columnOrigins = NSZoneMalloc (NSDefaultMallocZone (), - sizeof(CGFloat) * _numberOfColumns); - } + { + _columnOrigins = NSZoneMalloc (NSDefaultMallocZone (), + sizeof(CGFloat) * _numberOfColumns); + } [self tile]; /* Initialize _columnOrigins */ } - + return self; } @@ -6001,7 +5930,7 @@ - (CGFloat *) _columnOrigins - (void) _mouseDownInHeaderOfTableColumn: (NSTableColumn *)tc { - if ([_delegate + if ([_delegate respondsToSelector: @selector(tableView:mouseDownInHeaderOfTableColumn:)]) { @@ -6014,7 +5943,7 @@ - (void) _clickTableColumn: (NSTableColumn *)tc { NSSortDescriptor *oldMainSortDescriptor = nil; NSSortDescriptor *newMainSortDescriptor = [tc sortDescriptorPrototype]; - NSMutableArray *newSortDescriptors = + NSMutableArray *newSortDescriptors = [NSMutableArray arrayWithArray: [self sortDescriptors]]; NSEnumerator *e = [newSortDescriptors objectEnumerator]; NSSortDescriptor *descriptor = nil; @@ -6029,7 +5958,7 @@ - (void) _clickTableColumn: (NSTableColumn *)tc while ((descriptor = [e nextObject]) != nil) { if ([[descriptor key] isEqual: [newMainSortDescriptor key]]) - [outdatedDescriptors addObject: descriptor]; + [outdatedDescriptors addObject: descriptor]; } /* Invert the sort direction when the same column header is clicked twice */ @@ -6059,46 +5988,46 @@ - (void) _editNextCellAfterRow: (NSInteger) row byExtendingSelection: NO]; if ([self _isCellEditableColumn: column row:row]) - { - [self editColumn: column - row: row - withEvent: nil - select: YES]; - } + { + [self editColumn: column + row: row + withEvent: nil + select: YES]; + } } } -(BOOL) _editNextEditableCellAfterRow: (NSInteger)row - column: (NSInteger)column + column: (NSInteger)column { NSInteger i, j; - + if (row > -1) { // First look for cells in the same row for (j = column + 1; j < _numberOfColumns; j++) - { - if ([self _isCellEditableColumn: j row: row]) - { - [self editColumn: j row: row withEvent: nil select: YES]; - return YES; - } - } + { + if ([self _isCellEditableColumn: j row: row]) + { + [self editColumn: j row: row withEvent: nil select: YES]; + return YES; + } + } } // Otherwise, make the big cycle. for (i = row + 1; i < _numberOfRows; i++) { for (j = 0; j < _numberOfColumns; j++) - { - if ([self _isCellEditableColumn: j row: i]) - { - // Need to select row to be able to edit it. - [self selectRow: i byExtendingSelection: NO]; - [self editColumn: j row: i withEvent: nil select: YES]; - return YES; - } - } + { + if ([self _isCellEditableColumn: j row: i]) + { + // Need to select row to be able to edit it. + [self selectRow: i byExtendingSelection: NO]; + [self editColumn: j row: i withEvent: nil select: YES]; + return YES; + } + } } // Should we loop around or not? @@ -6107,15 +6036,15 @@ -(BOOL) _editNextEditableCellAfterRow: (NSInteger)row for (i = 0; i < row; i++) { for (j = 0; j < _numberOfColumns; j++) - { - if ([self _isCellEditableColumn: j row: i]) - { - // Need to select row to be able to edit it. - [self selectRow: i byExtendingSelection: NO]; - [self editColumn: j row: i withEvent: nil select: YES]; - return YES; - } - } + { + if ([self _isCellEditableColumn: j row: i]) + { + // Need to select row to be able to edit it. + [self selectRow: i byExtendingSelection: NO]; + [self editColumn: j row: i withEvent: nil select: YES]; + return YES; + } + } } // Still nothing? Look at the beginning of the current row @@ -6123,13 +6052,13 @@ -(BOOL) _editNextEditableCellAfterRow: (NSInteger)row { // First look for cells in the same row for (j = 0; j < column; j++) - { - if ([self _isCellEditableColumn: j row: row]) - { - [self editColumn: j row: row withEvent: nil select: YES]; - return YES; - } - } + { + if ([self _isCellEditableColumn: j row: row]) + { + [self editColumn: j row: row withEvent: nil select: YES]; + return YES; + } + } } #endif @@ -6145,28 +6074,28 @@ -(BOOL) _editPreviousEditableCellBeforeRow: (NSInteger)row { // First look for cells in the same row for (j = column - 1; j > -1; j--) - { - if ([self _isCellEditableColumn: j row: row]) - { - [self editColumn: j row: row withEvent: nil select: YES]; - return YES; - } - } + { + if ([self _isCellEditableColumn: j row: row]) + { + [self editColumn: j row: row withEvent: nil select: YES]; + return YES; + } + } } // Otherwise, make the big cycle. for (i = row - 1; i > -1; i--) { for (j = _numberOfColumns - 1; j > -1; j--) - { - if ([self _isCellEditableColumn: j row: i]) - { - // Need to select row to be able to edit it. - [self selectRow: i byExtendingSelection: NO]; - [self editColumn: j row: i withEvent: nil select: YES]; - return YES; - } - } + { + if ([self _isCellEditableColumn: j row: i]) + { + // Need to select row to be able to edit it. + [self selectRow: i byExtendingSelection: NO]; + [self editColumn: j row: i withEvent: nil select: YES]; + return YES; + } + } } // Should we loop around or not? @@ -6175,15 +6104,15 @@ -(BOOL) _editPreviousEditableCellBeforeRow: (NSInteger)row for (i = _numberOfRows - 1; i > row; i--) { for (j = _numberOfColumns - 1; j > -1; j--) - { - if ([self _isCellEditableColumn: j row: i]) - { - // Need to select row to be able to edit it. - [self selectRow: i byExtendingSelection: NO]; - [self editColumn: j row: i withEvent: nil select: YES]; - return YES; - } - } + { + if ([self _isCellEditableColumn: j row: i]) + { + // Need to select row to be able to edit it. + [self selectRow: i byExtendingSelection: NO]; + [self editColumn: j row: i withEvent: nil select: YES]; + return YES; + } + } } // Still nothing? Look at the end of the current row @@ -6191,13 +6120,13 @@ -(BOOL) _editPreviousEditableCellBeforeRow: (NSInteger)row { // First look for cells in the same row for (j = _numberOfColumns - 1; j > column; j++) - { - if ([self _isCellEditableColumn: j row: row]) - { - [self editColumn: j row: row withEvent: nil select: YES]; - return YES; - } - } + { + if ([self _isCellEditableColumn: j row: row]) + { + [self editColumn: j row: row withEvent: nil select: YES]; + return YES; + } + } } #endif @@ -6206,7 +6135,7 @@ -(BOOL) _editPreviousEditableCellBeforeRow: (NSInteger)row - (void) _autosaveTableColumns { - if (_autosaveTableColumns && _autosaveName != nil) + if (_autosaveTableColumns && _autosaveName != nil) { NSUserDefaults *defaults; NSString *tableKey; @@ -6215,24 +6144,24 @@ - (void) _autosaveTableColumns id en; defaults = [NSUserDefaults standardUserDefaults]; - tableKey = [NSString stringWithFormat: @"NSTableView Columns %@", + tableKey = [NSString stringWithFormat: @"NSTableView Columns %@", _autosaveName]; config = [NSMutableDictionary new]; - + en = [[self tableColumns] objectEnumerator]; while ((column = [en nextObject]) != nil) { NSArray *array; NSNumber *width, *identNum; id ident; - + width = [NSNumber numberWithInt: [column width]]; ident = [column identifier]; - identNum = [NSNumber numberWithInt: [self columnWithIdentifier: + identNum = [NSNumber numberWithInt: [self columnWithIdentifier: ident]]; - array = [NSArray arrayWithObjects: width, identNum, nil]; - [config setObject: array forKey: ident]; - } + array = [NSArray arrayWithObjects: width, identNum, nil]; + [config setObject: array forKey: ident]; + } [defaults setObject: config forKey: tableKey]; [defaults synchronize]; RELEASE (config); @@ -6241,27 +6170,27 @@ - (void) _autosaveTableColumns - (void) _autoloadTableColumns { - if (_autosaveTableColumns && _autosaveName != nil) - { + if (_autosaveTableColumns && _autosaveName != nil) + { NSUserDefaults *defaults; NSDictionary *config; NSString *tableKey; defaults = [NSUserDefaults standardUserDefaults]; - tableKey = [NSString stringWithFormat: @"NSTableView Columns %@", + tableKey = [NSString stringWithFormat: @"NSTableView Columns %@", _autosaveName]; config = [defaults objectForKey: tableKey]; - if (config != nil) + if (config != nil) { NSEnumerator *en = [[config allKeys] objectEnumerator]; NSString *colKey; - NSArray *colDesc; + NSArray *colDesc; NSTableColumn *col; - - while ((colKey = [en nextObject]) != nil) + + while ((colKey = [en nextObject]) != nil) { col = [self tableColumnWithIdentifier: colKey]; - + if (col != nil) { colDesc = [config objectForKey: colKey]; @@ -6278,22 +6207,22 @@ - (void) superviewFrameChanged: (NSNotification*)aNotification { if (_autoresizesAllColumnsToFit == YES) { - CGFloat visible_width = [self convertRect: [_super_view bounds] + CGFloat visible_width = [self convertRect: [_super_view bounds] fromView: _super_view].size.width; CGFloat table_width = 0; if (_numberOfColumns > 0) - { - table_width = - _columnOrigins[_numberOfColumns - 1] + - [[_tableColumns objectAtIndex: _numberOfColumns - 1] width]; - } - + { + table_width = + _columnOrigins[_numberOfColumns - 1] + + [[_tableColumns objectAtIndex: _numberOfColumns - 1] width]; + } + /* NSLog(@"columnOrigins[0] %f", _columnOrigins[0]); - NSLog(@"superview.bounds %@", + NSLog(@"superview.bounds %@", NSStringFromRect([_super_view bounds])); - NSLog(@"superview.frame %@", + NSLog(@"superview.frame %@", NSStringFromRect([_super_view frame])); NSLog(@"table_width %f", table_width); NSLog(@"width %f", visible_width); @@ -6324,22 +6253,22 @@ - (void) superviewFrameChanged: (NSNotification*)aNotification } else { - CGFloat visible_width = [self convertRect: [_super_view bounds] + CGFloat visible_width = [self convertRect: [_super_view bounds] fromView: _super_view].size.width; CGFloat table_width = 0; if (_numberOfColumns > 0) - { - table_width = - _columnOrigins[_numberOfColumns - 1] + - [[_tableColumns objectAtIndex: _numberOfColumns - 1] width]; - } - + { + table_width = + _columnOrigins[_numberOfColumns - 1] + + [[_tableColumns objectAtIndex: _numberOfColumns - 1] width]; + } + /* NSLog(@"columnOrigins[0] %f", _columnOrigins[0]); - NSLog(@"superview.bounds %@", + NSLog(@"superview.bounds %@", NSStringFromRect([_super_view bounds])); - NSLog(@"superview.frame %@", + NSLog(@"superview.frame %@", NSStringFromRect([_super_view frame])); NSLog(@"table_width %f", table_width); NSLog(@"width %f", visible_width); @@ -6385,7 +6314,7 @@ - (NSDragOperation) draggingSourceOperationMaskForLocal: (BOOL)isLocal } - (void) setDraggingSourceOperationMask: (NSDragOperation)mask - forLocal: (BOOL)isLocal + forLocal: (BOOL)isLocal { if (isLocal) { @@ -6448,7 +6377,7 @@ - (void) _drawDropIndicator } else { - newRect = NSMakeRect([self visibleRect].origin.x, + newRect = NSMakeRect([self visibleRect].origin.x, currentDropRow * _rowHeight - 1, [self visibleRect].size.width, 3); @@ -6459,7 +6388,7 @@ - (void) _drawDropIndicator else { newRect = [self frameOfCellAtColumn: 0 - row: currentDropRow]; + row: currentDropRow]; newRect.origin.x = _bounds.origin.x; newRect.size.width = _bounds.size.width + 2; newRect.origin.x -= _intercellSpacing.height / 2; @@ -6487,9 +6416,9 @@ - (void) _drawDropIndicator [self unlockFocus]; } -/* This is a crude method of scrolling the view while dragging so the user can -drag to any cell even if it's not visible. Unfortunately we don't receive -events when the drag is outside the view, so the pointer must still be in the +/* This is a crude method of scrolling the view while dragging so the user can +drag to any cell even if it's not visible. Unfortunately we don't receive +events when the drag is outside the view, so the pointer must still be in the view to drag. */ - (void) _scrollRowAtPointToVisible: (NSPoint)p { @@ -6499,13 +6428,13 @@ - (void) _scrollRowAtPointToVisible: (NSPoint)p { currentRow = [self rowAtPoint: p] - 1; if (currentRow > 0) - [self scrollRowToVisible: currentRow]; + [self scrollRowToVisible: currentRow]; } else if (p.y > NSMaxY([self visibleRect]) - 3) { currentRow = [self rowAtPoint: p] + 1; if (currentRow < _numberOfRows) - [self scrollRowToVisible: currentRow]; + [self scrollRowToVisible: currentRow]; } } @@ -6515,13 +6444,13 @@ - (NSInteger) _computedRowAtPoint: (NSPoint)p } - (void) _setDropOperationAndRow: (NSInteger)row - usingPositionInRow: (NSInteger)positionInRow - atPoint: (NSPoint)p + usingPositionInRow: (NSInteger)positionInRow + atPoint: (NSPoint)p { NSParameterAssert(row > -1); - BOOL isPositionInsideMiddleQuartersOfRow = + BOOL isPositionInsideMiddleQuartersOfRow = (positionInRow > _rowHeight / 4 && positionInRow <= (3 * _rowHeight) / 4); - BOOL isDropOn = (row > _numberOfRows || isPositionInsideMiddleQuartersOfRow); + BOOL isDropOn = (row > _numberOfRows || isPositionInsideMiddleQuartersOfRow); [self setDropRow: (isDropOn ? [self _computedRowAtPoint: p] : row) dropOperation: (isDropOn ? NSTableViewDropOn : NSTableViewDropAbove)]; @@ -6558,28 +6487,28 @@ - (NSDragOperation) draggingUpdated: (id ) sender /* Remember current drop target */ currentDragOperation = dragOperation; lastQuarterPosition = quarterPosition; - - /* The user can retarget this default drop using -setDropRow:dropOperation: + + /* The user can retarget this default drop using -setDropRow:dropOperation: in -tableView:validateDrop:proposedRow:proposedDropOperation:. */ - [self _setDropOperationAndRow: row - usingPositionInRow: positionInRow - atPoint: p]; + [self _setDropOperationAndRow: row + usingPositionInRow: positionInRow + atPoint: p]; - if ([_dataSource respondsToSelector: + if ([_dataSource respondsToSelector: @selector(tableView:validateDrop:proposedRow:proposedDropOperation:)]) { currentDragOperation = [_dataSource tableView: self - validateDrop: sender - proposedRow: currentDropRow - proposedDropOperation: currentDropOperation]; + validateDrop: sender + proposedRow: currentDropRow + proposedDropOperation: currentDropOperation]; } - - /* -setDropRow:dropOperation: can changes both currentDropRow and - currentDropOperation. Whether we have to redraw the drop indicator depends + + /* -setDropRow:dropOperation: can changes both currentDropRow and + currentDropOperation. Whether we have to redraw the drop indicator depends on this change. */ if (currentDropRow != oldDropRow || currentDropOperation != oldDropOperation) { - [self _drawDropIndicator]; + [self _drawDropIndicator]; oldDropRow = (currentDropRow > -1 ? currentDropRow : _numberOfRows); oldDropOperation = currentDropOperation; } @@ -6612,30 +6541,30 @@ - (void) concludeDragOperation:(id )sender { } -- (BOOL) canDragRowsWithIndexes: (NSIndexSet *)indexes - atPoint: (NSPoint)point +- (BOOL) canDragRowsWithIndexes: (NSIndexSet *)indexes + atPoint: (NSPoint)point { return YES; } -/* - * sorting +/* + * sorting */ -/** Sets the sort descriptors used to sort the rows and delegates the sorting +/** Sets the sort descriptors used to sort the rows and delegates the sorting to -tableView:didChangeSortDescriptors or -outlineView:didChangeSortDescriptors: in NSOutlineView. -The delegate methods can retrieve the new sort descriptors with +The delegate methods can retrieve the new sort descriptors with -sortDescriptors and override them with -setSortDescriptors:.
-The first object in the new sort descriptor array is the sort descriptor +The first object in the new sort descriptor array is the sort descriptor prototype returned by the table column whose header was the last clicked. See -[NSTableColumn sortDescriptorPrototype]. - -This method is called automatically when you click on a table column header, + +This method is called automatically when you click on a table column header, so you shouldn't need to call it usually. -Take note the sort descriptors are encoded by the keyed archiving (rarely used +Take note the sort descriptors are encoded by the keyed archiving (rarely used since neither IB or Gorm support to set these directly). */ - (void) setSortDescriptors: (NSArray *)sortDescriptors { @@ -6649,8 +6578,8 @@ - (void) setSortDescriptors: (NSArray *)sortDescriptors } else { - /* _sortDescriptors must remain immutable since -sortDescriptors doesn't - return a defensive copy */ + /* _sortDescriptors must remain immutable since -sortDescriptors doesn't + return a defensive copy */ newSortDescriptors = [NSArray arrayWithArray: sortDescriptors]; } @@ -6665,7 +6594,7 @@ - (void) setSortDescriptors: (NSArray *)sortDescriptors RELEASE(oldSortDescriptors); } -/** Returns the current sort descriptors, usually updated every time a click +/** Returns the current sort descriptors, usually updated every time a click happens on a table column header. By default, returns an empty array. @@ -6696,6 +6625,26 @@ - (void) _postSelectionIsChangingNotification - (void) _postSelectionDidChangeNotification { + NSTableColumn *tb = [_tableColumns objectAtIndex: 0]; + GSKeyValueBinding *theBinding; + + theBinding = [GSKeyValueBinding getBinding: NSValueBinding + forObject: tb]; + + // If there is a binding, send the indexes back + if (theBinding != nil) + { + id observedObject = [theBinding observedObject]; + + // Set the selection indexes on the controller... + theBinding = [GSKeyValueBinding getBinding: NSSelectionIndexesBinding + forObject: observedObject]; + if (theBinding != nil) + { + [theBinding reverseSetValue: _selectedRows]; + } + } + [nc postNotificationName: NSTableViewSelectionDidChangeNotification object: self]; } @@ -6705,7 +6654,7 @@ - (void) _postColumnDidMoveNotificationWithOldIndex: (NSInteger) oldIndex { [nc postNotificationName: NSTableViewColumnDidMoveNotification object: self - userInfo: [NSDictionary + userInfo: [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInteger: newIndex], @"NSNewColumn", @@ -6716,20 +6665,20 @@ - (void) _postColumnDidMoveNotificationWithOldIndex: (NSInteger) oldIndex - (void) _postColumnDidResizeNotificationWithOldWidth: (float) oldWidth { - [nc postNotificationName: + [nc postNotificationName: NSTableViewColumnDidResizeNotification object: self - userInfo: [NSDictionary + userInfo: [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithFloat: oldWidth], - @"NSOldWidth", + @"NSOldWidth", nil]]; } - (BOOL) _shouldSelectTableColumn: (NSTableColumn *)tableColumn { - if ([_delegate respondsToSelector: - @selector (tableView:shouldSelectTableColumn:)] == YES) + if ([_delegate respondsToSelector: + @selector (tableView:shouldSelectTableColumn:)] == YES) { if ([_delegate tableView: self shouldSelectTableColumn: tableColumn] == NO) { @@ -6742,35 +6691,35 @@ - (BOOL) _shouldSelectTableColumn: (NSTableColumn *)tableColumn - (BOOL) _shouldSelectRow: (NSInteger)rowIndex { - if ([_delegate respondsToSelector: - @selector (tableView:shouldSelectRow:)] == YES) + if ([_delegate respondsToSelector: + @selector (tableView:shouldSelectRow:)] == YES) { if ([_delegate tableView: self shouldSelectRow: rowIndex] == NO) { return NO; } } - + return YES; } - (BOOL) _shouldSelectionChange { - if ([_delegate respondsToSelector: - @selector (selectionShouldChangeInTableView:)] == YES) + if ([_delegate respondsToSelector: + @selector (selectionShouldChangeInTableView:)] == YES) { if ([_delegate selectionShouldChangeInTableView: self] == NO) { return NO; } } - + return YES; } - (void) _didChangeSortDescriptors: (NSArray *)oldSortDescriptors { - if ([_dataSource + if ([_dataSource respondsToSelector: @selector(tableView:sortDescriptorsDidChange:)]) { [_dataSource tableView: self sortDescriptorsDidChange: oldSortDescriptors]; @@ -6779,7 +6728,7 @@ - (void) _didChangeSortDescriptors: (NSArray *)oldSortDescriptors - (void) _didClickTableColumn: (NSTableColumn *)tc { - if ([_delegate + if ([_delegate respondsToSelector: @selector(tableView:didClickTableColumn:)]) { @@ -6791,7 +6740,7 @@ - (void) _didClickTableColumn: (NSTableColumn *)tc - (BOOL) _shouldEditTableColumn: (NSTableColumn *)tableColumn row: (NSInteger) rowIndex { - if ([_delegate respondsToSelector: + if ([_delegate respondsToSelector: @selector(tableView:shouldEditTableColumn:row:)]) { return [_delegate tableView: self shouldEditTableColumn: tableColumn @@ -6802,16 +6751,16 @@ - (BOOL) _shouldEditTableColumn: (NSTableColumn *)tableColumn } - (BOOL) _isEditableColumn: (NSInteger) columnIndex - row: (NSInteger) rowIndex + row: (NSInteger) rowIndex { NSTableColumn *tableColumn = [_tableColumns objectAtIndex: columnIndex]; return [tableColumn isEditable] && [self _shouldEditTableColumn: tableColumn - row: rowIndex]; + row: rowIndex]; } - (BOOL) _isCellSelectableColumn: (NSInteger) columnIndex - row: (NSInteger) rowIndex + row: (NSInteger) rowIndex { if (![self _isEditableColumn: columnIndex row: rowIndex]) { @@ -6844,13 +6793,16 @@ - (void) _willDisplayCell: (NSCell*)cell forTableColumn: (NSTableColumn *)tb row: (NSInteger)index { + [tb _applyBindingsToCell: cell + atRow: index]; + if (_del_responds) { - [_delegate tableView: self - willDisplayCell: cell - forTableColumn: tb + [_delegate tableView: self + willDisplayCell: cell + forTableColumn: tb row: index]; - } + } } - (id) _objectValueForTableColumn: (NSTableColumn *)tb @@ -6859,12 +6811,12 @@ - (id) _objectValueForTableColumn: (NSTableColumn *)tb id result = nil; GSKeyValueBinding *theBinding; - theBinding = [GSKeyValueBinding getBinding: NSValueBinding + theBinding = [GSKeyValueBinding getBinding: NSValueBinding forObject: tb]; if (theBinding != nil) { - return [(NSArray *)[theBinding destinationValue] - objectAtIndex: index]; + result = [(NSArray *)[theBinding destinationValue] + objectAtIndex: index]; } else if ([_dataSource respondsToSelector: @selector(tableView:objectValueForTableColumn:row:)]) @@ -6873,7 +6825,7 @@ - (id) _objectValueForTableColumn: (NSTableColumn *)tb objectValueForTableColumn: tb row: index]; } - + return result; } @@ -6881,8 +6833,28 @@ - (void) _setObjectValue: (id)value forTableColumn: (NSTableColumn *)tb row: (NSInteger) index { - if ([_dataSource respondsToSelector: - @selector(tableView:setObjectValue:forTableColumn:row:)]) + GSKeyValueBinding *theBinding; + + theBinding = [GSKeyValueBinding getBinding: NSValueBinding + forObject: tb]; + if (theBinding != nil) + { + NSString *keyPath = [tb _keyPathForValueBinding]; + if (keyPath != nil) + { + NSArray *items = [[theBinding observedObject] arrangedObjects]; + if (items != nil) + { + id obj = [items objectAtIndex: index]; + if (obj != nil) + { + [obj setValue: value forKeyPath: keyPath]; + } + } + } + } + else if ([_dataSource respondsToSelector: + @selector(tableView:setObjectValue:forTableColumn:row:)]) { [_dataSource tableView: self setObjectValue: value @@ -6892,7 +6864,7 @@ - (void) _setObjectValue: (id)value } /* Quasi private method called on self from -noteNumberOfRowsChanged - * implemented in NSTableView and subclasses + * implemented in NSTableView and subclasses * by default returns the DataSource's -numberOfRowsInTableView: */ - (NSInteger) _numRows @@ -6901,8 +6873,8 @@ - (NSInteger) _numRows // If we have content binding the data source is used only // like a delegate - theBinding = [GSKeyValueBinding getBinding: NSContentBinding - forObject: self]; + theBinding = [GSKeyValueBinding getBinding: NSContentBinding + forObject: self]; if (theBinding != nil) { return [(NSArray *)[theBinding destinationValue] count]; @@ -6918,11 +6890,11 @@ - (NSInteger) _numRows GSKeyValueBinding *theBinding; theBinding = [GSKeyValueBinding getBinding: NSValueBinding - forObject: tb]; + forObject: tb]; if (theBinding != nil) - { - return [[theBinding destinationValue] count]; - } + { + return [[theBinding destinationValue] count]; + } // FIXME return 0; @@ -6936,9 +6908,9 @@ - (NSInteger) _numRows - (BOOL) _isDraggingSource { return [_dataSource respondsToSelector: - @selector(tableView:writeRows:toPasteboard:)] + @selector(tableView:writeRows:toPasteboard:)] || [_dataSource respondsToSelector: - @selector(tableView:writeRowsWithIndexes:toPasteboard:)]; + @selector(tableView:writeRowsWithIndexes:toPasteboard:)]; } - (BOOL) _writeRows: (NSIndexSet *)rows @@ -6948,24 +6920,24 @@ - (BOOL) _writeRows: (NSIndexSet *)rows @selector(tableView:writeRowsWithIndexes:toPasteboard:)] == YES) { return [_dataSource tableView: self - writeRowsWithIndexes: rows - toPasteboard: pboard]; + writeRowsWithIndexes: rows + toPasteboard: pboard]; } else if ([_dataSource respondsToSelector: - @selector(tableView:writeRows:toPasteboard:)] == YES) + @selector(tableView:writeRows:toPasteboard:)] == YES) { NSArray *rowArray; rowArray = [self _indexSetToArray: rows]; return [_dataSource tableView: self - writeRows: rowArray - toPasteboard: pboard]; + writeRows: rowArray + toPasteboard: pboard]; } return NO; } - (void) reloadDataForRowIndexes: (NSIndexSet*)rowIndexes - columnIndexes: (NSIndexSet*)columnIndexes + columnIndexes: (NSIndexSet*)columnIndexes { [self reloadData]; } @@ -6980,11 +6952,11 @@ - (void) endUpdates if (_beginEndUpdates > 0) { if (--_beginEndUpdates == 0) - { - // Process batched inserts/removes.... - // Just reload table for now until we get inserts/removes working... - [self reloadData]; - } + { + // Process batched inserts/removes.... + // Just reload table for now until we get inserts/removes working... + [self reloadData]; + } } } @@ -6995,12 +6967,12 @@ - (NSInteger) columnForView: (NSView*)view } - (void) insertRowsAtIndexes: (NSIndexSet*)indexes - withAnimation: (NSTableViewAnimationOptions)animationOptions + withAnimation: (NSTableViewAnimationOptions)animationOptions { } - (void) removeRowsAtIndexes: (NSIndexSet*)indexes - withAnimation: (NSTableViewAnimationOptions)animationOptions + withAnimation: (NSTableViewAnimationOptions)animationOptions { } @@ -7033,7 +7005,7 @@ - (NSView *) makeViewWithIdentifier: (NSUserInterfaceItemIdentifier)identifier o { NSEnumerator *en = [tlo objectEnumerator]; id v = nil; - + while ((v = [en nextObject]) != nil) { if ([v isKindOfClass: [NSView class]]) @@ -7049,7 +7021,7 @@ - (NSView *) makeViewWithIdentifier: (NSUserInterfaceItemIdentifier)identifier o } } } - + return view; } @@ -7057,7 +7029,7 @@ - (id) _prototypeCellViewFromTableColumn: (NSTableColumn *)tb { NSArray *protoCellViews = [tb _prototypeCellViews]; id view = nil; - + // it seems there is always one prototype... if ([protoCellViews count] > 0) { @@ -7075,7 +7047,7 @@ - (NSTableRowView *) rowViewAtRow: (NSInteger)row makeIfNecessary: (BOOL)flag if (_viewBased == YES) { NSNumber *aRow = [NSNumber numberWithInteger: row]; - + rv = [_rowViews objectForKey: aRow]; if (rv == nil) { @@ -7088,14 +7060,14 @@ - (NSTableRowView *) rowViewAtRow: (NSInteger)row makeIfNecessary: (BOOL)flag if (rv == nil) { rv = AUTORELEASE([[NSTableRowView alloc] init]); - } + } } - + [_rowViews setObject: rv forKey: aRow]; } } - + return rv; } @@ -7107,7 +7079,7 @@ - (NSView *) viewAtColumn: (NSInteger)column row: (NSInteger)row makeIfNecessary NSView *view = [self _renderedViewForPath: path]; NSRect drawingRect = [self frameOfCellAtColumn: column row: row]; - + // If the view has been stored use it, if not // then grab it. if (view == nil @@ -7123,7 +7095,7 @@ - (NSView *) viewAtColumn: (NSInteger)column row: (NSInteger)row makeIfNecessary { view = [self _prototypeCellViewFromTableColumn: tb]; } - + [self _setRenderedView: view forPath: path]; } @@ -7178,7 +7150,7 @@ - (void) _setSelectingColumns: (BOOL)flag { if (flag == _selectingColumns) return; - + if (flag == NO) { [self _unselectAllColumns]; @@ -7195,15 +7167,15 @@ - (NSArray *) _indexSetToArray: (NSIndexSet*)indexSet { NSMutableArray *array = [NSMutableArray array]; NSUInteger index = [indexSet firstIndex]; - + while (index != NSNotFound) { NSNumber *num = [NSNumber numberWithUnsignedInteger: index]; - [array addObject: num]; + [array addObject: num]; index = [indexSet indexGreaterThanIndex: index]; - } - + } + return array; } @@ -7218,7 +7190,7 @@ - (BOOL) _selectRow: (NSInteger)rowIndex { return NO; } - + [self setNeedsDisplayInRect: [self rectOfRow: rowIndex]]; [_selectedRows addIndex: rowIndex]; _selectedRow = rowIndex; @@ -7231,7 +7203,7 @@ - (BOOL) _selectUnselectedRow: (NSInteger)rowIndex { return NO; } - + [self setNeedsDisplayInRect: [self rectOfRow: rowIndex]]; [_selectedRows addIndex: rowIndex]; _selectedRow = rowIndex; @@ -7260,7 +7232,7 @@ - (void) _unselectAllRows { /* Compute rect to redraw to clear the old row selection */ NSUInteger row = [_selectedRows firstIndex]; - + while (row != NSNotFound) { [self setNeedsDisplayInRect: [self rectOfRow: row]]; @@ -7279,19 +7251,19 @@ - (void) _unselectAllColumns { /* Compute rect to redraw to clear the old column selection */ NSUInteger column = [_selectedColumns firstIndex]; - + while (column != NSNotFound) { [self setNeedsDisplayInRect: [self rectOfColumn: column]]; if (_headerView) - { - [_headerView setNeedsDisplayInRect: + { + [_headerView setNeedsDisplayInRect: [_headerView headerRectOfColumn: column]]; } column = [_selectedColumns indexGreaterThanIndex: column]; - } + } [_selectedColumns removeAllIndexes]; - _selectedColumn = -1; + _selectedColumn = -1; } - (void) setValue: (id)anObject forKey: (NSString*)aKey @@ -7305,29 +7277,29 @@ - (void) setValue: (id)anObject forKey: (NSString*)aKey else if ([aKey isEqual: NSSelectionIndexesBinding]) { if (_selectingColumns) - { - if (nil == anObject) - { - [self _unselectAllColumns]; - } - else - { - return [self selectColumnIndexes: anObject - byExtendingSelection: NO]; - } - } + { + 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]; - } - } + { + if (nil == anObject) + { + [self _unselectAllRows]; + } + else + { + return [self selectRowIndexes: anObject + byExtendingSelection: NO]; + } + } } else { @@ -7344,13 +7316,13 @@ - (id) valueForKey: (NSString*)aKey else if ([aKey isEqual: NSSelectionIndexesBinding]) { if (_selectingColumns) - { - return [self selectedColumnIndexes]; - } + { + return [self selectedColumnIndexes]; + } else - { - return [self selectedRowIndexes]; - } + { + return [self selectedRowIndexes]; + } } else { diff --git a/Source/NSTreeController.m b/Source/NSTreeController.m index 9cd1ad9bd..13247ff46 100644 --- a/Source/NSTreeController.m +++ b/Source/NSTreeController.m @@ -1,41 +1,13 @@ -/* - NSTreeController.h + /* + NSTreeController.m The tree controller class. - Copyright (C) 2012 Free Software Foundation, Inc. + Copyright (C) 2012, 2024 Free Software Foundation, Inc. Author: Gregory Casamento - Date: 2012 - - This file is part of the GNUstep GUI Library. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. + Date: 2012, 2024 - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; see the file COPYING.LIB. - If not, see or write to the - Free Software Foundation, 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ -/* - NSTreeController.h - - The tree controller class. - - Copyright (C) 2012 Free Software Foundation, Inc. - - Author: Gregory Casamento - Date: 2012 - This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or @@ -50,27 +22,77 @@ You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. - If not, see or write to the - Free Software Foundation, 51 Franklin Street, Fifth Floor, + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ +*/ +#import #import +#import #import +#import +#import +#import +#import #import #import -#import -#import +#import "AppKit/NSOutlineView.h" +#import "AppKit/NSKeyValueBinding.h" +#import "AppKit/NSTreeController.h" +#import "AppKit/NSTreeNode.h" + +#import "GSBindingHelpers.h" +#import "GSFastEnumeration.h" +#import "GSControllerTreeProxy.h" @implementation NSTreeController ++ (void) initialize +{ + if (self == [NSTreeController class]) + { + [self exposeBinding: NSContentArrayBinding]; + [self exposeBinding: NSContentBinding]; + [self exposeBinding: NSSelectionIndexPathsBinding]; + [self setKeys: [NSArray arrayWithObjects: NSContentBinding, NSContentObjectBinding, nil] + triggerChangeNotificationsForDependentKey: @"arrangedObjects"]; + } +} + +- (void) _initDefaults +{ + _childrenKeyPath = nil; + _countKeyPath = nil; + _leafKeyPath = nil; + _sortDescriptors = nil; + _selection_index_paths = [[NSMutableArray alloc] init]; + + _canInsert = YES; + _canInsertChild = YES; + _canAddChild = YES; + + [self setObjectClass: [NSMutableDictionary class]]; +} + - (id) initWithContent: (id)content { if ((self = [super initWithContent: content]) != nil) { + [self _initDefaults]; } - + + return self; +} + +- (id) init +{ + NSMutableArray *array = [[NSMutableArray alloc] init]; + + self = [self initWithContent: array]; + RELEASE(array); + return self; } @@ -80,13 +102,22 @@ - (void) dealloc RELEASE(_countKeyPath); RELEASE(_leafKeyPath); RELEASE(_sortDescriptors); + RELEASE(_arranged_objects); + RELEASE(_selection_index_paths); + [super dealloc]; } -- (BOOL) addSelectionIndexPaths: (NSArray*)indexPaths +- (BOOL) addSelectionIndexPaths: (NSArray *)indexPaths { - // FIXME - return NO; + BOOL f = [self commitEditing]; + + if (YES == f) + { + [_selection_index_paths addObjectsFromArray: indexPaths]; + } + + return f; } - (BOOL) alwaysUsesMultipleValuesMarker @@ -99,22 +130,19 @@ - (BOOL) avoidsEmptySelection return _avoidsEmptySelection; } -- (BOOL) canAddChid +- (BOOL) canAddChild { - // FIXME - return NO; + return _canAddChild; } - (BOOL) canInsert { - // FIXME - return NO; + return _canInsert; } - (BOOL) canInsertChild { - // FIXME - return NO; + return _canInsertChild; } - (BOOL) preservesSelection @@ -127,123 +155,248 @@ - (BOOL) selectsInsertedObjects return _selectsInsertedObjects; } -- (BOOL) setSelectionIndexPath: (NSIndexPath*)indexPath +- (BOOL) setSelectionIndexPath: (NSIndexPath *)indexPath { - // FIXME - return NO; + BOOL f = [self commitEditing]; + + if (YES == f) + { + NSMutableArray *mutable_index_paths = [NSMutableArray arrayWithObject: indexPath]; + ASSIGN(_selection_index_paths, mutable_index_paths); + } + + return f; } -- (BOOL) setSelectionIndexPaths: (NSArray*)indexPaths +- (BOOL) setSelectionIndexPaths: (NSArray *)indexPaths { - // FIXME - return NO; + BOOL f = [self commitEditing]; + + if (YES == f) + { + NSMutableArray *mutable_index_paths = [NSMutableArray arrayWithArray: indexPaths]; + ASSIGN(_selection_index_paths, mutable_index_paths); + } + + return f; } -- (id) arrangedObjects +- (NSTreeNode *) arrangedObjects { - // FIXME - return nil; + if (_arranged_objects == nil) + { + [self rearrangeObjects]; + } + return _arranged_objects; } -- (id) content +- (void) rearrangeObjects { - // FIXME - return [super content]; + [self willChangeValueForKey: @"arrangedObjects"]; + DESTROY(_arranged_objects); + + if ([_content isKindOfClass: [NSArray class]]) + { + _arranged_objects = [[GSControllerTreeProxy alloc] initWithContent: _content + withController: self]; + } + + [self didChangeValueForKey: @"arrangedObjects"]; } -- (NSArray*) selectedObjects +- (id) _objectAtIndexPath: (NSIndexPath *)indexPath { - // FIXME - return [super selectedObjects]; + NSUInteger length = [indexPath length]; + NSUInteger pos = 0; + NSMutableArray *children = [_arranged_objects mutableChildNodes]; + NSUInteger lastIndex = 0; + id obj = nil; + + for (pos = 0; pos < length - 1; pos++) + { + NSUInteger i = [indexPath indexAtPosition: pos]; + id node = [children objectAtIndex: i]; + + children = [node valueForKeyPath: _childrenKeyPath]; + } + + lastIndex = [indexPath indexAtPosition: length - 1]; + obj = [children objectAtIndex: lastIndex]; + + return obj; } -- (NSIndexPath*) selectionIndexPath +- (NSArray *) selectedObjects { - // FIXME - return nil; + NSMutableArray *selectedObjects = [NSMutableArray array]; + + FOR_IN(NSIndexPath*, path, _selection_index_paths) + { + id obj = [self _objectAtIndexPath: path]; + [selectedObjects addObject: obj]; + } + END_FOR_IN(_selection_index_paths); + + return selectedObjects; } -- (NSArray*) selectionIndexPaths +- (NSIndexPath *) selectionIndexPath { - // FIXME + if ([_selection_index_paths count] > 0) + { + return [_selection_index_paths objectAtIndex: 0]; + } return nil; } -- (NSArray*) sortDescriptors +- (NSArray *) selectionIndexPaths { - return _sortDescriptors; + return [_selection_index_paths copy]; } -- (NSString*) childrenKeyPath +- (NSArray *) sortDescriptors { - return _childrenKeyPath; + return [_sortDescriptors copy]; } -- (NSString*) countKeyPath +- (NSString *) childrenKeyPath { - return _countKeyPath;; + return _childrenKeyPath; } -- (NSString*) leafKeyPath +- (NSString *) countKeyPath { - return _leafKeyPath; + return _countKeyPath; } -- (void) addChild: (id)sender +- (NSString *) leafKeyPath { - // FIXME + return _leafKeyPath; } -- (void) add: (id)sender +- (IBAction) add: (id)sender { - // FIXME - [super add: sender]; + NSIndexPath *p = [NSIndexPath indexPathWithIndex: 0]; + id newObject = [self newObject]; + [self insertObject: newObject atArrangedObjectIndexPath: p]; + RELEASE(newObject); } -- (void) insertChild: (id)sender +- (IBAction) addChild: (id)sender { - // FIXME + NSIndexPath *p = [self selectionIndexPath]; + id newObject = [self newObject]; + + if (p != nil) + { + [self insertObject: newObject atArrangedObjectIndexPath: p]; + RELEASE(newObject); + } } -- (void) insertObject: (id)object atArrangedObjectIndexPath: (NSIndexPath*)indexPath +- (IBAction) remove: (id)sender { - // FIXME + if ([self canRemove] + && [self countKeyPath] == nil) + { + if ([_selection_index_paths count] > 0) + { + NSIndexPath *p = [self selectionIndexPath]; + [self removeObjectAtArrangedObjectIndexPath: p]; + } + } } -- (void) insertObjects: (NSArray*)objects atArrangedObjectIndexPaths: (NSArray*)indexPaths +- (IBAction) insertChild: (id)sender { - // FIXME + [self addChild: sender]; } -- (void) insert: (id)sender +- (void) insertObject: (id)object atArrangedObjectIndexPath: (NSIndexPath *)indexPath { - // FIXME + if ([self canAddChild] + && [self countKeyPath] == nil) + { + NSUInteger length = [indexPath length]; + NSUInteger pos = 0; + NSMutableArray *children = [_arranged_objects mutableChildNodes]; + + for (pos = 0; pos < length - 1; pos++) + { + NSUInteger i = [indexPath indexAtPosition: pos]; + id node = [children objectAtIndex: i]; + + children = [node valueForKeyPath: _childrenKeyPath]; + } + + [children addObject: object]; + + [self rearrangeObjects]; + } } -- (void) rearrangeObjects +- (void) insertObjects: (NSArray *)objects atArrangedObjectIndexPaths: (NSArray *)indexPaths { - // FIXME + if ([self canAddChild] + && [self countKeyPath] == nil) + { + if ([objects count] != [indexPaths count]) + { + return; + } + else + { + NSUInteger i = 0; + + FOR_IN(id, object, objects) + { + NSIndexPath *indexPath = [indexPaths objectAtIndex: i]; + + [self insertObject: object atArrangedObjectIndexPath: indexPath]; + i++; + } + END_FOR_IN(objects); + } + } } -- (void) removeObjectAtArrangedObjectIndexPath: (NSIndexPath*)indexPath +- (IBAction) insert: (id)sender { - // FIXME + [self addChild: sender]; } -- (void) removeObjectsAtArrangedObjectIndexPaths: (NSArray*)indexPaths +- (void) removeObjectAtArrangedObjectIndexPath: (NSIndexPath *)indexPath { - // FIXME + NSUInteger length = [indexPath length]; + NSUInteger pos = 0; + NSMutableArray *children = [_arranged_objects mutableChildNodes]; + NSUInteger lastIndex = 0; + + for (pos = 0; pos < length - 1; pos++) + { + NSUInteger i = [indexPath indexAtPosition: pos]; + id node = [children objectAtIndex: i]; + + children = [node valueForKeyPath: _childrenKeyPath]; + } + + lastIndex = [indexPath indexAtPosition: length - 1]; + [children removeObjectAtIndex: lastIndex]; + [self rearrangeObjects]; } -- (void) removeSelectionIndexPaths: (NSArray*)indexPaths +- (void) removeObjectsAtArrangedObjectIndexPaths: (NSArray *)indexPaths { - // FIXME + FOR_IN(NSIndexPath*, indexPath, indexPaths) + { + [self removeObjectAtArrangedObjectIndexPath: indexPath]; + } + END_FOR_IN(indexPaths); } -- (void) remove: (id)sender +- (void) removeSelectionIndexPaths: (NSArray *)indexPaths { - // FIXME - [super remove: sender]; + [self removeObjectsAtArrangedObjectIndexPaths: indexPaths]; } - (void) setAlwaysUsesMultipleValuesMarker: (BOOL)flag @@ -256,23 +409,23 @@ - (void) setAvoidsEmptySelection: (BOOL)flag _avoidsEmptySelection = flag; } -- (void) setChildrenKeyPath: (NSString*)path +- (void) setChildrenKeyPath: (NSString *)path { ASSIGN(_childrenKeyPath, path); } - (void) setContent: (id)content { - // FIXME [super setContent: content]; + [self rearrangeObjects]; } -- (void) setCountKeyPath: (NSString*)path +- (void) setCountKeyPath: (NSString *)path { ASSIGN(_countKeyPath, path); } -- (void) setLeafPathKey: (NSString*)key +- (void) setLeafKeyPath: (NSString *)key { ASSIGN(_leafKeyPath, key); } @@ -287,58 +440,204 @@ - (void) setSelectsInsertedObjects: (BOOL)flag _selectsInsertedObjects = flag; } -- (void) setSortDescriptors: (NSArray*)descriptors +- (void) setSortDescriptors: (NSArray *)descriptors { ASSIGN(_sortDescriptors, descriptors); } -- (NSString*) childrenKeyPathForNode: (NSTreeNode*)node +- (NSString *) childrenKeyPathForNode: (NSTreeNode *)node { - // FIXME - return nil; + return _childrenKeyPath; } -- (NSString*) countKeyPathForNode: (NSTreeNode*)node +- (NSString *) countKeyPathForNode: (NSTreeNode *)node { - // FIXME - return nil; + return _countKeyPath; } -- (NSString*) leafKeyPathForNode: (NSTreeNode*)node +- (NSString *) leafKeyPathForNode: (NSTreeNode *)node { - // FIXME - return nil; + return _leafKeyPath; } -- (void) moveNode: (NSTreeNode*)node toIndexPath: (NSIndexPath*)indexPath +- (void) moveNode: (NSTreeNode *)node toIndexPath: (NSIndexPath *)indexPath { // FIXME } -- (void) moveNodes: (NSArray*)nodes toIndexPath: (NSIndexPath*)startingIndexPath +- (void) moveNodes: (NSArray *)nodes toIndexPath: (NSIndexPath *)startingIndexPath { // FIXME } -- (NSArray*) selectedNodes +- (NSArray *) selectedNodes { // FIXME - return nil; + return [self selectedObjects]; +} + + +- (void) bind: (NSString *)binding + toObject: (id)anObject + withKeyPath: (NSString *)keyPath + options: (NSDictionary *)options +{ + if ([binding isEqual: NSContentArrayBinding]) + { + GSKeyValueBinding *kvb; + + [self unbind: binding]; + kvb = [[GSKeyValueBinding alloc] initWithBinding: @"content" + withName: binding + toObject: anObject + withKeyPath: keyPath + options: options + fromObject: self]; + // The binding will be retained in the binding table + RELEASE(kvb); + } + else + { + [super bind: binding + toObject: anObject + withKeyPath: keyPath + options: options]; + } } -- (id) initWithCoder: (NSCoder*)coder +- (id) initWithCoder: (NSCoder *)coder { + self = [super initWithCoder: coder]; + + if (self != nil) + { + [self _initDefaults]; // set up default values... + if ([coder allowsKeyedCoding]) + { + // These names do not stick to convention. Usually it would be + // NS* or NSTreeController* so they must be overriden in + // GSXib5KeyedUnarchver. + if ([coder containsValueForKey: @"NSTreeContentChildrenKey"]) + { + [self setChildrenKeyPath: + [coder decodeObjectForKey: @"NSTreeContentChildrenKey"]]; + } + if ([coder containsValueForKey: @"NSTreeContentCountKey"]) + { + [self setCountKeyPath: + [coder decodeObjectForKey: @"NSTreeContentCountKey"]]; + } + if ([coder containsValueForKey: @"NSTreeContentLeafKey"]) + { + [self setLeafKeyPath: + [coder decodeObjectForKey: @"NSTreeContentLeafKey"]]; + } + + // Since we don't inherit from NSArrayController these are decoded here + // as well. + if ([coder containsValueForKey: @"NSAvoidsEmptySelection"]) + { + [self setAvoidsEmptySelection: + [coder decodeBoolForKey: @"NSAvoidsEmptySelection"]]; + } + if ([coder containsValueForKey: @"NSPreservesSelection"]) + { + [self setPreservesSelection: + [coder decodeBoolForKey: @"NSPreservesSelection"]]; + } + if ([coder containsValueForKey: @"NSSelectsInsertedObjects"]) + { + [self setSelectsInsertedObjects: + [coder decodeBoolForKey: @"NSSelectsInsertedObjects"]]; + } + } + } + else + { + id obj = nil; + BOOL f = NO; + + obj = [coder decodeObject]; + [self setChildrenKeyPath: obj]; + obj = [coder decodeObject]; + [self setCountKeyPath: obj]; + obj = [coder decodeObject]; + [self setLeafKeyPath: obj]; + + [coder decodeValueOfObjCType: @encode(BOOL) + at: &f]; + [self setAvoidsEmptySelection: f]; + [coder decodeValueOfObjCType: @encode(BOOL) + at: &f]; + [self setPreservesSelection: f]; + [coder decodeValueOfObjCType: @encode(BOOL) + at: &f]; + [self setSelectsInsertedObjects: f]; + } + return self; } -- (void) encodeWithCoder: (NSCoder*)coder +- (void) encodeWithCoder: (NSCoder *)coder { - // Do nothing... + [super encodeWithCoder: coder]; + if ([coder allowsKeyedCoding]) + { + [coder encodeObject: _childrenKeyPath + forKey: @"NSTreeContentChildrenKey"]; + [coder encodeObject: _countKeyPath + forKey: @"NSTreeContentCountKey"]; + [coder encodeObject: _leafKeyPath + forKey: @"NSTreeContentLeafKey"]; + + + [coder encodeBool: _avoidsEmptySelection + forKey: @"NSAvoidsEmptySelection"]; + [coder encodeBool: _preservesSelection + forKey: @"NSPreservesSelection"]; + [coder encodeBool: _selectsInsertedObjects + forKey: @"NSSelectsInsertedObjects"]; + } + else + { + id obj = nil; + BOOL f = NO; + + obj = [self childrenKeyPath]; + [coder encodeObject: obj]; + obj = [self countKeyPath]; + [coder encodeObject: obj]; + obj = [self leafKeyPath]; + [coder encodeObject: obj]; + + f = [self avoidsEmptySelection]; + [coder encodeValueOfObjCType: @encode(BOOL) + at: &f]; + f = [self preservesSelection]; + [coder encodeValueOfObjCType: @encode(BOOL) + at: &f]; + f = [self selectsInsertedObjects]; + [coder encodeValueOfObjCType: @encode(BOOL) + at: &f]; + } } -- (id) copyWithZone: (NSZone*)zone +- (id) copyWithZone: (NSZone *)zone { - return [self retain]; + id copy = [[NSTreeController allocWithZone: zone] initWithContent: [self content]]; + + if (copy != nil) + { + [copy setChildrenKeyPath: [self childrenKeyPath]]; + [copy setCountKeyPath: [self countKeyPath]]; + [copy setLeafKeyPath: [self leafKeyPath]]; + + [copy setAvoidsEmptySelection: [self avoidsEmptySelection]]; + [copy setPreservesSelection: [self preservesSelection]]; + [copy setSelectsInsertedObjects: [self selectsInsertedObjects]]; + } + + return copy; } @end diff --git a/Source/NSTreeNode.m b/Source/NSTreeNode.m index 2d80fcdd2..12f20ff6d 100644 --- a/Source/NSTreeNode.m +++ b/Source/NSTreeNode.m @@ -32,7 +32,7 @@ #import #import -#import +#import "AppKit/NSTreeNode.h" @interface NSTreeNode (Private) - (NSMutableArray*) _childNodes; @@ -159,7 +159,7 @@ - (NSIndexPath*) indexPath NSIndexPath *path; NSUInteger index; - index = [_parentNode->_childNodes indexOfObject: self]; + index = [[_parentNode childNodes] indexOfObject: self]; path = [_parentNode indexPath]; if (path != nil) { @@ -248,4 +248,10 @@ - (void) sortWithSortDescriptors: (NSArray*)sortDescs recursively: (BOOL)flag } } +- (NSString *) description +{ + return [NSString stringWithFormat: @"<%@> _representedObject = %@, _childNode = %@, _parentNode = %@", + [super description], _representedObject, _childNodes, _parentNode]; +} + @end diff --git a/Source/externs.m b/Source/externs.m index c4464829f..fa0cc71b6 100644 --- a/Source/externs.m +++ b/Source/externs.m @@ -711,6 +711,7 @@ APPKIT_DECLARE NSString *NSSelectedTagBinding = @"selectedTag"; APPKIT_DECLARE NSString *NSSelectedValueBinding = @"selectedValue"; APPKIT_DECLARE NSString *NSSelectionIndexesBinding = @"selectionIndexes"; +APPKIT_DECLARE NSString *NSSelectionIndexPathsBinding = @"selectionIndexPaths"; APPKIT_DECLARE NSString *NSSortDescriptorsBinding = @"sortDescriptors"; APPKIT_DECLARE NSString *NSTextColorBinding = @"textColor"; APPKIT_DECLARE NSString *NSTitleBinding = @"title";