mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 04:57:03 +00:00
The msgSend function has always returned nil if the receiver has been nil or undefined. Example: var a = undefined; var b = [a someSelector]; // b = nil The variable b is now nil. This pull request adds the ability for the msgSend function to return undefined if the receiver is undefined. If the receiver is nil it still return nil. The above example again: var a = undefined; var b = [a someSelector]; // b = undefined The variable b is now undefined. Background. The use of nil in Objective-C corresponds to the use of null in C and C++ and stands for "no value". A fundamental function in Objective-C is when you send a message to a receiver that is nil the result is again a nil value. This can be very convenient as you don't need the check if a receiver is nil before sending a message to it. Objective-J adds the ability the use class structures and message send functionality for Javascript in the same way as Objective-C adds this to C and C++. Javascript also has the value null and is handled in the same way for Objective-J. Javascript also has the value undefined that stands for "not yet defined". This can sometimes be confusing and many try to handle null and undefined as the same thing. This is almost what Objective-J and the Cappuccino frameworks always has been doing. They try to always check for both null and ``undefined and always return nil but never undefined. We can say that Objective-J understands undefined but will try to translate it to nil. Why do we need this change. Javascript has both null and undefined and Objective-J is a superset of Javascript. It is now very hard to use undefined in Objective-J code as it will always try to translate it to nil. There are some Javascript libraries that use both null and undefined values and they are very hard to use from Objective-J programs today. Same if you decide to use nil and undefined as a value in your own Objective-J code. This small change will make undefined a full member of the Objective-J language. It should be as it is a superset of Javascript. The Cappuccino frameworks will still handle undefined but only return nil. How will it impact. Today most methods will never return undefined so this is a very limited problem. If any does this the main concern is if some code will only check for nil and not undefined. Example: var a = [someObject someSelector]; If (a === nil) a = 42; ... If the variable someObject contains undefined the variable a will now be set to undefined instead of nil. But the variable a will then never be set to 42. The correct way is to check for both nil and undefined like this: var a = [someObject someSelector]; If (a == nil) a = 42; ...
1193 lines
38 KiB
Plaintext
1193 lines
38 KiB
Plaintext
/*
|
|
* CPBrowser.j
|
|
* AppKit
|
|
*
|
|
* Created by Ross Boucher.
|
|
* Copyright 2010, 280 North, Inc.
|
|
*
|
|
* 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-1301 USA
|
|
*/
|
|
|
|
@import <Foundation/CPObject.j>
|
|
@import <Foundation/CPIndexSet.j>
|
|
|
|
@import "CPControl.j"
|
|
@import "CPImage.j"
|
|
@import "CPScrollView.j"
|
|
@import "CPTableView.j"
|
|
@import "CPTextField.j"
|
|
|
|
@global CPApp
|
|
|
|
@protocol CPBrowserDelegate <CPObject>
|
|
|
|
@optional
|
|
- (BOOL)browser:(CPBrowser)browser acceptDrop:(id)info atRow:(CPInteger)row column:(CPInteger)column dropOperation:(CPTableViewDropOperation)dropOperation;
|
|
- (BOOL)browser:(CPBrowser)browser canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)column withEvent:(CPEvent )event;
|
|
- (BOOL)browser:(CPBrowser)browser isLeafItem:(id)item;
|
|
- (BOOL)browser:(CPBrowser)browser shouldSelectRowIndexes:(CPIndexSet)anIndexSet inColumn:(CPInteger)column;
|
|
- (BOOL)browser:(CPBrowser)browser writeRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)column toPasteboard:(CPPasteboard)pasteboard;
|
|
- (CPDragOperation)browser:(CPBrowser)browser validateDrop:(id)info proposedRow:(CPInteger)row column:(CPInteger)column dropOperation:(CPTableViewDropOperation)dropOperation;
|
|
- (CPImage)browser:(CPBrowser)browser imageValueForItem:(id)anItem;
|
|
- (CPImage)browser:(CPBrowser)browser draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)column withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset;
|
|
- (CPIndexSet)browser:(CPBrowser)browser selectionIndexesForProposedSelection:(CPIndexSet)proposedSelectionIndexes inColumn:(CPInteger)column;
|
|
- (CPInteger)browser:(CPBrowser)browser numberOfChildrenOfItem:(id)item;
|
|
- (CPView)browser:(CPBrowser)browser draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)column withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset;
|
|
- (id)browser:(CPBrowser)browser child:(CPInteger)index ofItem:(id)item;
|
|
- (id)browser:(CPBrowser)browser objectValueForItem:(id)item;
|
|
- (id)rootItemForBrowser:(CPBrowser)browser;
|
|
- (void)browser:(CPBrowser)browser didChangeLastColumn:(CPInteger)oldLastColumn toColumn:(CPInteger)column;
|
|
- (void)browser:(CPBrowser)browser didResizeColumn:(CPInteger)column;
|
|
- (void)browserSelectionIsChanging:(CPBrowser)browser;
|
|
- (void)browserSelectionDidChange:(CPBrowser)browser;
|
|
|
|
@end
|
|
|
|
var CPBrowserDelegate_browser_acceptDrop_atRow_column_dropOperation_ = 1 << 1,
|
|
CPBrowserDelegate_browser_canDragRowsWithIndexes_inColumn_withEvent_ = 1 << 2,
|
|
CPBrowserDelegate_browser_isLeafItem_ = 1 << 3,
|
|
CPBrowserDelegate_browser_shouldSelectRowIndexes_inColumn_ = 1 << 4,
|
|
CPBrowserDelegate_browser_writeRowsWithIndexes_inColumn_toPasteboard_ = 1 << 5,
|
|
CPBrowserDelegate_browser_validateDrop_proposedRow_column_dropOperation_ = 1 << 6,
|
|
CPBrowserDelegate_browser_draggingImageForRowsWithIndexes_inColumn_withEvent_offset_ = 1 << 7,
|
|
CPBrowserDelegate_browser_imageValueForItem_ = 1 << 8,
|
|
CPBrowserDelegate_browser_selectionIndexesForProposedSelection_inColumn_ = 1 << 9,
|
|
CPBrowserDelegate_browser_numberOfChildrenOfItem_ = 1 << 10,
|
|
CPBrowserDelegate_browser_draggingViewForRowsWithIndexes_inColumn_withEvent_offset_ = 1 << 11,
|
|
CPBrowserDelegate_browser_child_ofItem_ = 1 << 12,
|
|
CPBrowserDelegate_browser_objectValueForItem_ = 1 << 13,
|
|
CPBrowserDelegate_rootItemForBrowser_ = 1 << 14,
|
|
CPBrowserDelegate_browser_didChangeLastColumn_toColumn_ = 1 << 15,
|
|
CPBrowserDelegate_browser_didResizeColumn_ = 1 << 16,
|
|
CPBrowserDelegate_browserSelectionIsChanging_ = 1 << 17,
|
|
CPBrowserDelegate_browserSelectionDidChange_ = 1 << 18;
|
|
|
|
/*!
|
|
@ingroup appkit
|
|
@class CPBrowser
|
|
*/
|
|
@implementation CPBrowser : CPControl
|
|
{
|
|
id <CPBrowserDelegate> _delegate;
|
|
CPString _pathSeparator;
|
|
unsigned _implementedDelegateMethods;
|
|
|
|
CPView _contentView;
|
|
CPScrollView _horizontalScrollView;
|
|
CPView _prototypeView;
|
|
|
|
CPArray _tableViews;
|
|
CPArray _tableDelegates;
|
|
|
|
id _rootItem;
|
|
|
|
BOOL _delegateSupportsImages;
|
|
|
|
SEL _doubleAction @accessors(property=doubleAction);
|
|
|
|
BOOL _allowsMultipleSelection;
|
|
BOOL _allowsEmptySelection;
|
|
|
|
Class _tableViewClass @accessors(property=tableViewClass);
|
|
|
|
float _rowHeight;
|
|
float _imageWidth;
|
|
float _leafWidth;
|
|
float _minColumnWidth;
|
|
float _defaultColumnWidth @accessors(property=defaultColumnWidth);
|
|
|
|
CPArray _columnWidths;
|
|
}
|
|
|
|
+ (CPString)defaultThemeClass
|
|
{
|
|
return "browser";
|
|
}
|
|
|
|
+ (CPDictionary)themeAttributes
|
|
{
|
|
return @{
|
|
@"image-control-resize": [CPNull null],
|
|
@"image-control-leaf": [CPNull null],
|
|
@"image-control-leaf-pressed": [CPNull null]
|
|
};
|
|
}
|
|
|
|
- (id)initWithFrame:(CGRect)aFrame
|
|
{
|
|
if (self = [super initWithFrame:aFrame])
|
|
{
|
|
[self _init];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)_init
|
|
{
|
|
_rowHeight = 23.0;
|
|
_defaultColumnWidth = 140.0;
|
|
_minColumnWidth = 80.0;
|
|
_imageWidth = 23.0;
|
|
_leafWidth = 13.0;
|
|
_columnWidths = [];
|
|
|
|
_pathSeparator = "/";
|
|
_tableViews = [];
|
|
_tableDelegates = [];
|
|
_allowsMultipleSelection = YES;
|
|
_allowsEmptySelection = YES;
|
|
_tableViewClass = [_CPBrowserTableView class];
|
|
|
|
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
|
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
|
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelectedDataView];
|
|
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
|
|
|
|
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
|
|
|
|
[_horizontalScrollView setHasVerticalScroller:NO];
|
|
[_horizontalScrollView setAutohidesScrollers:YES];
|
|
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
|
|
|
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
|
|
[_contentView setAutoresizingMask:CPViewHeightSizable];
|
|
|
|
[_horizontalScrollView setDocumentView:_contentView];
|
|
|
|
[self addSubview:_horizontalScrollView];
|
|
}
|
|
|
|
- (void)setPrototypeView:(CPView)aPrototypeView
|
|
{
|
|
_prototypeView = [CPKeyedUnarchiver unarchiveObjectWithData:
|
|
[CPKeyedArchiver archivedDataWithRootObject:aPrototypeView]];
|
|
}
|
|
|
|
- (CPView)prototypeView
|
|
{
|
|
return [CPKeyedUnarchiver unarchiveObjectWithData:
|
|
[CPKeyedArchiver archivedDataWithRootObject:_prototypeView]];
|
|
}
|
|
|
|
- (void)setDelegate:(id <CPBrowserDelegate>)anObject
|
|
{
|
|
if (_delegate === anObject)
|
|
return;
|
|
|
|
_delegate = anObject;
|
|
_implementedDelegateMethods = 0;
|
|
_delegateSupportsImages = NO;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:acceptDrop:atRow:column:dropOperation:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_acceptDrop_atRow_column_dropOperation_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:canDragRowsWithIndexes:inColumn:withEvent:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_canDragRowsWithIndexes_inColumn_withEvent_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:isLeafItem:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_isLeafItem_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_shouldSelectRowIndexes_inColumn_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_writeRowsWithIndexes_inColumn_toPasteboard_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_validateDrop_proposedRow_column_dropOperation_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:draggingImageForRowsWithIndexes:inColumn:withEvent:offset:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_draggingImageForRowsWithIndexes_inColumn_withEvent_offset_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:imageValueForItem:)])
|
|
{
|
|
_delegateSupportsImages = YES;
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_imageValueForItem_;
|
|
}
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_selectionIndexesForProposedSelection_inColumn_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:numberOfChildrenOfItem:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_numberOfChildrenOfItem_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:draggingViewForRowsWithIndexes:inColumn:withEvent:offset:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_draggingViewForRowsWithIndexes_inColumn_withEvent_offset_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:child:ofItem:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_child_ofItem_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:objectValueForItem:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_objectValueForItem_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(rootItemForBrowser:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_rootItemForBrowser_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:didChangeLastColumn:toColumn:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_didChangeLastColumn_toColumn_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browser:didChangeLastColumn:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browser_didResizeColumn_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browserSelectionIsChanging:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browserSelectionIsChanging_;
|
|
|
|
if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)])
|
|
_implementedDelegateMethods |= CPBrowserDelegate_browserSelectionDidChange_;
|
|
|
|
[self loadColumnZero];
|
|
}
|
|
|
|
- (id)delegate
|
|
{
|
|
return _delegate;
|
|
}
|
|
|
|
- (CPTableView)tableViewInColumn:(unsigned)index
|
|
{
|
|
return _tableViews[index];
|
|
}
|
|
|
|
- (unsigned)columnOfTableView:(CPTableView)aTableView
|
|
{
|
|
return [_tableViews indexOfObject:aTableView];
|
|
}
|
|
|
|
- (void)loadColumnZero
|
|
{
|
|
_rootItem = [self _sendDelegateRootItemForBrowser];
|
|
|
|
[self setLastColumn:-1];
|
|
[self addColumn];
|
|
}
|
|
|
|
- (void)setLastColumn:(CPInteger)columnIndex
|
|
{
|
|
if (columnIndex >= _tableViews.length)
|
|
return;
|
|
|
|
var oldValue = _tableViews.length - 1,
|
|
indexPlusOne = columnIndex + 1; // unloads all later columns.
|
|
|
|
if (columnIndex > 0)
|
|
[_tableViews[columnIndex - 1] setNeedsDisplay:YES];
|
|
|
|
[_tableViews[columnIndex] setNeedsDisplay:YES];
|
|
|
|
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
|
|
makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
|
|
|
_tableViews = _tableViews.slice(0, indexPlusOne);
|
|
_tableDelegates = _tableDelegates.slice(0, indexPlusOne);
|
|
|
|
[self _sendDelegateBrowserDidChangeLastColumn:oldValue toColumn:columnIndex];
|
|
|
|
[self tile];
|
|
}
|
|
|
|
- (int)lastColumn
|
|
{
|
|
return _tableViews.length - 1;
|
|
}
|
|
|
|
- (void)addColumn
|
|
{
|
|
var lastIndex = [self lastColumn],
|
|
lastColumn = _tableViews[lastIndex],
|
|
selectionIndexes = [lastColumn selectedRowIndexes];
|
|
|
|
if (lastIndex >= 0 && [selectionIndexes count] > 1)
|
|
[CPException raise:CPInvalidArgumentException
|
|
reason:"Can't add column, column "+lastIndex+" has invalid selection."];
|
|
|
|
var index = lastIndex + 1,
|
|
item = index === 0 ? _rootItem : [_tableDelegates[lastIndex] childAtIndex:[selectionIndexes firstIndex]];
|
|
|
|
if (index > 0 && item && [self isLeafItem:item])
|
|
return;
|
|
|
|
var table = [[_tableViewClass alloc] initWithFrame:CGRectMakeZero() browser:self];
|
|
|
|
[table setHeaderView:nil];
|
|
[table setCornerView:nil];
|
|
[table setAllowsMultipleSelection:_allowsMultipleSelection];
|
|
[table setAllowsEmptySelection:_allowsEmptySelection];
|
|
[table registerForDraggedTypes:[self registeredDraggedTypes]];
|
|
|
|
[self _addTableColumnsToTableView:table forColumnIndex:index];
|
|
|
|
var delegate = [[_CPBrowserTableDelegate alloc] init];
|
|
|
|
[delegate _setDelegate:_delegate];
|
|
[delegate _setBrowser:self];
|
|
[delegate _setIndex:index];
|
|
[delegate _setItem:item];
|
|
|
|
_tableViews[index] = table;
|
|
_tableDelegates[index] = delegate;
|
|
|
|
[table setDelegate:delegate];
|
|
[table setDataSource:delegate];
|
|
[table setTarget:delegate];
|
|
[table setAction:@selector(_tableViewClicked:)];
|
|
[table setDoubleAction:@selector(_tableViewDoubleClicked:)];
|
|
[table setDraggingDestinationFeedbackStyle:CPTableViewDraggingDestinationFeedbackStyleRegular];
|
|
|
|
var scrollView = [[_CPBrowserScrollView alloc] initWithFrame:CGRectMakeZero()];
|
|
[scrollView _setBrowser:self];
|
|
[scrollView setDocumentView:table];
|
|
[scrollView setHasHorizontalScroller:NO];
|
|
[scrollView setAutoresizingMask:CPViewHeightSizable];
|
|
|
|
[_contentView addSubview:scrollView];
|
|
|
|
[self tile];
|
|
|
|
[self scrollColumnToVisible:index];
|
|
}
|
|
|
|
- (void)_addTableColumnsToTableView:(CPTableView)aTableView forColumnIndex:(unsigned)index
|
|
{
|
|
if (_delegateSupportsImages)
|
|
{
|
|
var column = [[CPTableColumn alloc] initWithIdentifier:@"Image"],
|
|
view = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
|
|
|
[view setImageScaling:CPImageScaleProportionallyDown];
|
|
|
|
[column setDataView:view];
|
|
[column setResizingMask:CPTableColumnNoResizing];
|
|
|
|
[aTableView addTableColumn:column];
|
|
}
|
|
|
|
var column = [[CPTableColumn alloc] initWithIdentifier:@"Content"];
|
|
|
|
[column setDataView:_prototypeView];
|
|
[column setResizingMask:CPTableColumnNoResizing];
|
|
|
|
[aTableView addTableColumn:column];
|
|
|
|
var column = [[CPTableColumn alloc] initWithIdentifier:@"Leaf"],
|
|
view = [[_CPBrowserLeafView alloc] initWithFrame:CGRectMakeZero()];
|
|
|
|
[view setBranchImage:[self valueForThemeAttribute:@"image-control-leaf"]];
|
|
[view setHighlightedBranchImage:[self valueForThemeAttribute:@"image-control-leaf-pressed"]];
|
|
|
|
[column setDataView:view];
|
|
[column setResizingMask:CPTableColumnNoResizing];
|
|
|
|
[aTableView addTableColumn:column];
|
|
}
|
|
|
|
- (void)reloadColumn:(CPInteger)column
|
|
{
|
|
[[self tableViewInColumn:column] reloadData];
|
|
}
|
|
|
|
- (void)tile
|
|
{
|
|
var xOrigin = 0,
|
|
scrollerWidth = [CPScroller scrollerWidth],
|
|
height = CGRectGetHeight([_contentView bounds]);
|
|
|
|
for (var i = 0, count = _tableViews.length; i < count; i++)
|
|
{
|
|
var tableView = _tableViews[i],
|
|
scrollView = [tableView enclosingScrollView],
|
|
width = [self widthOfColumn:i],
|
|
tableHeight = CGRectGetHeight([tableView bounds]);
|
|
|
|
[[tableView tableColumnWithIdentifier:"Image"] setWidth:_imageWidth];
|
|
[[tableView tableColumnWithIdentifier:"Content"] setWidth:[self columnContentWidthForColumnWidth:width]];
|
|
[[tableView tableColumnWithIdentifier:"Leaf"] setWidth:_leafWidth];
|
|
|
|
[tableView setRowHeight:_rowHeight];
|
|
[tableView setFrameSize:CGSizeMake(width - scrollerWidth, tableHeight)];
|
|
[scrollView setFrameOrigin:CGPointMake(xOrigin, 0)];
|
|
[scrollView setFrameSize:CGSizeMake(width, height)];
|
|
|
|
xOrigin += width;
|
|
}
|
|
|
|
[_contentView setFrameSize:CGSizeMake(xOrigin, height)];
|
|
}
|
|
|
|
- (unsigned)rowAtPoint:(CGPoint)aPoint
|
|
{
|
|
var column = [self columnAtPoint:aPoint];
|
|
if (column === -1)
|
|
return -1;
|
|
|
|
var tableView = _tableViews[column];
|
|
return [tableView rowAtPoint:[tableView convertPoint:aPoint fromView:self]];
|
|
}
|
|
|
|
- (unsigned)columnAtPoint:(CGPoint)aPoint
|
|
{
|
|
var adjustedPoint = [_contentView convertPoint:aPoint fromView:self];
|
|
|
|
for (var i = 0, count = _tableViews.length; i < count; i++)
|
|
{
|
|
var frame = [[_tableViews[i] enclosingScrollView] frame];
|
|
if (CGRectContainsPoint(frame, adjustedPoint))
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
- (CGRect)rectOfRow:(unsigned)aRow inColumn:(unsigned)aColumn
|
|
{
|
|
var tableView = _tableViews[aColumn],
|
|
rect = [tableView rectOfRow:aRow];
|
|
|
|
rect.origin = [self convertPoint:rect.origin fromView:tableView];
|
|
return rect;
|
|
}
|
|
|
|
// ITEMS
|
|
|
|
- (id)itemAtRow:(CPInteger)row inColumn:(CPInteger)column
|
|
{
|
|
return [_tableDelegates[column] childAtIndex:row] || nil;
|
|
}
|
|
|
|
- (BOOL)isLeafItem:(id)item
|
|
{
|
|
return (_implementedDelegateMethods & CPBrowserDelegate_browser_isLeafItem_) && [_delegate browser:self isLeafItem:item];
|
|
}
|
|
|
|
- (id)parentForItemsInColumn:(CPInteger)column
|
|
{
|
|
return [_tableDelegates[column] _item] || nil;
|
|
}
|
|
|
|
- (CPSet)selectedItems
|
|
{
|
|
var selectedColumn = [self selectedColumn],
|
|
selectedIndexes = [self selectedRowIndexesInColumn:selectedColumn],
|
|
set = [CPSet set],
|
|
index = [selectedIndexes firstIndex];
|
|
|
|
while (index !== CPNotFound)
|
|
{
|
|
[set addObject:[self itemAtRow:index inColumn:selectedColumn]];
|
|
index = [selectedIndexes indexGreaterThanIndex:index];
|
|
}
|
|
|
|
return set;
|
|
}
|
|
|
|
- (id)selectedItem
|
|
{
|
|
var selectedColumn = [self selectedColumn],
|
|
selectedRow = [self selectedRowInColumn:selectedColumn];
|
|
|
|
return [self itemAtRow:selectedRow inColumn:selectedColumn];
|
|
}
|
|
|
|
// CLICK EVENTS
|
|
|
|
- (void)trackMouse:(CPEvent)anEvent
|
|
{
|
|
}
|
|
|
|
- (void)_column:(unsigned)columnIndex clickedRow:(unsigned)rowIndex
|
|
{
|
|
[self setLastColumn:columnIndex];
|
|
|
|
if (rowIndex >= 0)
|
|
[self addColumn];
|
|
|
|
[self doClick:self];
|
|
}
|
|
|
|
- (void)sendAction
|
|
{
|
|
[self sendAction:_action to:_target];
|
|
}
|
|
|
|
- (void)doClick:(id)sender
|
|
{
|
|
[self sendAction:_action to:_target];
|
|
}
|
|
|
|
- (void)doDoubleClick:(id)sender
|
|
{
|
|
[self sendAction:_doubleAction to:_target];
|
|
}
|
|
|
|
- (void)keyDown:(CPEvent)anEvent
|
|
{
|
|
var key = [anEvent charactersIgnoringModifiers],
|
|
column = [self selectedColumn];
|
|
|
|
if (column === CPNotFound)
|
|
return;
|
|
|
|
if (key === CPLeftArrowFunctionKey || key === CPRightArrowFunctionKey)
|
|
{
|
|
if (key === CPLeftArrowFunctionKey)
|
|
{
|
|
var previousColumn = column - 1,
|
|
selectedRow = [self selectedRowInColumn:previousColumn];
|
|
|
|
[self selectRow:selectedRow inColumn:previousColumn];
|
|
}
|
|
else
|
|
[self selectRow:0 inColumn:column + 1];
|
|
}
|
|
else
|
|
[_tableViews[column] keyDown:anEvent];
|
|
}
|
|
|
|
// SIZING
|
|
|
|
- (float)columnContentWidthForColumnWidth:(float)aWidth
|
|
{
|
|
var columnSpacing = [_tableViews[0] intercellSpacing].width;
|
|
return aWidth - (_leafWidth + columnSpacing + (_delegateSupportsImages ? _imageWidth + columnSpacing : 0)) - columnSpacing - [CPScroller scrollerWidth];
|
|
}
|
|
|
|
- (float)columnWidthForColumnContentWidth:(float)aWidth
|
|
{
|
|
var columnSpacing = [_tableViews[0] intercellSpacing].width;
|
|
return aWidth + (_leafWidth + columnSpacing + (_delegateSupportsImages ? _imageWidth + columnSpacing: 0)) + columnSpacing + [CPScroller scrollerWidth];
|
|
}
|
|
|
|
- (void)setImageWidth:(float)aWidth
|
|
{
|
|
_imageWidth = aWidth;
|
|
[self tile];
|
|
}
|
|
|
|
- (float)imageWidth
|
|
{
|
|
return _imageWidth;
|
|
}
|
|
|
|
- (void)setMinColumnWidth:(float)minWidth
|
|
{
|
|
_minColumnWidth = minWidth;
|
|
[self tile];
|
|
}
|
|
|
|
- (float)minColumnWidth
|
|
{
|
|
return _minColumnWidth;
|
|
}
|
|
|
|
- (void)setWidth:(float)aWidth ofColumn:(unsigned)column
|
|
{
|
|
_columnWidths[column] = aWidth;
|
|
|
|
[self _sendDelegateBrowserDidResizeColumn:column];
|
|
[self tile];
|
|
}
|
|
|
|
- (float)widthOfColumn:(unsigned)column
|
|
{
|
|
var width = _columnWidths[column];
|
|
|
|
if (width == null)
|
|
width = _defaultColumnWidth;
|
|
|
|
return MAX([CPScroller scrollerWidth], MAX(_minColumnWidth, width));
|
|
}
|
|
|
|
- (void)setRowHeight:(float)aHeight
|
|
{
|
|
_rowHeight = aHeight;
|
|
}
|
|
|
|
- (float)rowHeight
|
|
{
|
|
return _rowHeight;
|
|
}
|
|
|
|
// SCROLLERS
|
|
|
|
- (void)scrollColumnToVisible:(unsigned)columnIndex
|
|
{
|
|
[_contentView scrollRectToVisible:[[[self tableViewInColumn:columnIndex] enclosingScrollView] frame]];
|
|
}
|
|
|
|
- (void)scrollRowToVisible:(unsigned)rowIndex inColumn:(unsigned)columnIndex
|
|
{
|
|
[self scrollColumnToVisible:columnIndex];
|
|
[[self tableViewInColumn:columnIndex] scrollRowToVisible:rowIndex];
|
|
}
|
|
|
|
- (BOOL)autohidesScroller
|
|
{
|
|
return [_horizontalScrollView autohidesScrollers];
|
|
}
|
|
|
|
- (void)setAutohidesScroller:(BOOL)shouldHide
|
|
{
|
|
[_horizontalScrollView setAutohidesScrollers:shouldHide];
|
|
}
|
|
|
|
// SELECTION
|
|
|
|
- (unsigned)selectedRowInColumn:(unsigned)columnIndex
|
|
{
|
|
if (columnIndex > [self lastColumn] || columnIndex < 0)
|
|
return -1;
|
|
|
|
return [_tableViews[columnIndex] selectedRow];
|
|
}
|
|
|
|
- (unsigned)selectedColumn
|
|
{
|
|
var column = [self lastColumn],
|
|
row = [self selectedRowInColumn:column];
|
|
|
|
if (row >= 0)
|
|
return column;
|
|
else
|
|
return column - 1;
|
|
}
|
|
|
|
- (void)selectRow:(unsigned)row inColumn:(unsigned)column
|
|
{
|
|
var selectedIndexes = row === -1 ? [CPIndexSet indexSet] : [CPIndexSet indexSetWithIndex:row];
|
|
[self selectRowIndexes:selectedIndexes inColumn:column];
|
|
}
|
|
|
|
- (BOOL)allowsMultipleSelection
|
|
{
|
|
return _allowsMultipleSelection;
|
|
}
|
|
|
|
- (void)setAllowsMultipleSelection:(BOOL)shouldAllow
|
|
{
|
|
if (_allowsMultipleSelection === shouldAllow)
|
|
return;
|
|
|
|
_allowsMultipleSelection = shouldAllow;
|
|
[_tableViews makeObjectsPerformSelector:@selector(setAllowsMultipleSelection:) withObject:shouldAllow];
|
|
}
|
|
|
|
- (BOOL)allowsEmptySelection
|
|
{
|
|
return _allowsEmptySelection;
|
|
}
|
|
|
|
- (void)setAllowsEmptySelection:(BOOL)shouldAllow
|
|
{
|
|
if (_allowsEmptySelection === shouldAllow)
|
|
return;
|
|
|
|
_allowsEmptySelection = shouldAllow;
|
|
[_tableViews makeObjectsPerformSelector:@selector(setAllowsEmptySelection:) withObject:shouldAllow];
|
|
}
|
|
|
|
- (CPIndexSet)selectedRowIndexesInColumn:(unsigned)column
|
|
{
|
|
if (column < 0 || column > [self lastColumn] +1)
|
|
return [CPIndexSet indexSet];
|
|
|
|
return [[self tableViewInColumn:column] selectedRowIndexes];
|
|
}
|
|
|
|
- (void)selectRowIndexes:(CPIndexSet)indexSet inColumn:(unsigned)column
|
|
{
|
|
if (column < 0 || column > [self lastColumn] + 1)
|
|
return;
|
|
|
|
indexSet = [self _sendDelegateBrowserSelectionIndexesForProposedSelection:indexSet inColumn:column];
|
|
|
|
if (![self _sendDelegateBrowserShouldSelectRowIndexes:indexSet inColumn:column])
|
|
return;
|
|
|
|
[self _sendDelegateBrowserSelectionIsChanging];
|
|
|
|
if (column > [self lastColumn])
|
|
[self addColumn];
|
|
|
|
[self setLastColumn:column];
|
|
|
|
[[self tableViewInColumn:column] selectRowIndexes:indexSet byExtendingSelection:NO];
|
|
|
|
[self scrollColumnToVisible:column];
|
|
|
|
[self _sendDelegateBrowserSelectionDidChange];
|
|
}
|
|
|
|
- (void)setBackgroundColor:(CPColor)aColor
|
|
{
|
|
[super setBackgroundColor:aColor];
|
|
[_contentView setBackgroundColor:aColor];
|
|
}
|
|
|
|
- (BOOL)acceptsFirstResponder
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
// DRAG AND DROP
|
|
|
|
- (void)registerForDraggedTypes:(CPArray)types
|
|
{
|
|
[super registerForDraggedTypes:types];
|
|
[_tableViews makeObjectsPerformSelector:@selector(registerForDraggedTypes:) withObject:types];
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation CPBrowser (CPCoding)
|
|
|
|
- (id)initWithCoder:(CPCoder)aCoder
|
|
{
|
|
self = [super initWithCoder:aCoder];
|
|
|
|
if (self)
|
|
{
|
|
[self _init];
|
|
|
|
_allowsEmptySelection = [aCoder decodeBoolForKey:@"CPBrowserAllowsEmptySelectionKey"];
|
|
_allowsMultipleSelection = [aCoder decodeBoolForKey:@"CPBrowserAllowsMultipleSelectionKey"];
|
|
_prototypeView = [aCoder decodeObjectForKey:@"CPBrowserPrototypeViewKey"];
|
|
_rowHeight = [aCoder decodeFloatForKey:@"CPBrowserRowHeightKey"];
|
|
_imageWidth = [aCoder decodeFloatForKey:@"CPBrowserImageWidthKey"];
|
|
_minColumnWidth = [aCoder decodeFloatForKey:@"CPBrowserMinColumnWidthKey"];
|
|
_columnWidths = [aCoder decodeObjectForKey:@"CPBrowserColumnWidthsKey"];
|
|
|
|
[self setDelegate:[aCoder decodeObjectForKey:@"CPBrowserDelegateKey"]];
|
|
[self setAutohidesScroller:[aCoder decodeBoolForKey:@"CPBrowserAutohidesScrollerKey"]];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
|
{
|
|
// Don't encode the subviews, they're transient and will be recreated from data.
|
|
var actualSubviews = _subviews;
|
|
_subviews = [];
|
|
[super encodeWithCoder:aCoder];
|
|
_subviews = actualSubviews;
|
|
|
|
[aCoder encodeBool:[self autohidesScroller] forKey:@"CPBrowserAutohidesScrollerKey"];
|
|
[aCoder encodeBool:_allowsEmptySelection forKey:@"CPBrowserAllowsEmptySelectionKey"];
|
|
[aCoder encodeBool:_allowsMultipleSelection forKey:@"CPBrowserAllowsMultipleSelectionKey"];
|
|
[aCoder encodeObject:_delegate forKey:@"CPBrowserDelegateKey"];
|
|
[aCoder encodeObject:_prototypeView forKey:@"CPBrowserPrototypeViewKey"];
|
|
[aCoder encodeFloat:_rowHeight forKey:@"CPBrowserRowHeightKey"];
|
|
[aCoder encodeFloat:_imageWidth forKey:@"CPBrowserImageWidthKey"];
|
|
[aCoder encodeFloat:_minColumnWidth forKey:@"CPBrowserMinColumnWidthKey"];
|
|
[aCoder encodeObject:_columnWidths forKey:@"CPBrowserColumnWidthsKey"];
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
@implementation _CPBrowserResizeControl : CPView
|
|
{
|
|
CGPoint _mouseDownX;
|
|
CPBrowser _browser;
|
|
unsigned _index;
|
|
unsigned _width;
|
|
}
|
|
|
|
- (id)initWithFrame:(CGRect)aFrame
|
|
{
|
|
if (self = [super initWithFrame:aFrame])
|
|
{
|
|
var browser = [[CPBrowser alloc] init];
|
|
[self setBackgroundColor:[CPColor colorWithPatternImage:[browser valueForThemeAttribute:@"image-control-resize"]]];
|
|
}
|
|
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)mouseDown:(CPEvent)anEvent
|
|
{
|
|
_mouseDownX = [anEvent locationInWindow].x;
|
|
_browser = [[self superview] _browser];
|
|
_index = [_browser columnOfTableView:[[self superview] documentView]];
|
|
_width = [_browser widthOfColumn:_index];
|
|
}
|
|
|
|
- (void)mouseDragged:(CPEvent)anEvent
|
|
{
|
|
var deltaX = [anEvent locationInWindow].x - _mouseDownX;
|
|
[_browser setWidth:_width + deltaX ofColumn:_index];
|
|
}
|
|
|
|
- (void)mouseUp:(CPEvent)anEvent
|
|
{
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation _CPBrowserScrollView : CPScrollView
|
|
{
|
|
_CPBrowserResizeControl _resizeControl;
|
|
CPBrowser _browser @accessors;
|
|
}
|
|
|
|
- (id)initWithFrame:(CGRect)aFrame
|
|
{
|
|
if (self = [super initWithFrame:aFrame])
|
|
{
|
|
_resizeControl = [[_CPBrowserResizeControl alloc] initWithFrame:CGRectMakeZero()];
|
|
[self addSubview:_resizeControl];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)reflectScrolledClipView:(CPClipView)aClipView
|
|
{
|
|
[super reflectScrolledClipView:aClipView];
|
|
|
|
var frame = [_verticalScroller frame];
|
|
frame.size.height = CGRectGetHeight([self bounds]) - 14.0 - frame.origin.y;
|
|
[_verticalScroller setFrameSize:frame.size];
|
|
|
|
var resizeFrame = CGRectMake(CGRectGetMinX(frame), CGRectGetMaxY(frame), [CPScroller scrollerWidth], 14.0);
|
|
[_resizeControl setFrame:resizeFrame];
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation _CPBrowserTableView : CPTableView
|
|
{
|
|
CPBrowser _browser;
|
|
}
|
|
|
|
- (id)initWithFrame:(CGRect)aFrame browser:(CPBrowser)aBrowser
|
|
{
|
|
if (self = [super initWithFrame:aFrame])
|
|
_browser = aBrowser;
|
|
|
|
return self;
|
|
}
|
|
|
|
- (BOOL)acceptsFirstResponder
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
- (void)mouseDown:(CPEvent)anEvent
|
|
{
|
|
[super mouseDown:anEvent];
|
|
[[self window] makeFirstResponder:_browser];
|
|
}
|
|
|
|
- (CPView)browserView
|
|
{
|
|
return _browser;
|
|
}
|
|
|
|
/*!
|
|
@ignore
|
|
*/
|
|
- (BOOL)_isFocused
|
|
{
|
|
return ([super _isFocused] || [_browser tableViewInColumn:[_browser selectedColumn]] === self);
|
|
}
|
|
|
|
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes atPoint:(CGPoint)mouseDownPoint
|
|
{
|
|
return [_browser canDragRowsWithIndexes:rowIndexes inColumn:[_browser columnOfTableView:self] withEvent:[CPApp currentEvent]];
|
|
}
|
|
|
|
- (CPImage)dragImageForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
|
{
|
|
return [_browser draggingImageForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragImageOffset] ||
|
|
[super dragImageForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragImageOffset];
|
|
}
|
|
|
|
- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CGPoint)dragViewOffset
|
|
{
|
|
var count = theTableColumns.length;
|
|
while (count--)
|
|
{
|
|
if ([theTableColumns[count] identifier] === "Leaf")
|
|
[theTableColumns removeObject:theTableColumns[count]];
|
|
}
|
|
|
|
return [_browser draggingViewForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragViewOffset] ||
|
|
[super dragViewForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragViewOffset];
|
|
}
|
|
|
|
|
|
@end
|
|
|
|
@implementation _CPBrowserTableDelegate : CPObject
|
|
{
|
|
CPBrowser _browser @accessors;
|
|
unsigned _index @accessors;
|
|
id _delegate @accessors;
|
|
id _item @accessors;
|
|
}
|
|
|
|
- (unsigned)numberOfRowsInTableView:(CPTableView)aTableView
|
|
{
|
|
return [_delegate browser:_browser numberOfChildrenOfItem:_item];
|
|
}
|
|
|
|
- (void)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)column row:(unsigned)row
|
|
{
|
|
if ([column identifier] === "Image")
|
|
return [_delegate browser:_browser imageValueForItem:[self childAtIndex:row]];
|
|
else if ([column identifier] === "Leaf")
|
|
return ![_browser isLeafItem:[self childAtIndex:row]];
|
|
else
|
|
return [_delegate browser:_browser objectValueForItem:[self childAtIndex:row]];
|
|
}
|
|
|
|
- (void)_tableViewDoubleClicked:(CPTableView)aTableView
|
|
{
|
|
[_browser doDoubleClick:self];
|
|
}
|
|
|
|
- (void)_tableViewClicked:(CPTableView)aTableView
|
|
{
|
|
var selectedIndexes = [aTableView selectedRowIndexes];
|
|
[_browser _column:_index clickedRow:[selectedIndexes count] === 1 ? [selectedIndexes firstIndex] : -1];
|
|
}
|
|
|
|
- (void)tableViewSelectionDidChange:(CPNotification)aNotification
|
|
{
|
|
var selectedIndexes = [[aNotification object] selectedRowIndexes];
|
|
[_browser selectRowIndexes:selectedIndexes inColumn:_index];
|
|
}
|
|
|
|
- (id)childAtIndex:(CPUInteger)index
|
|
{
|
|
return [_delegate browser:_browser child:index ofItem:_item];
|
|
}
|
|
|
|
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id)info row:(CPInteger)row dropOperation:(CPTableViewDropOperation)operation
|
|
{
|
|
if (_browser._implementedDelegateMethods & CPBrowserDelegate_browser_acceptDrop_atRow_column_dropOperation_)
|
|
return [_delegate browser:_browser acceptDrop:info atRow:row column:_index dropOperation:operation];
|
|
else
|
|
return NO;
|
|
}
|
|
|
|
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(CPInteger)row proposedDropOperation:(CPTableViewDropOperation)operation
|
|
{
|
|
if (_browser._implementedDelegateMethods & CPBrowserDelegate_browser_validateDrop_proposedRow_column_dropOperation_)
|
|
return [_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
|
|
else
|
|
return CPDragOperationNone;
|
|
}
|
|
|
|
- (BOOL)tableView:(CPTableView)aTableView writeRowsWithIndexes:(CPIndexSet)rowIndexes toPasteboard:(CPPasteboard)pboard
|
|
{
|
|
if (_browser._implementedDelegateMethods & CPBrowserDelegate_browser_writeRowsWithIndexes_inColumn_toPasteboard_)
|
|
return [_delegate browser:_browser writeRowsWithIndexes:rowIndexes inColumn:_index toPasteboard:pboard];
|
|
else
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL)respondsToSelector:(SEL)aSelector
|
|
{
|
|
if (aSelector === @selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:))
|
|
return [_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)];
|
|
else
|
|
return [super respondsToSelector:aSelector];
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation _CPBrowserLeafView : CPView
|
|
{
|
|
BOOL _isLeaf @accessors(readonly, property=isLeaf);
|
|
CPImage _branchImage @accessors(property=branchImage);
|
|
CPImage _highlightedBranchImage @accessors(property=highlightedBranchImage);
|
|
}
|
|
|
|
- (BOOL)objectValue
|
|
{
|
|
return _isLeaf;
|
|
}
|
|
|
|
- (void)setObjectValue:(id)aValue
|
|
{
|
|
_isLeaf = !!aValue;
|
|
[self setNeedsLayout];
|
|
}
|
|
|
|
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
|
{
|
|
if (aName === "image-view")
|
|
return CGRectInset([self bounds], 1, 1);
|
|
|
|
return [super rectForEphemeralSubviewNamed:aName];
|
|
}
|
|
|
|
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
|
{
|
|
if (aName === "image-view")
|
|
return [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
|
|
|
return [super createEphemeralSubviewNamed:aName];
|
|
}
|
|
|
|
- (void)layoutSubviews
|
|
{
|
|
var imageView = [self layoutEphemeralSubviewNamed:@"image-view"
|
|
positioned:CPWindowAbove
|
|
relativeToEphemeralSubviewNamed:nil],
|
|
isHighlighted = [self hasThemeState:CPThemeStateSelectedDataView];
|
|
|
|
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
|
|
[imageView setImageScaling:CPImageScaleNone];
|
|
}
|
|
|
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
|
{
|
|
[super encodeWithCoder:aCoder];
|
|
|
|
[aCoder encodeBool:_isLeaf forKey:"_CPBrowserLeafViewIsLeafKey"];
|
|
[aCoder encodeObject:_branchImage forKey:"_CPBrowserLeafViewBranchImageKey"];
|
|
[aCoder encodeObject:_highlightedBranchImage forKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
|
|
}
|
|
|
|
- (id)initWithCoder:(CPCoder)aCoder
|
|
{
|
|
if (self = [super initWithCoder:aCoder])
|
|
{
|
|
_isLeaf = [aCoder decodeBoolForKey:"_CPBrowserLeafViewIsLeafKey"];
|
|
_branchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewBranchImageKey"];
|
|
_highlightedBranchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation CPBrowser (CPBrowserDelegate)
|
|
|
|
/*!
|
|
@ignore
|
|
Call delegate rootItemForBrowser:
|
|
*/
|
|
- (id)_sendDelegateRootItemForBrowser
|
|
{
|
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_rootItemForBrowser_))
|
|
return nil;
|
|
|
|
return [_delegate rootItemForBrowser:self];
|
|
}
|
|
|
|
/*!
|
|
@ignore
|
|
Call delegate browser:didChangeLastColumn:toColumn:
|
|
*/
|
|
- (void)_sendDelegateBrowserDidChangeLastColumn:(CPInteger)lastColumn toColumn:(CPInteger)newColumn
|
|
{
|
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_browser_didChangeLastColumn_toColumn_))
|
|
return;
|
|
|
|
[_delegate browser:self didChangeLastColumn:lastColumn toColumn:newColumn];
|
|
}
|
|
|
|
/*!
|
|
@ignore
|
|
Call delegate browser:didResizeColumn:
|
|
*/
|
|
- (void)_sendDelegateBrowserDidResizeColumn:(CPInteger)column
|
|
{
|
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_browser_didResizeColumn_))
|
|
return;
|
|
|
|
[_delegate browser:self didResizeColumn:column];
|
|
}
|
|
|
|
/*!
|
|
@ignore
|
|
Call delegate browserSelectionIsChanging:
|
|
*/
|
|
- (void)_sendDelegateBrowserSelectionIsChanging
|
|
{
|
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_browserSelectionIsChanging_))
|
|
return;
|
|
|
|
[_delegate browserSelectionIsChanging:self];
|
|
}
|
|
|
|
/*!
|
|
@ignore
|
|
Call delegate browser:shouldSelectRowIndexes:inColumn:
|
|
*/
|
|
- (BOOL)_sendDelegateBrowserShouldSelectRowIndexes:(CPIndexSet)anIndexSet inColumn:(CPInteger)aColumn
|
|
{
|
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_browser_shouldSelectRowIndexes_inColumn_))
|
|
return YES;
|
|
|
|
return [_delegate browser:self shouldSelectRowIndexes:anIndexSet inColumn:aColumn];
|
|
}
|
|
|
|
/*!
|
|
@ignore
|
|
Call delegate browser:selectionIndexesForProposedSelection:inColumn:
|
|
*/
|
|
- (CPIndexSet)_sendDelegateBrowserSelectionIndexesForProposedSelection:(CPIndexSet)anIndexSet inColumn:(CPInteger)aColumn
|
|
{
|
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_browser_selectionIndexesForProposedSelection_inColumn_))
|
|
return anIndexSet;
|
|
|
|
return [_delegate browser:self selectionIndexesForProposedSelection:anIndexSet inColumn:aColumn];
|
|
}
|
|
|
|
/*!
|
|
@ignore
|
|
Call delegate browserSelectionDidChange
|
|
*/
|
|
- (void)_sendDelegateBrowserSelectionDidChange
|
|
{
|
|
if (!(_implementedDelegateMethods & CPBrowserDelegate_browserSelectionDidChange_))
|
|
return;
|
|
|
|
[_delegate browserSelectionDidChange:self];
|
|
}
|
|
|
|
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent
|
|
{
|
|
if (_implementedDelegateMethods & CPBrowserDelegate_browser_canDragRowsWithIndexes_inColumn_withEvent_)
|
|
return [_delegate browser:self canDragRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent];
|
|
|
|
return YES;
|
|
}
|
|
|
|
- (CPImage)draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
|
{
|
|
if (_implementedDelegateMethods & CPBrowserDelegate_browser_draggingImageForRowsWithIndexes_inColumn_withEvent_offset_)
|
|
return [_delegate browser:self draggingImageForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (CPView)draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
|
{
|
|
if (_implementedDelegateMethods & CPBrowserDelegate_browser_draggingViewForRowsWithIndexes_inColumn_withEvent_offset_)
|
|
return [_delegate browser:self draggingViewForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
|
|
|
return nil;
|
|
}
|
|
|
|
@end
|