2001-12-17 16:51:51 +00:00
|
|
|
/** <title>NSOutlineView</title>
|
2001-10-25 21:41:03 +00:00
|
|
|
|
2001-12-17 16:51:51 +00:00
|
|
|
<abstract>The outline class.</abstract>
|
2001-10-25 21:41:03 +00:00
|
|
|
|
|
|
|
Copyright (C) 2001 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
Author: Gregory John Casamento <greg_casamento@yahoo.com>
|
|
|
|
Date: October 2001
|
|
|
|
|
|
|
|
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 Library 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
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
License along with this library; see the file COPYING.LIB.
|
|
|
|
If not, write to the Free Software Foundation,
|
|
|
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
2002-04-11 23:17:42 +00:00
|
|
|
#include <AppKit/NSOutlineView.h>
|
|
|
|
#include <Foundation/NSNotification.h>
|
|
|
|
#include <Foundation/NSNull.h>
|
|
|
|
#include <Foundation/NSValue.h>
|
|
|
|
#include <Foundation/NSException.h>
|
|
|
|
#include <Foundation/NSUserDefaults.h>
|
|
|
|
#include <Foundation/NSArray.h>
|
|
|
|
#include <Foundation/NSMapTable.h>
|
|
|
|
#include <AppKit/NSApplication.h>
|
|
|
|
#include <AppKit/NSCell.h>
|
|
|
|
#include <AppKit/NSFont.h>
|
|
|
|
#include <AppKit/NSClipView.h>
|
|
|
|
#include <AppKit/NSColor.h>
|
|
|
|
#include <AppKit/NSEvent.h>
|
|
|
|
#include <AppKit/NSGraphics.h>
|
|
|
|
#include <AppKit/NSScroller.h>
|
|
|
|
#include <AppKit/NSImage.h>
|
|
|
|
#include <AppKit/NSTableColumn.h>
|
|
|
|
#include <AppKit/NSTableHeaderView.h>
|
|
|
|
#include <AppKit/NSText.h>
|
|
|
|
#include <AppKit/NSTextFieldCell.h>
|
|
|
|
#include <AppKit/NSWindow.h>
|
|
|
|
#include <AppKit/PSOperators.h>
|
|
|
|
#include <AppKit/NSCachedImageRep.h>
|
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
|
|
|
|
static NSNotificationCenter *nc = nil;
|
|
|
|
static const int current_version = 1;
|
|
|
|
|
2002-03-22 00:15:03 +00:00
|
|
|
int NSOutlineViewDropOnItemIndex = -1;
|
|
|
|
|
|
|
|
static int lastVerticalQuarterPosition;
|
|
|
|
static int lastHorizontalHalfPosition;
|
|
|
|
|
|
|
|
static NSRect oldDraggingRect;
|
|
|
|
static int oldDropRow;
|
|
|
|
static int oldProposedDropRow;
|
|
|
|
static int currentDropRow;
|
|
|
|
static int oldDropLevel;
|
|
|
|
static int currentDropLevel;
|
|
|
|
|
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
// Cache the arrow images...
|
2002-03-02 22:20:52 +00:00
|
|
|
static NSImage *collapsed = nil;
|
|
|
|
static NSImage *expanded = nil;
|
2002-03-03 05:58:51 +00:00
|
|
|
static NSImage *unexpandable = nil;
|
2002-02-23 16:37:17 +00:00
|
|
|
|
2002-03-04 23:53:27 +00:00
|
|
|
@interface NSOutlineView (NotificationRequestMethods)
|
|
|
|
- (void) _postSelectionIsChangingNotification;
|
|
|
|
- (void) _postSelectionDidChangeNotification;
|
|
|
|
- (void) _postColumnDidMoveNotificationWithOldIndex: (int) oldIndex
|
|
|
|
newIndex: (int) newIndex;
|
|
|
|
- (void) _postColumnDidResizeNotification;
|
|
|
|
- (BOOL) _shouldSelectTableColumn: (NSTableColumn *)tableColumn;
|
|
|
|
- (BOOL) _shouldSelectRow: (int)rowIndex;
|
|
|
|
- (BOOL) _shouldSelectionChange;
|
|
|
|
- (BOOL) _shouldEditTableColumn: (NSTableColumn *)tableColumn
|
|
|
|
row: (int) rowIndex;
|
|
|
|
@end
|
2002-02-23 16:37:17 +00:00
|
|
|
|
2002-03-23 16:39:19 +00:00
|
|
|
// These methods are private...
|
2002-02-23 16:37:17 +00:00
|
|
|
@interface NSOutlineView (TableViewInternalPrivate)
|
|
|
|
- (void) _setSelectingColumns: (BOOL)flag;
|
|
|
|
- (BOOL) _editNextEditableCellAfterRow: (int)row
|
|
|
|
column: (int)column;
|
|
|
|
- (BOOL) _editPreviousEditableCellBeforeRow: (int)row
|
|
|
|
column: (int)column;
|
2002-04-02 05:04:57 +00:00
|
|
|
- (void) _autosaveExpandedItems;
|
|
|
|
- (void) _autoloadExpandedItems;
|
2002-02-23 16:37:17 +00:00
|
|
|
- (void) _openItem: (id)item;
|
|
|
|
- (void) _closeItem: (id)item;
|
|
|
|
@end
|
2001-10-25 21:41:03 +00:00
|
|
|
|
|
|
|
@implementation NSOutlineView
|
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
// Initialize the class when it is loaded
|
|
|
|
+ (void) initialize
|
|
|
|
{
|
|
|
|
if (self == [NSOutlineView class])
|
|
|
|
{
|
|
|
|
[self setVersion: current_version];
|
|
|
|
nc = [NSNotificationCenter defaultCenter];
|
2002-03-23 16:39:19 +00:00
|
|
|
collapsed = [NSImage imageNamed: @"common_outlineCollapsed.tiff"];
|
|
|
|
expanded = [NSImage imageNamed: @"common_outlineExpanded.tiff"];
|
2002-03-03 05:58:51 +00:00
|
|
|
unexpandable = [NSImage imageNamed: @"common_outlineUnexpandable.tiff"];
|
2002-02-23 16:37:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-10-25 21:41:03 +00:00
|
|
|
// Instance methods
|
2002-02-23 16:37:17 +00:00
|
|
|
- (id)initWithFrame: (NSRect)frame
|
2001-10-25 21:41:03 +00:00
|
|
|
{
|
2002-02-23 16:37:17 +00:00
|
|
|
[super initWithFrame: frame];
|
|
|
|
|
2002-03-23 16:39:19 +00:00
|
|
|
// Initial values
|
2002-04-26 04:30:04 +00:00
|
|
|
_indentationMarkerFollowsCell = YES;
|
2002-02-24 03:10:16 +00:00
|
|
|
_autoResizesOutlineColumn = NO;
|
2002-02-23 16:37:17 +00:00
|
|
|
_autosaveExpandedItems = NO;
|
2002-02-24 03:10:16 +00:00
|
|
|
_indentationPerLevel = 0.0;
|
2001-10-25 21:41:03 +00:00
|
|
|
_outlineTableColumn = nil;
|
2002-04-01 16:03:02 +00:00
|
|
|
_itemDict = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
|
|
|
NSObjectMapValueCallBacks,
|
|
|
|
64);
|
2002-02-23 16:37:17 +00:00
|
|
|
_items = [NSMutableArray array];
|
|
|
|
_expandedItems = [NSMutableArray array];
|
2002-04-01 16:03:02 +00:00
|
|
|
_levelOfItems = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
|
|
|
NSObjectMapValueCallBacks,
|
|
|
|
64);
|
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
|
|
|
|
// Retain items
|
|
|
|
RETAIN(_items);
|
|
|
|
RETAIN(_expandedItems);
|
2001-10-25 21:41:03 +00:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)autoResizesOutlineColumn
|
|
|
|
{
|
2002-02-24 03:10:16 +00:00
|
|
|
return _autoResizesOutlineColumn;
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)autosaveExpandedItems
|
|
|
|
{
|
2002-02-23 16:37:17 +00:00
|
|
|
return _autosaveExpandedItems;
|
|
|
|
}
|
|
|
|
|
2002-03-03 05:58:51 +00:00
|
|
|
// Collect all of the items under a given element.
|
2002-03-23 16:39:19 +00:00
|
|
|
- (void)_collectItemsStartingWith: (id)startitem
|
|
|
|
into: (NSMutableArray *)allChildren
|
2002-03-03 05:58:51 +00:00
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
int num = 0;
|
2002-03-03 05:58:51 +00:00
|
|
|
int i = 0;
|
2002-04-01 16:03:02 +00:00
|
|
|
id object = nil;
|
2002-03-23 16:39:19 +00:00
|
|
|
|
2002-04-01 16:03:02 +00:00
|
|
|
object = NSMapGet(_itemDict, startitem);
|
|
|
|
num = [object count];
|
2002-03-06 01:45:33 +00:00
|
|
|
for(i = 0; i < num; i++)
|
2002-03-03 05:58:51 +00:00
|
|
|
{
|
2002-04-01 16:03:02 +00:00
|
|
|
id obj = NSMapGet(_itemDict, startitem);
|
|
|
|
id anitem = [obj objectAtIndex: i];
|
2002-03-03 05:58:51 +00:00
|
|
|
|
|
|
|
// Only collect the children if the item is expanded
|
2002-03-23 16:39:19 +00:00
|
|
|
if([self isItemExpanded: startitem])
|
2002-03-03 05:58:51 +00:00
|
|
|
{
|
|
|
|
[allChildren addObject: anitem];
|
|
|
|
}
|
|
|
|
|
2002-03-23 16:39:19 +00:00
|
|
|
[self _collectItemsStartingWith: anitem
|
|
|
|
into: allChildren];
|
2002-03-03 05:58:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-03-28 00:23:37 +00:00
|
|
|
- (void) _loadDictionaryStartingWith: (id) startitem
|
|
|
|
atLevel: (int) level
|
|
|
|
{
|
|
|
|
int num = [_dataSource outlineView: self
|
|
|
|
numberOfChildrenOfItem: startitem];
|
|
|
|
int i = 0;
|
2002-04-01 16:03:02 +00:00
|
|
|
id sitem = (startitem == nil)?[NSNull null]:startitem;
|
2002-03-28 00:23:37 +00:00
|
|
|
|
|
|
|
if(num > 0)
|
|
|
|
{
|
2002-04-01 16:03:02 +00:00
|
|
|
NSMapInsert(_itemDict, sitem, [NSMutableArray array]);
|
2002-03-28 00:23:37 +00:00
|
|
|
}
|
|
|
|
|
2002-04-01 16:03:02 +00:00
|
|
|
NSMapInsert(_levelOfItems, sitem, [NSNumber numberWithInt: level]);
|
2002-03-28 00:23:37 +00:00
|
|
|
|
|
|
|
for(i = 0; i < num; i++)
|
|
|
|
{
|
|
|
|
id anitem = [_dataSource outlineView: self
|
|
|
|
child: i
|
|
|
|
ofItem: startitem];
|
2002-04-01 16:03:02 +00:00
|
|
|
|
|
|
|
id anarray = NSMapGet(_itemDict, sitem);
|
2002-03-28 00:23:37 +00:00
|
|
|
|
|
|
|
[anarray addObject: anitem];
|
|
|
|
[self _loadDictionaryStartingWith: anitem
|
|
|
|
atLevel: level + 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
- (void)_closeItem: (id)item
|
|
|
|
{
|
2002-03-03 05:58:51 +00:00
|
|
|
int numchildren = 0;
|
2002-02-23 16:37:17 +00:00
|
|
|
int i = 0;
|
2002-03-03 05:58:51 +00:00
|
|
|
NSMutableArray *removeAll = [NSMutableArray array];
|
|
|
|
|
2002-03-23 16:39:19 +00:00
|
|
|
[self _collectItemsStartingWith: item into: removeAll];
|
2002-03-03 05:58:51 +00:00
|
|
|
numchildren = [removeAll count];
|
2002-02-23 16:37:17 +00:00
|
|
|
|
|
|
|
// close the item...
|
2002-03-06 01:45:33 +00:00
|
|
|
if(item != nil)
|
2002-02-23 16:37:17 +00:00
|
|
|
{
|
|
|
|
[_expandedItems removeObject: item];
|
|
|
|
}
|
|
|
|
|
|
|
|
// For the close method it doesn't matter what order they are
|
|
|
|
// removed in.
|
2002-03-03 05:58:51 +00:00
|
|
|
for(i=0; i < numchildren; i++)
|
2002-02-23 16:37:17 +00:00
|
|
|
{
|
2002-03-03 05:58:51 +00:00
|
|
|
id child = [removeAll objectAtIndex: i];
|
2002-02-23 16:37:17 +00:00
|
|
|
[_items removeObject: child];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)_openItem: (id)item
|
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
int numchildren = 0;
|
2002-02-23 16:37:17 +00:00
|
|
|
int i = 0;
|
|
|
|
int insertionPoint = 0;
|
2002-04-01 16:03:02 +00:00
|
|
|
id object = nil;
|
|
|
|
id sitem = (item == nil)?[NSNull null]:item;
|
|
|
|
|
|
|
|
object = NSMapGet(_itemDict, sitem);
|
|
|
|
numchildren = [object count];
|
2002-03-23 16:39:19 +00:00
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
// open the item...
|
2002-03-06 01:45:33 +00:00
|
|
|
if(item != nil)
|
2002-02-23 16:37:17 +00:00
|
|
|
{
|
|
|
|
[_expandedItems addObject: item];
|
|
|
|
}
|
|
|
|
|
|
|
|
insertionPoint = [_items indexOfObject: item];
|
|
|
|
if(insertionPoint == NSNotFound)
|
|
|
|
{
|
|
|
|
insertionPoint = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
insertionPoint++;
|
|
|
|
}
|
|
|
|
|
|
|
|
[self setNeedsDisplay: YES];
|
2002-03-06 01:45:33 +00:00
|
|
|
for(i=numchildren-1; i >= 0; i--)
|
2002-02-23 16:37:17 +00:00
|
|
|
{
|
2002-04-01 16:03:02 +00:00
|
|
|
id obj = NSMapGet(_itemDict, sitem);
|
|
|
|
id child = [obj objectAtIndex: i];
|
2002-03-03 05:58:51 +00:00
|
|
|
|
|
|
|
// Add all of the children...
|
|
|
|
if([self isItemExpanded: child])
|
|
|
|
{
|
|
|
|
NSMutableArray *insertAll = [NSMutableArray array];
|
|
|
|
int i = 0, numitems = 0;
|
|
|
|
|
2002-03-23 16:39:19 +00:00
|
|
|
[self _collectItemsStartingWith: child into: insertAll];
|
2002-03-03 05:58:51 +00:00
|
|
|
numitems = [insertAll count];
|
2002-03-23 16:39:19 +00:00
|
|
|
for(i = numitems-1; i >= 0; i--)
|
2002-03-03 05:58:51 +00:00
|
|
|
{
|
|
|
|
[_items insertObject: [insertAll objectAtIndex: i]
|
|
|
|
atIndex: insertionPoint];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the parent
|
2002-02-23 16:37:17 +00:00
|
|
|
[_items insertObject: child atIndex: insertionPoint];
|
|
|
|
}
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)collapseItem: (id)item
|
|
|
|
{
|
2002-02-23 16:37:17 +00:00
|
|
|
[self collapseItem: item collapseChildren: NO];
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)collapseItem: (id)item collapseChildren: (BOOL)collapseChildren
|
|
|
|
{
|
2002-02-23 16:37:17 +00:00
|
|
|
const SEL shouldSelector = @selector(outlineView:shouldCollapseItem:);
|
|
|
|
BOOL canCollapse = YES;
|
|
|
|
|
|
|
|
if([_delegate respondsToSelector: shouldSelector])
|
|
|
|
{
|
|
|
|
canCollapse = [_delegate outlineView: self shouldCollapseItem: item];
|
|
|
|
}
|
|
|
|
|
|
|
|
if([self isExpandable: item] && [self isItemExpanded: item] && canCollapse)
|
|
|
|
{
|
2002-02-27 06:05:33 +00:00
|
|
|
NSMutableDictionary *infoDict = [NSMutableDictionary dictionary];
|
2002-02-23 16:37:17 +00:00
|
|
|
[infoDict setObject: item forKey: @"NSObject"];
|
|
|
|
|
|
|
|
// Send out the notification to let observers know that this is about
|
|
|
|
// to occur.
|
|
|
|
[nc postNotificationName: NSOutlineViewItemWillCollapseNotification
|
|
|
|
object: self
|
|
|
|
userInfo: infoDict];
|
|
|
|
|
|
|
|
// collapse...
|
|
|
|
[self _closeItem: item];
|
|
|
|
|
|
|
|
// Send out the notification to let observers know that this has
|
|
|
|
// occured.
|
|
|
|
[nc postNotificationName: NSOutlineViewItemDidCollapseNotification
|
|
|
|
object: self
|
|
|
|
userInfo: infoDict];
|
|
|
|
|
|
|
|
|
|
|
|
if(collapseChildren) // collapse all
|
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
int numchild = 0;
|
2002-02-23 16:37:17 +00:00
|
|
|
int index = 0;
|
2002-03-23 16:39:19 +00:00
|
|
|
NSMutableArray *allChildren = [NSMutableArray array];
|
|
|
|
|
|
|
|
[self _collectItemsStartingWith: item into: allChildren];
|
|
|
|
numchild = [allChildren count];
|
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
for(index = 0;index < numchild;index++)
|
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
id child = [allChildren objectAtIndex: index];
|
|
|
|
|
|
|
|
if([self isExpandable: child] &&
|
|
|
|
[self isItemExpanded: child])
|
2002-02-23 16:37:17 +00:00
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
NSMutableDictionary *childDict = [NSDictionary dictionary];
|
|
|
|
[childDict setObject: child forKey: @"NSObject"];
|
|
|
|
|
|
|
|
// Send out the notification to let observers know
|
|
|
|
// that this is about to occur.
|
|
|
|
[nc postNotificationName: NSOutlineViewItemWillCollapseNotification
|
|
|
|
object: self
|
|
|
|
userInfo: childDict];
|
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
[self _closeItem: child];
|
2002-03-23 16:39:19 +00:00
|
|
|
|
|
|
|
// Send out the notification to let observers know that
|
|
|
|
// this is about to occur.
|
|
|
|
[nc postNotificationName: NSOutlineViewItemDidCollapseNotification
|
|
|
|
object: self
|
|
|
|
userInfo: childDict];
|
2002-02-23 16:37:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-03-23 16:39:19 +00:00
|
|
|
[self noteNumberOfRowsChanged];
|
2002-02-23 16:37:17 +00:00
|
|
|
}
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)expandItem: (id)item
|
|
|
|
{
|
2002-02-23 16:37:17 +00:00
|
|
|
[self expandItem: item expandChildren: NO];
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)expandItem:(id)item expandChildren:(BOOL)expandChildren
|
|
|
|
{
|
2002-02-23 16:37:17 +00:00
|
|
|
const SEL shouldExpandSelector = @selector(outlineView:shouldExpandItem:);
|
|
|
|
BOOL canExpand = YES;
|
|
|
|
|
|
|
|
if([_delegate respondsToSelector: shouldExpandSelector])
|
|
|
|
{
|
|
|
|
canExpand = [_delegate outlineView: self shouldExpandItem: item];
|
|
|
|
}
|
|
|
|
|
|
|
|
if([self isExpandable: item] && ![self isItemExpanded: item] && canExpand)
|
|
|
|
{
|
2002-02-24 03:10:16 +00:00
|
|
|
NSMutableDictionary *infoDict = [NSMutableDictionary dictionary];
|
2002-02-23 16:37:17 +00:00
|
|
|
|
|
|
|
[infoDict setObject: item forKey: @"NSObject"];
|
|
|
|
|
|
|
|
// Send out the notification to let observers know that this is about
|
|
|
|
// to occur.
|
|
|
|
[nc postNotificationName: NSOutlineViewItemWillExpandNotification
|
|
|
|
object: self
|
|
|
|
userInfo: infoDict];
|
|
|
|
|
|
|
|
// insert the root element, if necessary otherwise insert the
|
|
|
|
// actual object.
|
|
|
|
[self _openItem: item];
|
|
|
|
|
|
|
|
// Send out the notification to let observers know that this has
|
|
|
|
// occured.
|
|
|
|
[nc postNotificationName: NSOutlineViewItemDidExpandNotification
|
|
|
|
object: self
|
|
|
|
userInfo: infoDict];
|
|
|
|
|
|
|
|
if(expandChildren) // expand all
|
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
NSMutableArray *allChildren = nil;
|
|
|
|
int numchild = 0;
|
2002-02-23 16:37:17 +00:00
|
|
|
int index = 0;
|
2002-03-23 16:39:19 +00:00
|
|
|
|
|
|
|
[self _collectItemsStartingWith: item into: allChildren];
|
|
|
|
numchild = [allChildren count];
|
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
for(index = 0;index < numchild;index++)
|
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
id child = [allChildren objectAtIndex: index];
|
|
|
|
|
|
|
|
if([self isExpandable: child] &&
|
|
|
|
![self isItemExpanded: child])
|
2002-02-23 16:37:17 +00:00
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
NSMutableDictionary *childDict = [NSMutableDictionary dictionary];
|
|
|
|
|
|
|
|
[childDict setObject: child forKey: @"NSObject"];
|
|
|
|
// Send out the notification to let observers know that this has
|
|
|
|
// occured.
|
|
|
|
[nc postNotificationName: NSOutlineViewItemWillExpandNotification
|
|
|
|
object: self
|
|
|
|
userInfo: childDict];
|
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
[self _openItem: child];
|
2002-03-23 16:39:19 +00:00
|
|
|
|
|
|
|
// Send out the notification to let observers know that this has
|
|
|
|
// occured.
|
|
|
|
[nc postNotificationName: NSOutlineViewItemDidExpandNotification
|
|
|
|
object: self
|
|
|
|
userInfo: childDict];
|
2002-02-23 16:37:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-03-23 16:39:19 +00:00
|
|
|
[self noteNumberOfRowsChanged];
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)indentationMarkerFollowsCell
|
|
|
|
{
|
2002-02-24 03:10:16 +00:00
|
|
|
return _indentationMarkerFollowsCell;
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (float)indentationPerLevel
|
|
|
|
{
|
2002-02-24 03:10:16 +00:00
|
|
|
return _indentationPerLevel;
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isExpandable: (id)item
|
|
|
|
{
|
2002-02-23 16:37:17 +00:00
|
|
|
return [_dataSource outlineView: self isItemExpandable: item];
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isItemExpanded: (id)item
|
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
if(item == nil)
|
|
|
|
return YES;
|
2002-02-23 16:37:17 +00:00
|
|
|
|
|
|
|
// Check the array to determine if it is expanded.
|
2002-03-23 16:39:19 +00:00
|
|
|
return([_expandedItems containsObject: item]);
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id)itemAtRow: (int)row
|
|
|
|
{
|
2002-02-23 16:37:17 +00:00
|
|
|
return [_items objectAtIndex: row];
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
2002-02-27 06:05:33 +00:00
|
|
|
- (int)levelForItem: (id)item
|
2001-10-25 21:41:03 +00:00
|
|
|
{
|
2002-02-27 06:05:33 +00:00
|
|
|
if(item != nil)
|
|
|
|
{
|
2002-04-01 16:03:02 +00:00
|
|
|
id object = NSMapGet(_levelOfItems, item);
|
|
|
|
return [object intValue];
|
2002-02-27 06:05:33 +00:00
|
|
|
}
|
|
|
|
|
2001-10-25 21:41:03 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2002-02-27 06:05:33 +00:00
|
|
|
- (int)levelForRow: (int)row
|
|
|
|
{
|
|
|
|
return [self levelForItem: [self itemAtRow: row]];
|
|
|
|
}
|
|
|
|
|
2001-10-25 21:41:03 +00:00
|
|
|
- (NSTableColumn *)outlineTableColumn
|
|
|
|
{
|
|
|
|
return _outlineTableColumn;
|
|
|
|
}
|
|
|
|
|
2002-03-23 16:39:19 +00:00
|
|
|
- (BOOL)_findItem: (id)item
|
|
|
|
childIndex: (int *)index
|
|
|
|
ofParent: (id)parent
|
|
|
|
{
|
2002-04-01 16:03:02 +00:00
|
|
|
NSArray *allKeys = NSAllMapTableKeys(_itemDict);
|
2002-03-23 16:39:19 +00:00
|
|
|
BOOL hasChildren = NO;
|
|
|
|
NSEnumerator *en = [allKeys objectEnumerator];
|
|
|
|
id object = nil;
|
|
|
|
|
|
|
|
// initial values for return parameters
|
|
|
|
*index = NSNotFound;
|
|
|
|
parent = nil;
|
|
|
|
|
|
|
|
if([allKeys containsObject: item])
|
|
|
|
{
|
|
|
|
hasChildren = YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
while((object = [en nextObject]))
|
|
|
|
{
|
2002-04-01 16:03:02 +00:00
|
|
|
NSArray *childArray = NSMapGet(_itemDict, object);
|
2002-03-23 16:39:19 +00:00
|
|
|
|
|
|
|
if((*index = [childArray indexOfObject: item]) != NSNotFound)
|
|
|
|
{
|
|
|
|
parent = object;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return hasChildren;
|
|
|
|
}
|
|
|
|
|
2001-10-25 21:41:03 +00:00
|
|
|
- (void)reloadItem: (id)item
|
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
[self reloadItem: item reloadChildren: NO];
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)reloadItem: (id)item reloadChildren: (BOOL)reloadChildren
|
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
id parent = nil;
|
|
|
|
id dsobj = nil;
|
|
|
|
BOOL haschildren = NO;
|
|
|
|
int index = 0;
|
2002-04-01 16:03:02 +00:00
|
|
|
id obj = nil;
|
|
|
|
id object = (item == nil)?([NSNull null]):item;
|
2002-03-23 16:39:19 +00:00
|
|
|
|
|
|
|
// find the item
|
|
|
|
haschildren = [self _findItem: object
|
|
|
|
childIndex: &index
|
|
|
|
ofParent: parent];
|
|
|
|
|
|
|
|
dsobj = [_dataSource outlineView: self
|
|
|
|
child: index
|
|
|
|
ofItem: parent];
|
|
|
|
|
2002-04-01 16:03:02 +00:00
|
|
|
obj = NSMapGet(_itemDict, parent);
|
|
|
|
[obj removeObject: item];
|
|
|
|
[obj insertObject: dsobj atIndex: index];
|
2002-03-23 16:39:19 +00:00
|
|
|
|
|
|
|
if(reloadChildren && haschildren) // expand all
|
|
|
|
{
|
2002-04-01 16:03:02 +00:00
|
|
|
[self _loadDictionaryStartingWith: object
|
|
|
|
atLevel: [self levelForItem: object]];
|
2002-03-23 16:39:19 +00:00
|
|
|
|
|
|
|
// release the old array
|
|
|
|
if(_items != nil)
|
|
|
|
{
|
|
|
|
RELEASE(_items);
|
|
|
|
}
|
|
|
|
|
|
|
|
// regenerate the _items array based on the new dictionary
|
|
|
|
[self _openItem: nil];
|
|
|
|
}
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (int)rowForItem: (id)item
|
|
|
|
{
|
2002-02-23 16:37:17 +00:00
|
|
|
return [_items indexOfObject: item];
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setAutoresizesOutlineColumn: (BOOL)resize
|
|
|
|
{
|
2002-02-24 03:10:16 +00:00
|
|
|
_autoResizesOutlineColumn = resize;
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setAutosaveExpandedItems: (BOOL)flag
|
|
|
|
{
|
2002-04-02 05:04:57 +00:00
|
|
|
if(flag == _autosaveExpandedItems)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
_autosaveExpandedItems = flag;
|
2002-04-02 05:04:57 +00:00
|
|
|
if(flag)
|
|
|
|
{
|
|
|
|
[self _autoloadExpandedItems];
|
|
|
|
// notify when an item expands...
|
|
|
|
[nc addObserver: self
|
|
|
|
selector: @selector(_autosaveExpandedItems)
|
|
|
|
name: NSOutlineViewItemDidExpandNotification
|
|
|
|
object: self];
|
|
|
|
|
|
|
|
// notify when an item collapses...
|
|
|
|
[nc addObserver: self
|
|
|
|
selector: @selector(_autosaveExpandedItems)
|
|
|
|
name: NSOutlineViewItemDidCollapseNotification
|
|
|
|
object: self];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// notify when an item expands...
|
|
|
|
[nc removeObserver: self
|
|
|
|
name: NSOutlineViewItemDidExpandNotification
|
|
|
|
object: self];
|
|
|
|
|
|
|
|
// notify when an item collapses...
|
|
|
|
[nc removeObserver: self
|
|
|
|
name: NSOutlineViewItemDidCollapseNotification
|
|
|
|
object: self];
|
|
|
|
}
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setIndentationMarkerFollowsCell: (BOOL)followsCell
|
|
|
|
{
|
2002-02-24 03:10:16 +00:00
|
|
|
_indentationMarkerFollowsCell = followsCell;
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setIndentationPerLevel: (float)newIndentLevel
|
|
|
|
{
|
2002-02-24 03:10:16 +00:00
|
|
|
_indentationPerLevel = newIndentLevel;
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setOutlineTableColumn: (NSTableColumn *)outlineTableColumn
|
|
|
|
{
|
|
|
|
_outlineTableColumn = outlineTableColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)shouldCollapseAutoExpandedItemsForDeposited: (BOOL)deposited
|
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
return YES;
|
2001-10-25 21:41:03 +00:00
|
|
|
}
|
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
- (void) noteNumberOfRowsChanged
|
|
|
|
{
|
|
|
|
_numberOfRows = [_items count];
|
2002-03-28 00:23:37 +00:00
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
/* If we are selecting rows, we have to check that we have no
|
|
|
|
selected rows below the new end of the table */
|
|
|
|
if (!_selectingColumns)
|
|
|
|
{
|
|
|
|
int i, count = [_selectedRows count];
|
|
|
|
int row = -1;
|
|
|
|
|
|
|
|
/* Check that all selected rows are in the new range of rows */
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
row = [[_selectedRows objectAtIndex: i] intValue];
|
|
|
|
|
|
|
|
if (row >= _numberOfRows)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i < count && row > -1)
|
|
|
|
{
|
|
|
|
/* Some of them are outside the table ! - Remove them */
|
|
|
|
for (; i < count; i++)
|
|
|
|
{
|
|
|
|
[_selectedRows removeLastObject];
|
|
|
|
}
|
|
|
|
/* Now if the _selectedRow is outside the table, reset it to be
|
|
|
|
the last selected row (if any) */
|
|
|
|
if (_selectedRow >= _numberOfRows)
|
|
|
|
{
|
|
|
|
if ([_selectedRows count] > 0)
|
|
|
|
{
|
|
|
|
_selectedRow = [[_selectedRows lastObject] intValue];
|
|
|
|
}
|
|
|
|
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 */
|
|
|
|
int lastRow = _numberOfRows - 1;
|
|
|
|
|
|
|
|
if (lastRow > -1)
|
|
|
|
{
|
|
|
|
[_selectedRows addObject:
|
|
|
|
[NSNumber numberWithInt: lastRow]];
|
|
|
|
_selectedRow = lastRow;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* problem - there are no rows at all */
|
|
|
|
_selectedRow = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[self setFrame: NSMakeRect (_frame.origin.x,
|
|
|
|
_frame.origin.y,
|
|
|
|
_frame.size.width,
|
|
|
|
(_numberOfRows * _rowHeight) + 1)];
|
|
|
|
|
|
|
|
/* If we are shorter in height than the enclosing clipview, we
|
|
|
|
should redraw us now. */
|
|
|
|
if (_super_view != nil)
|
|
|
|
{
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setDataSource: (id)anObject
|
|
|
|
{
|
|
|
|
NSArray *requiredMethods =
|
|
|
|
[NSArray arrayWithObjects: @"outlineView:child:ofItem:",
|
|
|
|
@"outlineView:isItemExpandable:",
|
|
|
|
@"outlineView:numberOfChildrenOfItem:",
|
|
|
|
@"outlineView:objectValueForTableColumn:byItem:",
|
|
|
|
nil];
|
|
|
|
NSEnumerator *en = [requiredMethods objectEnumerator];
|
|
|
|
NSString *selectorName = nil;
|
|
|
|
|
|
|
|
// Is the data source editable?
|
|
|
|
_dataSource_editable = [anObject respondsToSelector:
|
|
|
|
@selector(outlineView:setObjectValue:forTableColumn:byItem:)];
|
|
|
|
|
|
|
|
while((selectorName = [en nextObject]) != nil)
|
|
|
|
{
|
|
|
|
SEL sel = NSSelectorFromString(selectorName);
|
|
|
|
if ([anObject respondsToSelector: sel] == NO)
|
|
|
|
{
|
|
|
|
[NSException
|
|
|
|
raise: NSInternalInconsistencyException
|
|
|
|
format: @"Data Source doesn't respond to %@",
|
|
|
|
selectorName];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We do *not* retain the dataSource, it's like a delegate */
|
|
|
|
_dataSource = anObject;
|
|
|
|
[self tile];
|
|
|
|
[self reloadData];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) reloadData
|
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
// release the old array
|
|
|
|
if(_items != nil)
|
2002-02-23 16:37:17 +00:00
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
RELEASE(_items);
|
|
|
|
}
|
|
|
|
|
2002-04-01 16:03:02 +00:00
|
|
|
if(_itemDict != NULL)
|
2002-03-23 16:39:19 +00:00
|
|
|
{
|
2002-04-01 16:03:02 +00:00
|
|
|
NSFreeMapTable(_itemDict);
|
2002-02-23 16:37:17 +00:00
|
|
|
}
|
2002-03-23 16:39:19 +00:00
|
|
|
|
2002-04-01 16:03:02 +00:00
|
|
|
if(_levelOfItems != NULL)
|
2002-03-28 00:23:37 +00:00
|
|
|
{
|
2002-04-01 16:03:02 +00:00
|
|
|
NSFreeMapTable(_levelOfItems);
|
2002-03-28 00:23:37 +00:00
|
|
|
}
|
|
|
|
|
2002-03-23 16:39:19 +00:00
|
|
|
// create a new empty one
|
|
|
|
_items = RETAIN([NSMutableArray array]);
|
2002-04-01 16:03:02 +00:00
|
|
|
_itemDict = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
|
|
|
NSObjectMapValueCallBacks,
|
|
|
|
64);
|
|
|
|
_levelOfItems = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
|
|
|
NSObjectMapValueCallBacks,
|
|
|
|
64);
|
2002-03-23 16:39:19 +00:00
|
|
|
|
|
|
|
// reload all the open items...
|
2002-03-28 00:23:37 +00:00
|
|
|
[self _loadDictionaryStartingWith: nil
|
|
|
|
atLevel: -1];
|
2002-03-23 16:39:19 +00:00
|
|
|
[self _openItem: nil];
|
2002-02-23 16:37:17 +00:00
|
|
|
[super reloadData];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setDelegate: (id)anObject
|
2002-04-18 22:44:04 +00:00
|
|
|
{
|
2002-02-23 16:37:17 +00:00
|
|
|
if (_delegate)
|
|
|
|
[nc removeObserver: _delegate name: nil object: self];
|
|
|
|
_delegate = anObject;
|
|
|
|
|
|
|
|
#define SET_DELEGATE_NOTIFICATION(notif_name) \
|
|
|
|
if ([_delegate respondsToSelector: @selector(outlineView##notif_name:)]) \
|
|
|
|
[nc addObserver: _delegate \
|
|
|
|
selector: @selector(outlineView##notif_name:) \
|
|
|
|
name: NSOutlineView##notif_name##Notification object: self]
|
|
|
|
|
|
|
|
SET_DELEGATE_NOTIFICATION(ColumnDidMove);
|
|
|
|
SET_DELEGATE_NOTIFICATION(ColumnDidResize);
|
|
|
|
SET_DELEGATE_NOTIFICATION(SelectionDidChange);
|
|
|
|
SET_DELEGATE_NOTIFICATION(SelectionIsChanging);
|
|
|
|
SET_DELEGATE_NOTIFICATION(ItemDidExpand);
|
|
|
|
SET_DELEGATE_NOTIFICATION(ItemDidCollapse);
|
|
|
|
SET_DELEGATE_NOTIFICATION(ItemWillExpand);
|
|
|
|
SET_DELEGATE_NOTIFICATION(ItemWillCollapse);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
|
|
|
{
|
|
|
|
[super encodeWithCoder: aCoder];
|
|
|
|
|
2002-02-24 03:10:16 +00:00
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &_autoResizesOutlineColumn];
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &_indentationMarkerFollowsCell];
|
2002-02-23 16:37:17 +00:00
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &_autosaveExpandedItems];
|
2002-02-24 03:10:16 +00:00
|
|
|
[aCoder encodeValueOfObjCType: @encode(float) at: &_indentationPerLevel];
|
2002-02-23 16:37:17 +00:00
|
|
|
[aCoder encodeConditionalObject: _outlineTableColumn];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithCoder: (NSCoder *)aDecoder
|
|
|
|
{
|
|
|
|
// Since we only have one version....
|
|
|
|
self = [super initWithCoder: aDecoder];
|
|
|
|
|
2002-02-24 03:10:16 +00:00
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_autoResizesOutlineColumn];
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_indentationMarkerFollowsCell];
|
2002-02-23 16:37:17 +00:00
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_autosaveExpandedItems];
|
2002-02-24 03:10:16 +00:00
|
|
|
[aDecoder decodeValueOfObjCType: @encode(float) at: &_indentationPerLevel];
|
2002-02-23 16:37:17 +00:00
|
|
|
_outlineTableColumn = [aDecoder decodeObject];
|
|
|
|
|
2002-04-01 16:03:02 +00:00
|
|
|
_itemDict = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
|
|
|
NSObjectMapValueCallBacks,
|
|
|
|
64);
|
2002-03-31 15:46:19 +00:00
|
|
|
_items = [NSMutableArray array];
|
|
|
|
_expandedItems = [NSMutableArray array];
|
2002-04-01 16:03:02 +00:00
|
|
|
_levelOfItems = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
|
|
|
NSObjectMapValueCallBacks,
|
|
|
|
64);
|
2002-03-31 15:46:19 +00:00
|
|
|
// Retain items
|
|
|
|
RETAIN(_items);
|
|
|
|
RETAIN(_expandedItems);
|
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) mouseDown: (NSEvent *)theEvent
|
|
|
|
{
|
|
|
|
NSPoint location = [theEvent locationInWindow];
|
|
|
|
NSTableColumn *tb;
|
2002-03-23 16:39:19 +00:00
|
|
|
NSImage *image = nil;
|
2002-02-23 16:37:17 +00:00
|
|
|
|
|
|
|
location = [self convertPoint: location fromView: nil];
|
|
|
|
_clickedRow = [self rowAtPoint: location];
|
|
|
|
_clickedColumn = [self columnAtPoint: location];
|
|
|
|
|
2002-03-23 16:39:19 +00:00
|
|
|
if([self isItemExpanded: [self itemAtRow: _clickedRow]])
|
|
|
|
{
|
|
|
|
image = expanded;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
image = collapsed;
|
|
|
|
}
|
|
|
|
|
2002-03-04 23:53:27 +00:00
|
|
|
tb = [_tableColumns objectAtIndex: _clickedColumn];
|
|
|
|
if(tb == _outlineTableColumn)
|
|
|
|
{
|
|
|
|
int level = [self levelForRow: _clickedRow];
|
|
|
|
int position = 0;
|
|
|
|
|
|
|
|
if(_indentationMarkerFollowsCell)
|
2002-02-23 16:37:17 +00:00
|
|
|
{
|
2002-03-04 23:53:27 +00:00
|
|
|
position = _indentationPerLevel * level;
|
2002-02-23 16:37:17 +00:00
|
|
|
}
|
2002-04-26 04:30:04 +00:00
|
|
|
|
|
|
|
position += _columnOrigins[_clickedColumn];
|
|
|
|
|
2002-03-23 16:39:19 +00:00
|
|
|
if(location.x >= position && location.x <= position + [image size].width)
|
2002-02-23 16:37:17 +00:00
|
|
|
{
|
2002-02-27 06:05:33 +00:00
|
|
|
if(![self isItemExpanded: [self itemAtRow: _clickedRow]])
|
|
|
|
{
|
|
|
|
[self expandItem: [self itemAtRow: _clickedRow]];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self collapseItem: [self itemAtRow: _clickedRow]];
|
|
|
|
}
|
2002-02-23 16:37:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-03-04 23:53:27 +00:00
|
|
|
[super mouseDown: theEvent];
|
|
|
|
}
|
2002-02-23 16:37:17 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Drawing
|
|
|
|
*/
|
|
|
|
- (void)drawRow: (int)rowIndex clipRect: (NSRect)aRect
|
|
|
|
{
|
|
|
|
int startingColumn;
|
|
|
|
int endingColumn;
|
|
|
|
NSTableColumn *tb;
|
|
|
|
NSRect drawingRect;
|
|
|
|
NSCell *cell;
|
|
|
|
NSCell *imageCell = nil;
|
|
|
|
NSRect imageRect;
|
|
|
|
int i;
|
|
|
|
float x_pos;
|
|
|
|
|
|
|
|
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 */
|
|
|
|
|
2002-03-28 00:23:37 +00:00
|
|
|
if(rowIndex >= _numberOfRows)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
/* Determine starting column as fast as possible */
|
|
|
|
x_pos = NSMinX (aRect);
|
|
|
|
i = 0;
|
|
|
|
while ((x_pos > _columnOrigins[i]) && (i < _numberOfColumns))
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
startingColumn = (i - 1);
|
|
|
|
|
|
|
|
if (startingColumn == -1)
|
|
|
|
startingColumn = 0;
|
|
|
|
|
|
|
|
/* Determine ending column as fast as possible */
|
|
|
|
x_pos = NSMaxX (aRect);
|
|
|
|
// Nota Bene: we do *not* reset i
|
|
|
|
while ((x_pos > _columnOrigins[i]) && (i < _numberOfColumns))
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
endingColumn = (i - 1);
|
|
|
|
|
|
|
|
if (endingColumn == -1)
|
|
|
|
endingColumn = _numberOfColumns - 1;
|
|
|
|
|
|
|
|
/* Draw the row between startingColumn and endingColumn */
|
|
|
|
for (i = startingColumn; i <= endingColumn; i++)
|
|
|
|
{
|
|
|
|
if (i != _editedColumn || rowIndex != _editedRow)
|
|
|
|
{
|
|
|
|
id item = [self itemAtRow: rowIndex];
|
|
|
|
|
|
|
|
tb = [_tableColumns objectAtIndex: i];
|
|
|
|
cell = [tb dataCellForRow: rowIndex];
|
|
|
|
|
2002-04-18 22:44:04 +00:00
|
|
|
if ([_delegate respondsToSelector: @selector(outlineView:willDisplayCell:forTableColumn:item:)])
|
2002-02-23 16:37:17 +00:00
|
|
|
{
|
|
|
|
[_delegate outlineView: self
|
|
|
|
willDisplayCell: cell
|
|
|
|
forTableColumn: tb
|
|
|
|
item: item];
|
|
|
|
}
|
|
|
|
|
|
|
|
[cell setObjectValue: [_dataSource outlineView: self
|
|
|
|
objectValueForTableColumn: tb
|
|
|
|
byItem: item]];
|
|
|
|
drawingRect = [self frameOfCellAtColumn: i
|
|
|
|
row: rowIndex];
|
|
|
|
|
|
|
|
if(tb == _outlineTableColumn)
|
|
|
|
{
|
2002-03-02 22:20:52 +00:00
|
|
|
NSImage *image = nil;
|
2002-02-27 06:05:33 +00:00
|
|
|
int level = 0;
|
|
|
|
float indentationFactor = 0.0;
|
2002-03-23 16:39:19 +00:00
|
|
|
// float originalWidth = drawingRect.size.width;
|
2002-02-24 03:10:16 +00:00
|
|
|
|
|
|
|
// display the correct arrow...
|
|
|
|
if([self isItemExpanded: item])
|
|
|
|
{
|
2002-03-02 22:20:52 +00:00
|
|
|
image = expanded;
|
2002-02-24 03:10:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-03-02 22:20:52 +00:00
|
|
|
image = collapsed;
|
2002-02-24 03:10:16 +00:00
|
|
|
}
|
|
|
|
|
2002-03-03 05:58:51 +00:00
|
|
|
if(![self isExpandable: item])
|
|
|
|
{
|
|
|
|
image = unexpandable;
|
|
|
|
}
|
|
|
|
|
2002-02-27 06:05:33 +00:00
|
|
|
level = [self levelForItem: item];
|
|
|
|
indentationFactor = _indentationPerLevel * level;
|
2002-03-02 22:20:52 +00:00
|
|
|
imageCell = [[NSCell alloc] initImageCell: image];
|
2002-02-27 06:05:33 +00:00
|
|
|
|
|
|
|
if(_indentationMarkerFollowsCell)
|
|
|
|
{
|
|
|
|
imageRect.origin.x = drawingRect.origin.x + indentationFactor;
|
|
|
|
imageRect.origin.y = drawingRect.origin.y;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
imageRect.origin.x = drawingRect.origin.x;
|
|
|
|
imageRect.origin.y = drawingRect.origin.y;
|
|
|
|
}
|
|
|
|
|
2002-03-02 22:20:52 +00:00
|
|
|
imageRect.size.width = [image size].width;
|
|
|
|
imageRect.size.height = [image size].height;
|
2002-02-24 03:10:16 +00:00
|
|
|
|
2002-03-03 05:58:51 +00:00
|
|
|
[imageCell drawWithFrame: imageRect inView: self];
|
2002-02-23 16:37:17 +00:00
|
|
|
|
2002-03-04 23:53:27 +00:00
|
|
|
drawingRect.origin.x += indentationFactor + [image size].width + 5;
|
|
|
|
drawingRect.size.width -= indentationFactor + [image size].width + 5;
|
2002-02-27 06:05:33 +00:00
|
|
|
|
2002-02-23 16:37:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
[cell drawWithFrame: drawingRect inView: self];
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-02-27 06:05:33 +00:00
|
|
|
- (void) drawRect: (NSRect)aRect
|
2002-02-23 16:37:17 +00:00
|
|
|
{
|
2002-02-27 06:05:33 +00:00
|
|
|
int index = 0;
|
2002-02-23 16:37:17 +00:00
|
|
|
|
2002-03-23 16:39:19 +00:00
|
|
|
if(_autoResizesOutlineColumn)
|
2002-02-23 16:37:17 +00:00
|
|
|
{
|
2002-03-23 16:39:19 +00:00
|
|
|
float widest = 0;
|
|
|
|
for(index = 0;index < _numberOfRows; index++)
|
|
|
|
{
|
|
|
|
float offset = [self levelForRow: index] *
|
|
|
|
[self indentationPerLevel];
|
|
|
|
NSRect drawingRect = [self frameOfCellAtColumn: 0
|
|
|
|
row: index];
|
|
|
|
float length = drawingRect.size.width + offset;
|
|
|
|
if(widest < length) widest = length;
|
|
|
|
}
|
|
|
|
// [_outlineTableColumn setWidth: widest];
|
2002-02-23 16:37:17 +00:00
|
|
|
}
|
|
|
|
|
2002-02-27 06:05:33 +00:00
|
|
|
[super drawRect: aRect];
|
2002-02-23 16:37:17 +00:00
|
|
|
}
|
2002-02-27 06:05:33 +00:00
|
|
|
|
2002-03-04 23:53:27 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* (NotificationRequestMethods)
|
|
|
|
*/
|
|
|
|
- (void) _postSelectionIsChangingNotification
|
|
|
|
{
|
|
|
|
[nc postNotificationName:
|
|
|
|
NSOutlineViewSelectionIsChangingNotification
|
|
|
|
object: self];
|
|
|
|
}
|
|
|
|
- (void) _postSelectionDidChangeNotification
|
|
|
|
{
|
|
|
|
[nc postNotificationName:
|
|
|
|
NSOutlineViewSelectionDidChangeNotification
|
|
|
|
object: self];
|
|
|
|
}
|
|
|
|
- (void) _postColumnDidMoveNotificationWithOldIndex: (int) oldIndex
|
|
|
|
newIndex: (int) newIndex
|
|
|
|
{
|
|
|
|
[nc postNotificationName:
|
|
|
|
NSOutlineViewColumnDidMoveNotification
|
|
|
|
object: self
|
|
|
|
userInfo: [NSDictionary
|
|
|
|
dictionaryWithObjectsAndKeys:
|
|
|
|
[NSNumber numberWithInt: newIndex],
|
|
|
|
@"NSNewColumn",
|
|
|
|
[NSNumber numberWithInt: oldIndex],
|
|
|
|
@"NSOldColumn",
|
|
|
|
nil]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _postColumnDidResizeNotificationWithOldWidth: (float) oldWidth
|
|
|
|
{
|
|
|
|
[nc postNotificationName:
|
|
|
|
NSOutlineViewColumnDidResizeNotification
|
|
|
|
object: self
|
|
|
|
userInfo: [NSDictionary
|
|
|
|
dictionaryWithObjectsAndKeys:
|
|
|
|
[NSNumber numberWithFloat: oldWidth],
|
|
|
|
@"NSOldWidth",
|
|
|
|
nil]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) _shouldSelectTableColumn: (NSTableColumn *)tableColumn
|
|
|
|
{
|
|
|
|
if ([_delegate respondsToSelector:
|
|
|
|
@selector (outlineView:shouldSelectTableColumn:)] == YES)
|
|
|
|
{
|
|
|
|
if ([_delegate outlineView: self shouldSelectTableColumn: tableColumn] == NO)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) _shouldSelectRow: (int)rowIndex
|
|
|
|
{
|
|
|
|
id item = [self itemAtRow: rowIndex];
|
|
|
|
|
|
|
|
if ([_delegate respondsToSelector:
|
|
|
|
@selector (outlineView:shouldSelectItem:)] == YES)
|
|
|
|
{
|
|
|
|
if ([_delegate outlineView: self shouldSelectItem: item] == NO)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) _shouldSelectionChange
|
|
|
|
{
|
|
|
|
if ([_delegate respondsToSelector:
|
|
|
|
@selector (selectionShouldChangeInTableView:)] == YES)
|
|
|
|
{
|
|
|
|
if ([_delegate selectionShouldChangeInTableView: self] == NO)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) _shouldEditTableColumn: (NSTableColumn *)tableColumn
|
|
|
|
row: (int) rowIndex
|
|
|
|
{
|
|
|
|
id item = [self itemAtRow: rowIndex];
|
|
|
|
|
|
|
|
if ([_delegate respondsToSelector:
|
|
|
|
@selector(outlineView:shouldEditTableColumn:item:)])
|
|
|
|
{
|
|
|
|
if ([_delegate outlineView: self shouldEditTableColumn: tableColumn
|
|
|
|
item: item] == NO)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
2002-03-22 00:15:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
- (void) setDropItem: (id) item
|
|
|
|
dropChildIndex: (int) childIndex
|
|
|
|
{
|
|
|
|
int row = [_items indexOfObject: item];
|
|
|
|
id itemAfter;
|
|
|
|
|
|
|
|
if (row == NSNotFound)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([self isItemExpanded: item] == NO)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (childIndex == NSOutlineViewDropOnItemIndex)
|
|
|
|
{
|
|
|
|
currentDropRow = row;
|
|
|
|
currentDropLevel = NSOutlineViewDropOnItemIndex;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
itemAfter = [_dataSource outlineView: self
|
|
|
|
child: childIndex
|
|
|
|
ofItem: item];
|
|
|
|
currentDropRow = [_items indexOfObject: itemAfter];
|
|
|
|
currentDropLevel = [self levelForItem: itemAfter];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) _isDraggingSource
|
|
|
|
{
|
|
|
|
return [_dataSource respondsToSelector:
|
|
|
|
@selector(outlineView:writeItems:toPasteboard:)];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) _writeRows: (NSArray *) rows
|
|
|
|
toPasteboard: (NSPasteboard *)pboard
|
|
|
|
{
|
|
|
|
int count = [rows count];
|
|
|
|
int i;
|
|
|
|
NSMutableArray *itemArray = [NSMutableArray
|
|
|
|
arrayWithCapacity: count];
|
|
|
|
|
|
|
|
for ( i = 0; i < count; i++ )
|
|
|
|
{
|
|
|
|
[itemArray addObject:
|
|
|
|
[self itemAtRow:
|
|
|
|
[[rows objectAtIndex: i] intValue]]];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([_dataSource respondsToSelector:
|
|
|
|
@selector(outlineView:writeItems:toPasteboard:)] == YES)
|
|
|
|
{
|
|
|
|
return [_dataSource outlineView: self
|
|
|
|
writeItems: itemArray
|
|
|
|
toPasteboard: pboard];
|
|
|
|
}
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Drag'n'drop support
|
|
|
|
*/
|
|
|
|
|
|
|
|
- (unsigned int) draggingEntered: (id <NSDraggingInfo>) sender
|
|
|
|
{
|
|
|
|
NSLog(@"draggingEntered");
|
|
|
|
currentDropRow = -1;
|
|
|
|
// currentDropOperation = -1;
|
|
|
|
oldDropRow = -1;
|
|
|
|
lastVerticalQuarterPosition = -1;
|
|
|
|
oldDraggingRect = NSMakeRect(0.,0., 0., 0.);
|
|
|
|
return NSDragOperationCopy;
|
|
|
|
}
|
|
|
|
|
2002-03-22 00:29:41 +00:00
|
|
|
- (void) draggingExited: (id <NSDraggingInfo>) sender
|
|
|
|
{
|
|
|
|
[self setNeedsDisplayInRect: oldDraggingRect];
|
|
|
|
[self displayIfNeeded];
|
|
|
|
}
|
2002-03-22 00:15:03 +00:00
|
|
|
|
|
|
|
- (unsigned int) draggingUpdated: (id <NSDraggingInfo>) sender
|
|
|
|
{
|
|
|
|
NSPoint p = [sender draggingLocation];
|
|
|
|
NSRect newRect;
|
|
|
|
int row;
|
|
|
|
int verticalQuarterPosition;
|
|
|
|
int horizontalHalfPosition;
|
|
|
|
int levelBefore;
|
|
|
|
int levelAfter;
|
|
|
|
int level;
|
|
|
|
|
|
|
|
p = [self convertPoint: p fromView: nil];
|
|
|
|
verticalQuarterPosition =
|
|
|
|
(p.y - _bounds.origin.y) / _rowHeight * 4.;
|
|
|
|
horizontalHalfPosition =
|
|
|
|
(p.x - _bounds.origin.y) / _indentationPerLevel * 2.;
|
|
|
|
|
|
|
|
|
|
|
|
if ((verticalQuarterPosition - oldProposedDropRow * 4 <= 2) &&
|
|
|
|
(verticalQuarterPosition - oldProposedDropRow * 4 >= -3) )
|
|
|
|
{
|
|
|
|
row = oldProposedDropRow;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
row = (verticalQuarterPosition + 2) / 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (row > _numberOfRows)
|
|
|
|
row = _numberOfRows;
|
|
|
|
|
|
|
|
// NSLog(@"horizontalHalfPosition = %d", horizontalHalfPosition);
|
|
|
|
|
|
|
|
// NSLog(@"dropRow %d", row);
|
|
|
|
|
|
|
|
if (row == 0)
|
|
|
|
{
|
|
|
|
levelBefore = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
levelBefore = [self levelForRow: (row - 1)];
|
|
|
|
}
|
|
|
|
if (row == _numberOfRows)
|
|
|
|
{
|
|
|
|
levelAfter = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
levelAfter = [self levelForRow: row];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (levelBefore < levelAfter)
|
|
|
|
levelBefore = levelAfter;
|
|
|
|
|
|
|
|
|
|
|
|
// NSLog(@"horizontalHalfPosition = %d", horizontalHalfPosition);
|
|
|
|
// NSLog(@"level before = %d", levelBefore);
|
|
|
|
// NSLog(@"level after = %d", levelAfter);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((lastVerticalQuarterPosition != verticalQuarterPosition)
|
|
|
|
|| (lastHorizontalHalfPosition != horizontalHalfPosition))
|
|
|
|
{
|
|
|
|
id item;
|
|
|
|
int childIndex;
|
|
|
|
|
|
|
|
if (horizontalHalfPosition / 2 < levelAfter)
|
|
|
|
horizontalHalfPosition = levelAfter * 2;
|
|
|
|
else if (horizontalHalfPosition / 2 > levelBefore)
|
|
|
|
horizontalHalfPosition = levelBefore * 2 + 1;
|
|
|
|
level = horizontalHalfPosition / 2;
|
|
|
|
|
|
|
|
|
|
|
|
lastVerticalQuarterPosition = verticalQuarterPosition;
|
|
|
|
lastHorizontalHalfPosition = horizontalHalfPosition;
|
|
|
|
|
|
|
|
// NSLog(@"horizontalHalfPosition = %d", horizontalHalfPosition);
|
|
|
|
// NSLog(@"verticalQuarterPosition = %d", verticalQuarterPosition);
|
|
|
|
|
|
|
|
currentDropRow = row;
|
|
|
|
currentDropLevel = level;
|
|
|
|
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int j = 0;
|
|
|
|
int lvl;
|
|
|
|
for ( i = row - 1; i >= 0; i-- )
|
|
|
|
{
|
|
|
|
lvl = [self levelForRow: i];
|
|
|
|
if (lvl == level - 1)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (lvl == level)
|
|
|
|
{
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// NSLog(@"found %d (proposed childIndex = %d)", i, j);
|
|
|
|
if (i == -1)
|
|
|
|
item = nil;
|
|
|
|
else
|
|
|
|
item = [self itemAtRow: i];
|
|
|
|
|
|
|
|
childIndex = j;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
oldProposedDropRow = currentDropRow;
|
|
|
|
if ([_dataSource respondsToSelector:
|
|
|
|
@selector(outlineView:validateDrop:proposedItem:proposedChildIndex:)])
|
|
|
|
{
|
|
|
|
// NSLog(@"currentDropLevel %d, currentDropRow %d",
|
|
|
|
// currentDropRow, currentDropLevel);
|
|
|
|
[_dataSource outlineView: self
|
|
|
|
validateDrop: sender
|
|
|
|
proposedItem: item
|
|
|
|
proposedChildIndex: childIndex];
|
|
|
|
// NSLog(@"currentDropLevel %d, currentDropRow %d",
|
|
|
|
// currentDropRow, currentDropLevel);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((currentDropRow != oldDropRow) || (currentDropLevel != oldDropLevel))
|
|
|
|
{
|
|
|
|
[self lockFocus];
|
|
|
|
|
|
|
|
[self setNeedsDisplayInRect: oldDraggingRect];
|
|
|
|
[self displayIfNeeded];
|
|
|
|
|
|
|
|
[[NSColor darkGrayColor] set];
|
|
|
|
|
|
|
|
// NSLog(@"currentDropLevel %d, currentDropRow %d",
|
|
|
|
// currentDropRow, currentDropLevel);
|
|
|
|
if (currentDropLevel != NSOutlineViewDropOnItemIndex)
|
|
|
|
{
|
|
|
|
if (currentDropRow == 0)
|
|
|
|
{
|
|
|
|
newRect = NSMakeRect([self visibleRect].origin.x,
|
|
|
|
currentDropRow * _rowHeight,
|
|
|
|
[self visibleRect].size.width,
|
|
|
|
3);
|
|
|
|
}
|
|
|
|
else if (currentDropRow == _numberOfRows)
|
|
|
|
{
|
|
|
|
newRect = NSMakeRect([self visibleRect].origin.x,
|
|
|
|
currentDropRow * _rowHeight - 2,
|
|
|
|
[self visibleRect].size.width,
|
|
|
|
3);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newRect = NSMakeRect([self visibleRect].origin.x,
|
|
|
|
currentDropRow * _rowHeight - 1,
|
|
|
|
[self visibleRect].size.width,
|
|
|
|
3);
|
|
|
|
}
|
|
|
|
newRect.origin.x += currentDropLevel * _indentationPerLevel;
|
|
|
|
newRect.size.width -= currentDropLevel * _indentationPerLevel;
|
|
|
|
NSRectFill(newRect);
|
|
|
|
oldDraggingRect = newRect;
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newRect = [self frameOfCellAtColumn: 0
|
|
|
|
row: currentDropRow];
|
|
|
|
newRect.origin.x = _bounds.origin.x;
|
|
|
|
newRect.size.width = _bounds.size.width + 2;
|
|
|
|
newRect.origin.x -= _intercellSpacing.height / 2;
|
|
|
|
newRect.size.height += _intercellSpacing.height;
|
|
|
|
oldDraggingRect = newRect;
|
|
|
|
oldDraggingRect.origin.y -= 1;
|
|
|
|
oldDraggingRect.size.height += 2;
|
|
|
|
|
|
|
|
newRect.size.height -= 1;
|
|
|
|
|
|
|
|
newRect.origin.x += 3;
|
|
|
|
newRect.size.width -= 3;
|
|
|
|
|
|
|
|
if (_drawsGrid)
|
|
|
|
{
|
|
|
|
//newRect.origin.y += 1;
|
|
|
|
//newRect.origin.x += 1;
|
|
|
|
//newRect.size.width -= 2;
|
|
|
|
newRect.size.height += 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
newRect.origin.x += currentDropLevel * _indentationPerLevel;
|
|
|
|
newRect.size.width -= currentDropLevel * _indentationPerLevel;
|
|
|
|
|
|
|
|
NSFrameRectWithWidth(newRect, 2.0);
|
|
|
|
// NSRectFill(newRect);
|
|
|
|
|
|
|
|
}
|
|
|
|
[_window flushWindow];
|
|
|
|
|
|
|
|
[self unlockFocus];
|
|
|
|
|
|
|
|
oldDropRow = currentDropRow;
|
|
|
|
oldDropLevel = currentDropLevel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return NSDragOperationCopy;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) performDragOperation: (id<NSDraggingInfo>)sender
|
|
|
|
{
|
|
|
|
NSLog(@"performDragOperation");
|
|
|
|
if ([_dataSource
|
|
|
|
respondsToSelector:
|
2002-04-06 00:15:05 +00:00
|
|
|
@selector(outlineView:acceptDrop:proposedItem:proposedChildIndex:)])
|
2002-03-22 00:15:03 +00:00
|
|
|
{
|
|
|
|
id item;
|
|
|
|
int childIndex;
|
|
|
|
int i;
|
|
|
|
int j = 0;
|
|
|
|
int lvl;
|
|
|
|
for ( i = currentDropRow - 1; i >= 0; i-- )
|
|
|
|
{
|
|
|
|
lvl = [self levelForRow: i];
|
|
|
|
if (lvl == currentDropLevel - 1)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (lvl == currentDropLevel)
|
|
|
|
{
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i == -1)
|
|
|
|
item = nil;
|
|
|
|
else
|
|
|
|
item = [self itemAtRow: i];
|
2002-03-22 01:14:35 +00:00
|
|
|
|
2002-03-22 00:15:03 +00:00
|
|
|
childIndex = j;
|
|
|
|
|
|
|
|
|
|
|
|
return [_dataSource
|
|
|
|
outlineView: self
|
2002-04-06 00:15:05 +00:00
|
|
|
acceptDrop: sender
|
|
|
|
proposedItem: item
|
|
|
|
proposedChildIndex: childIndex];
|
2002-03-22 00:15:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2002-03-22 01:14:35 +00:00
|
|
|
- (BOOL) prepareForDragOperation: (id<NSDraggingInfo>)sender
|
|
|
|
{
|
|
|
|
[self setNeedsDisplayInRect: oldDraggingRect];
|
|
|
|
[self displayIfNeeded];
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2002-04-02 05:04:57 +00:00
|
|
|
// Autosave methods...
|
|
|
|
- (void) setAutosaveName: (NSString *)name
|
|
|
|
{
|
|
|
|
[super setAutosaveName: name];
|
|
|
|
[self _autoloadExpandedItems];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _autosaveExpandedItems
|
|
|
|
{
|
|
|
|
if (_autosaveExpandedItems && _autosaveName != nil)
|
|
|
|
{
|
|
|
|
NSUserDefaults *defaults;
|
|
|
|
NSString *tableKey;
|
|
|
|
|
|
|
|
defaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
tableKey = [NSString stringWithFormat: @"NSOutlineView Expanded Items %@",
|
|
|
|
_autosaveName];
|
|
|
|
[defaults setObject: _expandedItems forKey: tableKey];
|
|
|
|
[defaults synchronize];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _autoloadExpandedItems
|
|
|
|
{
|
|
|
|
if (_autosaveExpandedItems && _autosaveName != nil)
|
|
|
|
{
|
|
|
|
NSUserDefaults *defaults;
|
|
|
|
id config;
|
|
|
|
NSString *tableKey;
|
|
|
|
|
|
|
|
defaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
tableKey = [NSString stringWithFormat: @"NSOutlineView Expanded Items %@",
|
|
|
|
_autosaveName];
|
|
|
|
config = [defaults objectForKey: tableKey];
|
|
|
|
if (config != nil)
|
|
|
|
{
|
|
|
|
NSEnumerator *en = [config objectEnumerator];
|
|
|
|
id item = nil;
|
|
|
|
|
|
|
|
while ((item = [en nextObject]) != nil)
|
|
|
|
{
|
|
|
|
[self expandItem: item];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-02-23 16:37:17 +00:00
|
|
|
@end /* implementation of NSOutlineView */
|
2001-10-25 21:41:03 +00:00
|
|
|
|