mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-22 18:11:06 +00:00
Merge pull request #277 from gnustep/NSTreeController_branch2
Updated PR for NSOutlineView/NSTreeController due to refactor
This commit is contained in:
commit
b003db284e
22 changed files with 2490 additions and 1357 deletions
20
ChangeLog
20
ChangeLog
|
@ -1,3 +1,21 @@
|
|||
2024-08-18 Gregory John Casamento <greg.casamento@gmail.com>
|
||||
|
||||
* 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 <greg.casamento@gmail.com>
|
||||
|
||||
* 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 <greg.casamento@gmail.com>
|
||||
|
||||
* Headers/Additions/GNUstepGUI/GSTheme.h: Add new methods
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
NSTreeController.h
|
||||
|
||||
The tree controller class.
|
||||
|
@ -7,7 +7,7 @@
|
|||
|
||||
Author: Gregory Casamento <greg.casamento@gmail.com>
|
||||
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 <http://www.gnu.org/licenses/> or write to the
|
||||
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||
If not, see <http://www.gnu.org/licenses/> 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 <AppKit/NSObjectController.h>
|
||||
#import <AppKit/NSNibDeclarations.h>
|
||||
|
||||
@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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -304,6 +304,7 @@ NSWindowController.m \
|
|||
NSWorkspace.m \
|
||||
GSAnimator.m \
|
||||
GSAutocompleteWindow.m \
|
||||
GSControllerTreeProxy.m \
|
||||
GSDisplayServer.m \
|
||||
GSHelpManagerPanel.m \
|
||||
GSInfoPanel.m \
|
||||
|
|
|
@ -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
|
||||
|
|
59
Source/GSControllerTreeProxy.h
Normal file
59
Source/GSControllerTreeProxy.h
Normal file
|
@ -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 */
|
||||
|
90
Source/GSControllerTreeProxy.m
Normal file
90
Source/GSControllerTreeProxy.m
Normal file
|
@ -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 <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#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
|
||||
|
|
@ -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 @@ static NSDictionary *titleTextAttributes[3] = {nil, nil, nil};
|
|||
{
|
||||
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 @@ static NSDictionary *titleTextAttributes[3] = {nil, nil, nil};
|
|||
{
|
||||
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 @@ static NSDictionary *titleTextAttributes[3] = {nil, nil, nil};
|
|||
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 @@ static NSDictionary *titleTextAttributes[3] = {nil, nil, nil};
|
|||
}
|
||||
else
|
||||
{
|
||||
[cell setObjectValue: [dataSource outlineView: outlineView
|
||||
objectValueForTableColumn: tb
|
||||
byItem: item]];
|
||||
id value = [outlineView _objectValueForTableColumn: tb
|
||||
row: rowIndex];
|
||||
[cell setObjectValue: value];
|
||||
}
|
||||
|
||||
drawingRect = [outlineView frameOfCellAtColumn: i
|
||||
|
|
|
@ -330,6 +330,9 @@ static NSArray *XmlBoolDefaultYes = nil;
|
|||
@"shadow", @"NSViewShadow",
|
||||
@"blurRadius", @"NSShadowBlurRadius",
|
||||
@"color", @"NSShadowColor",
|
||||
@"childrenKeyPath", @"NSTreeContentChildrenKey", // NSTreeController
|
||||
@"countKeyPath", @"NSTreeContentCountKey",
|
||||
@"leafKeyPath", @"NSTreeContentLeafKey",
|
||||
nil];
|
||||
RETAIN(XmlKeyMapTable);
|
||||
|
||||
|
|
|
@ -147,6 +147,7 @@
|
|||
if (self == [NSArrayController class])
|
||||
{
|
||||
[self exposeBinding: NSContentArrayBinding];
|
||||
[self exposeBinding: NSSelectionIndexesBinding];
|
||||
[self setKeys: [NSArray arrayWithObjects: NSContentBinding, NSContentObjectBinding, nil]
|
||||
triggerChangeNotificationsForDependentKey: @"arrangedObjects"];
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
|
||||
#import "GNUstepGUI/GSTheme.h"
|
||||
#import "GSGuiPrivate.h"
|
||||
#import "GSBindingHelpers.h"
|
||||
|
||||
/* Cache */
|
||||
static CGFloat scrollerWidth; // == [NSScroller scrollerWidth];
|
||||
|
@ -2569,6 +2570,8 @@ static BOOL browserUseBezels;
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
[GSKeyValueBinding unbindAllForObject: self];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
||||
|
||||
if ([titleCell controlView] == self)
|
||||
|
|
|
@ -122,6 +122,7 @@ static NSNotificationCenter *nc;
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
[GSKeyValueBinding unbindAllForObject: self];
|
||||
RELEASE(_cell);
|
||||
[super dealloc];
|
||||
}
|
||||
|
|
|
@ -192,8 +192,11 @@ void GSBindingInvokeAction(NSString *targetKey, NSString *argumentKey,
|
|||
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 GSBindingInvokeAction(NSString *targetKey, NSString *argumentKey,
|
|||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) observedObject
|
||||
{
|
||||
return [info objectForKey: NSObservedObjectKey];
|
||||
}
|
||||
|
||||
- (id) destinationValue
|
||||
{
|
||||
id newValue;
|
||||
|
|
|
@ -99,6 +99,8 @@
|
|||
{
|
||||
if (self == [NSObjectController class])
|
||||
{
|
||||
[self setVersion: 1];
|
||||
|
||||
[self exposeBinding: NSContentObjectBinding];
|
||||
[self setKeys: [NSArray arrayWithObject: @"editable"]
|
||||
triggerChangeNotificationsForDependentKey: @"canAdd"];
|
||||
|
@ -155,11 +157,13 @@
|
|||
[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 @@
|
|||
[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)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <math.h>
|
||||
|
||||
static NSMapTableKeyCallBacks keyCallBacks;
|
||||
|
@ -143,6 +149,24 @@ static NSImage *unexpandable = nil;
|
|||
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 @@ static NSImage *unexpandable = nil;
|
|||
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 @@ static NSImage *unexpandable = nil;
|
|||
*/
|
||||
- (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 @@ static NSImage *unexpandable = nil;
|
|||
*/
|
||||
- (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 @@ static NSImage *unexpandable = nil;
|
|||
*/
|
||||
- (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 @@ Also returns the child index relative to this parent. */
|
|||
@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 @@ Also returns the child index relative to this parent. */
|
|||
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 @@ Also returns the child index relative to this parent. */
|
|||
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 @@ Also returns the child index relative to this parent. */
|
|||
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 @@ Also returns the child index relative to this parent. */
|
|||
forTableColumn: (NSTableColumn *)tb
|
||||
row: (NSInteger) index
|
||||
{
|
||||
if ([_dataSource respondsToSelector:
|
||||
@selector(outlineView:setObjectValue:forTableColumn:byItem:)])
|
||||
{
|
||||
id item = [self itemAtRow: index];
|
||||
NSString *keyPath = [tb _keyPathForValueBinding];
|
||||
|
||||
[_dataSource outlineView: self
|
||||
setObjectValue: value
|
||||
forTableColumn: tb
|
||||
byItem: item];
|
||||
// If we have content binding the data source is used only
|
||||
// like a delegate
|
||||
if (keyPath != nil)
|
||||
{
|
||||
id theItem = [_items objectAtIndex: index];
|
||||
|
||||
// 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 @@ Also returns the child index relative to this parent. */
|
|||
- (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 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;
|
||||
|
||||
/* 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (num > 0)
|
||||
else
|
||||
{
|
||||
anarray = [NSMutableArray array];
|
||||
NSMapInsert(_itemDict, sitem, anarray);
|
||||
}
|
||||
/* 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];
|
||||
}
|
||||
|
||||
NSMapInsert(_levelOfItems, sitem, [NSNumber numberWithInteger: level]);
|
||||
if (num > 0)
|
||||
{
|
||||
anarray = [NSMutableArray arrayWithCapacity: num];
|
||||
NSMapInsert(_itemDict, sitem, anarray);
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
id anitem = [_dataSource outlineView: self
|
||||
child: i
|
||||
ofItem: startitem];
|
||||
NSMapInsert(_levelOfItems, sitem, [NSNumber numberWithInteger: level]);
|
||||
|
||||
[anarray addObject: anitem];
|
||||
[self _loadDictionaryStartingWith: anitem
|
||||
atLevel: level + 1];
|
||||
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 @@ Also returns the child index relative to this parent. */
|
|||
drawingRect: drawingRect
|
||||
rowIndex: row];
|
||||
}
|
||||
|
||||
|
||||
if (view == nil
|
||||
&& flag == YES)
|
||||
{
|
||||
|
|
|
@ -97,6 +97,10 @@
|
|||
[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 @@ to YES. */
|
|||
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 @@ to YES. */
|
|||
{
|
||||
// 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 @@ to YES. */
|
|||
// FIXME
|
||||
return [NSNumber numberWithBool: YES];
|
||||
}
|
||||
else if ([aKey isEqual: NSEditableBinding])
|
||||
{
|
||||
return [NSNumber numberWithBool: _is_editable];
|
||||
}
|
||||
else
|
||||
{
|
||||
return [super valueForKey: aKey];
|
||||
|
|
2128
Source/NSTableView.m
2128
Source/NSTableView.m
File diff suppressed because it is too large
Load diff
|
@ -1,13 +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 <greg.casamento@gmail.com>
|
||||
Date: 2012
|
||||
|
||||
Date: 2012, 2024
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
|
@ -22,55 +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 <http://www.gnu.org/licenses/> or write to the
|
||||
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||
If not, see <http://www.gnu.org/licenses/> 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 <greg.casamento@gmail.com>
|
||||
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.
|
||||
|
||||
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 <http://www.gnu.org/licenses/> or write to the
|
||||
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
*/
|
||||
|
||||
#import <Foundation/NSArchiver.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSIndexPath.h>
|
||||
#import <Foundation/NSKeyedArchiver.h>
|
||||
#import <Foundation/NSKeyValueCoding.h>
|
||||
#import <Foundation/NSKeyValueObserving.h>
|
||||
#import <Foundation/NSNotification.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSSortDescriptor.h>
|
||||
|
||||
#import <AppKit/NSTreeController.h>
|
||||
#import <AppKit/NSTreeNode.h>
|
||||
#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 @@
|
|||
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 @@
|
|||
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 @@
|
|||
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;
|
||||
}
|
||||
|
||||
- (id) content
|
||||
{
|
||||
// FIXME
|
||||
return [super content];
|
||||
}
|
||||
|
||||
- (NSArray*) selectedObjects
|
||||
{
|
||||
// FIXME
|
||||
return [super selectedObjects];
|
||||
}
|
||||
|
||||
- (NSIndexPath*) selectionIndexPath
|
||||
{
|
||||
// FIXME
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSArray*) selectionIndexPaths
|
||||
{
|
||||
// FIXME
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSArray*) sortDescriptors
|
||||
{
|
||||
return _sortDescriptors;
|
||||
}
|
||||
|
||||
- (NSString*) childrenKeyPath
|
||||
{
|
||||
return _childrenKeyPath;
|
||||
}
|
||||
|
||||
- (NSString*) countKeyPath
|
||||
{
|
||||
return _countKeyPath;;
|
||||
}
|
||||
|
||||
- (NSString*) leafKeyPath
|
||||
{
|
||||
return _leafKeyPath;
|
||||
}
|
||||
|
||||
- (void) addChild: (id)sender
|
||||
{
|
||||
// FIXME
|
||||
}
|
||||
|
||||
- (void) add: (id)sender
|
||||
{
|
||||
// FIXME
|
||||
[super add: sender];
|
||||
}
|
||||
|
||||
- (void) insertChild: (id)sender
|
||||
{
|
||||
// FIXME
|
||||
}
|
||||
|
||||
- (void) insertObject: (id)object atArrangedObjectIndexPath: (NSIndexPath*)indexPath
|
||||
{
|
||||
// FIXME
|
||||
}
|
||||
|
||||
- (void) insertObjects: (NSArray*)objects atArrangedObjectIndexPaths: (NSArray*)indexPaths
|
||||
{
|
||||
// FIXME
|
||||
}
|
||||
|
||||
- (void) insert: (id)sender
|
||||
{
|
||||
// FIXME
|
||||
if (_arranged_objects == nil)
|
||||
{
|
||||
[self rearrangeObjects];
|
||||
}
|
||||
return _arranged_objects;
|
||||
}
|
||||
|
||||
- (void) rearrangeObjects
|
||||
{
|
||||
// FIXME
|
||||
[self willChangeValueForKey: @"arrangedObjects"];
|
||||
DESTROY(_arranged_objects);
|
||||
|
||||
if ([_content isKindOfClass: [NSArray class]])
|
||||
{
|
||||
_arranged_objects = [[GSControllerTreeProxy alloc] initWithContent: _content
|
||||
withController: self];
|
||||
}
|
||||
|
||||
[self didChangeValueForKey: @"arrangedObjects"];
|
||||
}
|
||||
|
||||
- (void) removeObjectAtArrangedObjectIndexPath: (NSIndexPath*)indexPath
|
||||
- (id) _objectAtIndexPath: (NSIndexPath *)indexPath
|
||||
{
|
||||
// FIXME
|
||||
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;
|
||||
}
|
||||
|
||||
- (void) removeObjectsAtArrangedObjectIndexPaths: (NSArray*)indexPaths
|
||||
- (NSArray *) selectedObjects
|
||||
{
|
||||
// FIXME
|
||||
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;
|
||||
}
|
||||
|
||||
- (void) removeSelectionIndexPaths: (NSArray*)indexPaths
|
||||
- (NSIndexPath *) selectionIndexPath
|
||||
{
|
||||
// FIXME
|
||||
if ([_selection_index_paths count] > 0)
|
||||
{
|
||||
return [_selection_index_paths objectAtIndex: 0];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void) remove: (id)sender
|
||||
- (NSArray *) selectionIndexPaths
|
||||
{
|
||||
// FIXME
|
||||
[super remove: sender];
|
||||
return [_selection_index_paths copy];
|
||||
}
|
||||
|
||||
- (NSArray *) sortDescriptors
|
||||
{
|
||||
return [_sortDescriptors copy];
|
||||
}
|
||||
|
||||
- (NSString *) childrenKeyPath
|
||||
{
|
||||
return _childrenKeyPath;
|
||||
}
|
||||
|
||||
- (NSString *) countKeyPath
|
||||
{
|
||||
return _countKeyPath;
|
||||
}
|
||||
|
||||
- (NSString *) leafKeyPath
|
||||
{
|
||||
return _leafKeyPath;
|
||||
}
|
||||
|
||||
- (IBAction) add: (id)sender
|
||||
{
|
||||
NSIndexPath *p = [NSIndexPath indexPathWithIndex: 0];
|
||||
id newObject = [self newObject];
|
||||
[self insertObject: newObject atArrangedObjectIndexPath: p];
|
||||
RELEASE(newObject);
|
||||
}
|
||||
|
||||
- (IBAction) addChild: (id)sender
|
||||
{
|
||||
NSIndexPath *p = [self selectionIndexPath];
|
||||
id newObject = [self newObject];
|
||||
|
||||
if (p != nil)
|
||||
{
|
||||
[self insertObject: newObject atArrangedObjectIndexPath: p];
|
||||
RELEASE(newObject);
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction) remove: (id)sender
|
||||
{
|
||||
if ([self canRemove]
|
||||
&& [self countKeyPath] == nil)
|
||||
{
|
||||
if ([_selection_index_paths count] > 0)
|
||||
{
|
||||
NSIndexPath *p = [self selectionIndexPath];
|
||||
[self removeObjectAtArrangedObjectIndexPath: p];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction) insertChild: (id)sender
|
||||
{
|
||||
[self addChild: sender];
|
||||
}
|
||||
|
||||
- (void) insertObject: (id)object atArrangedObjectIndexPath: (NSIndexPath *)indexPath
|
||||
{
|
||||
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) insertObjects: (NSArray *)objects atArrangedObjectIndexPaths: (NSArray *)indexPaths
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction) insert: (id)sender
|
||||
{
|
||||
[self addChild: sender];
|
||||
}
|
||||
|
||||
- (void) removeObjectAtArrangedObjectIndexPath: (NSIndexPath *)indexPath
|
||||
{
|
||||
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) removeObjectsAtArrangedObjectIndexPaths: (NSArray *)indexPaths
|
||||
{
|
||||
FOR_IN(NSIndexPath*, indexPath, indexPaths)
|
||||
{
|
||||
[self removeObjectAtArrangedObjectIndexPath: indexPath];
|
||||
}
|
||||
END_FOR_IN(indexPaths);
|
||||
}
|
||||
|
||||
- (void) removeSelectionIndexPaths: (NSArray *)indexPaths
|
||||
{
|
||||
[self removeObjectsAtArrangedObjectIndexPaths: indexPaths];
|
||||
}
|
||||
|
||||
- (void) setAlwaysUsesMultipleValuesMarker: (BOOL)flag
|
||||
|
@ -256,23 +409,23 @@
|
|||
_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 @@
|
|||
_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];
|
||||
}
|
||||
|
||||
- (id) initWithCoder: (NSCoder*)coder
|
||||
|
||||
- (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
|
||||
{
|
||||
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
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSSortDescriptor.h>
|
||||
|
||||
#import <AppKit/NSTreeNode.h>
|
||||
#import "AppKit/NSTreeNode.h"
|
||||
|
||||
@interface NSTreeNode (Private)
|
||||
- (NSMutableArray*) _childNodes;
|
||||
|
@ -159,7 +159,7 @@
|
|||
NSIndexPath *path;
|
||||
NSUInteger index;
|
||||
|
||||
index = [_parentNode->_childNodes indexOfObject: self];
|
||||
index = [[_parentNode childNodes] indexOfObject: self];
|
||||
path = [_parentNode indexPath];
|
||||
if (path != nil)
|
||||
{
|
||||
|
@ -248,4 +248,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (NSString *) description
|
||||
{
|
||||
return [NSString stringWithFormat: @"<%@> _representedObject = %@, _childNode = %@, _parentNode = %@",
|
||||
[super description], _representedObject, _childNodes, _parentNode];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -711,6 +711,7 @@ APPKIT_DECLARE NSString *NSSelectedObjectBinding = @"selectedObject";
|
|||
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";
|
||||
|
|
Loading…
Reference in a new issue