44 BOOL _delegateSupportsImages;
48 BOOL _allowsMultipleSelection;
49 BOOL _allowsEmptySelection;
51 Class _tableViewClass;
56 float _minColumnWidth;
57 float _defaultColumnWidth;
66 size:CGSizeMake(9,9)];
73 size:CGSizeMake(9,9)];
76 - (id)initWithFrame:(CGRect)aFrame
78 if (
self = [super initWithFrame:aFrame])
89 _defaultColumnWidth = 140.0;
90 _minColumnWidth = 80.0;
98 _allowsMultipleSelection = YES;
99 _allowsEmptySelection = YES;
100 _tableViewClass = [_CPBrowserTableView class];
103 [_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
104 [_prototypeView setValue:[
CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelectedDataView];
105 [_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
109 [_horizontalScrollView setHasVerticalScroller:NO];
110 [_horizontalScrollView setAutohidesScrollers:YES];
111 [_horizontalScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
113 _contentView = [[
CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([
self bounds]))];
114 [_contentView setAutoresizingMask:CPViewHeightSizable];
116 [_horizontalScrollView setDocumentView:_contentView];
118 [
self addSubview:_horizontalScrollView];
121 - (void)setPrototypeView:(
CPView)aPrototypeView
133 - (void)setDelegate:(
id)anObject
135 _delegate = anObject;
136 _delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)];
148 return _tableViews[index];
153 return [_tableViews indexOfObject:aTableView];
156 - (void)loadColumnZero
158 if ([_delegate respondsToSelector:
@selector(rootItemForBrowser:)])
159 _rootItem = [_delegate rootItemForBrowser:self];
167 - (void)setLastColumn:(
int)columnIndex
169 if (columnIndex >= _tableViews.length)
172 var oldValue = _tableViews.length - 1,
173 indexPlusOne = columnIndex + 1;
175 [[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
176 makeObjectsPerformSelector:@selector(removeFromSuperview)];
178 _tableViews = _tableViews.slice(0, indexPlusOne);
179 _tableDelegates = _tableDelegates.slice(0, indexPlusOne);
181 if ([_delegate respondsToSelector:
@selector(browser:didChangeLastColumn:toColumn:)])
182 [_delegate browser:self didChangeLastColumn:oldValue toColumn:columnIndex];
189 return _tableViews.length - 1;
195 lastColumn = _tableViews[lastIndex],
196 selectionIndexes = [
lastColumn selectedRowIndexes];
198 if (lastIndex >= 0 && [selectionIndexes count] > 1)
200 reason:"Can't add column, column "+lastIndex+" has invalid selection."];
202 var index = lastIndex + 1,
203 item = index === 0 ? _rootItem : [_tableDelegates[lastIndex] childAtIndex:[selectionIndexes firstIndex]];
205 if (index > 0 && item && [
self isLeafItem:item])
208 var table = [[_tableViewClass alloc] initWithFrame:CGRectMakeZero() browser:self];
210 [table setHeaderView:nil];
211 [table setCornerView:nil];
212 [table setAllowsMultipleSelection:_allowsMultipleSelection];
213 [table setAllowsEmptySelection:_allowsEmptySelection];
216 [
self _addTableColumnsToTableView:table forColumnIndex:index];
218 var delegate = [[_CPBrowserTableDelegate alloc] init];
225 _tableViews[index] = table;
226 _tableDelegates[index] = delegate;
228 [table setDelegate:delegate];
229 [table setDataSource:delegate];
230 [table setTarget:delegate];
231 [table setAction:@selector(_tableViewClicked:)];
232 [table setDoubleAction:@selector(_tableViewDoubleClicked:)];
233 [table setDraggingDestinationFeedbackStyle:CPTableViewDraggingDestinationFeedbackStyleRegular];
235 var scrollView = [[_CPBrowserScrollView alloc] initWithFrame:CGRectMakeZero()];
236 [scrollView _setBrowser:self];
237 [scrollView setDocumentView:table];
238 [scrollView setHasHorizontalScroller:NO];
239 [scrollView setAutoresizingMask:CPViewHeightSizable];
241 [_contentView addSubview:scrollView];
248 - (void)_addTableColumnsToTableView:(
CPTableView)aTableView forColumnIndex:(
unsigned)index
250 if (_delegateSupportsImages)
255 [view setImageScaling:CPImageScaleProportionallyDown];
257 [column setDataView:view];
258 [column setResizingMask:CPTableColumnNoResizing];
265 [column setDataView:_prototypeView];
266 [column setResizingMask:CPTableColumnNoResizing];
271 view = [[_CPBrowserLeafView alloc] initWithFrame:CGRectMakeZero()];
273 [view setBranchImage:[[
self class] branchImage]];
274 [view setHighlightedBranchImage:[[
self class] highlightedBranchImage]];
276 [column setDataView:view];
277 [column setResizingMask:CPTableColumnNoResizing];
282 - (void)reloadColumn:(
int)column
291 height = CGRectGetHeight([_contentView bounds]);
293 for (var i = 0, count = _tableViews.length; i < count; i++)
296 scrollView = [tableView enclosingScrollView],
298 tableHeight = CGRectGetHeight([tableView bounds]);
300 [[tableView tableColumnWithIdentifier:"Image"] setWidth:_imageWidth];
302 [[tableView tableColumnWithIdentifier:"Leaf"] setWidth:_leafWidth];
304 [tableView setRowHeight:_rowHeight];
305 [tableView setFrameSize:CGSizeMake(width - scrollerWidth, tableHeight)];
306 [scrollView setFrameOrigin:CGPointMake(xOrigin, 0)];
307 [scrollView setFrameSize:CGSizeMake(width, height)];
312 [_contentView setFrameSize:CGSizeMake(xOrigin, height)];
315 - (unsigned)rowAtPoint:(CGPoint)aPoint
322 return [tableView rowAtPoint:[tableView convertPoint:aPoint fromView:self]];
325 - (unsigned)columnAtPoint:(CGPoint)aPoint
327 var adjustedPoint = [_contentView convertPoint:aPoint fromView:self];
329 for (var i = 0, count = _tableViews.length; i < count; i++)
331 var
frame = [[_tableViews[i] enclosingScrollView] frame];
332 if (CGRectContainsPoint(frame, adjustedPoint))
339 - (CGRect)rectOfRow:(
unsigned)aRow inColumn:(
unsigned)aColumn
342 rect = [tableView rectOfRow:aRow];
350 - (id)itemAtRow:(
int)row inColumn:(
int)column
352 return [_tableDelegates[column] childAtIndex:row];
355 - (BOOL)isLeafItem:(
id)item
357 return [_delegate respondsToSelector:@selector(browser:isLeafItem:)] && [_delegate browser:self isLeafItem:item];
360 - (id)parentForItemsInColumn:(
int)column
362 return [_tableDelegates[column] _item];
370 index = [selectedIndexes firstIndex];
375 index = [selectedIndexes indexGreaterThanIndex:index];
395 - (void)_column:(
unsigned)columnIndex clickedRow:(
unsigned)rowIndex
397 [
self setLastColumn:columnIndex];
410 - (void)doClick:(
id)sender
415 - (void)doDoubleClick:(
id)sender
426 [_tableViews[column] keyDown:anEvent];
431 - (float)columnContentWidthForColumnWidth:(
float)aWidth
433 var columnSpacing = [_tableViews[0] intercellSpacing].width;
434 return aWidth - (_leafWidth + columnSpacing + (_delegateSupportsImages ? _imageWidth + columnSpacing : 0)) - columnSpacing - [
CPScroller scrollerWidth];
437 - (float)columnWidthForColumnContentWidth:(
float)aWidth
439 var columnSpacing = [_tableViews[0] intercellSpacing].width;
440 return aWidth + (_leafWidth + columnSpacing + (_delegateSupportsImages ? _imageWidth + columnSpacing: 0)) + columnSpacing + [
CPScroller scrollerWidth];
443 - (void)setImageWidth:(
float)aWidth
445 _imageWidth = aWidth;
454 - (void)setMinColumnWidth:(
float)minWidth
456 _minColumnWidth = minWidth;
460 - (float)minColumnWidth
462 return _minColumnWidth;
465 - (void)setWidth:(
float)aWidth ofColumn:(
unsigned)column
467 _columnWidths[column] = aWidth;
469 if ([_delegate respondsToSelector:
@selector(browser:didResizeColumn:)])
470 [_delegate browser:
self didResizeColumn:column];
475 - (float)widthOfColumn:(
unsigned)column
477 var
width = _columnWidths[column];
480 width = _defaultColumnWidth;
485 - (void)setRowHeight:(
float)aHeight
487 _rowHeight = aHeight;
497 - (void)scrollColumnToVisible:(
unsigned)columnIndex
502 - (void)scrollRowToVisible:(
unsigned)rowIndex inColumn:(
unsigned)columnIndex
508 - (BOOL)autohidesScroller
510 return [_horizontalScrollView autohidesScrollers];
513 - (void)setAutohidesScroller:(BOOL)shouldHide
515 [_horizontalScrollView setAutohidesScrollers:shouldHide];
520 - (unsigned)selectedRowInColumn:(
unsigned)columnIndex
522 if (columnIndex > [
self lastColumn] || columnIndex < 0)
525 return [_tableViews[columnIndex] selectedRow];
528 - (unsigned)selectedColumn
539 - (void)selectRow:(
unsigned)row inColumn:(
unsigned)column
545 - (BOOL)allowsMultipleSelection
547 return _allowsMultipleSelection;
550 - (void)setAllowsMultipleSelection:(BOOL)shouldAllow
552 if (_allowsMultipleSelection === shouldAllow)
555 _allowsMultipleSelection = shouldAllow;
556 [_tableViews makeObjectsPerformSelector:@selector(setAllowsMultipleSelection:) withObject:shouldAllow];
559 - (BOOL)allowsEmptySelection
561 return _allowsEmptySelection;
564 - (void)setAllowsEmptySelection:(BOOL)shouldAllow
566 if (_allowsEmptySelection === shouldAllow)
569 _allowsEmptySelection = shouldAllow;
570 [_tableViews makeObjectsPerformSelector:@selector(setAllowsEmptySelection:) withObject:shouldAllow];
575 if (column < 0 || column > [
self lastColumn] +1)
581 - (void)selectRowIndexes:(
CPIndexSet)indexSet inColumn:(
unsigned)column
583 if (column < 0 || column > [
self lastColumn] + 1)
586 if ([_delegate respondsToSelector:
@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
587 indexSet = [_delegate browser:self selectionIndexesForProposedSelection:indexSet inColumn:column];
589 if ([_delegate respondsToSelector:
@selector(browser:shouldSelectRowIndexes:inColumn:)] &&
590 ![_delegate browser:
self shouldSelectRowIndexes:indexSet inColumn:column])
593 if ([_delegate respondsToSelector:
@selector(browserSelectionIsChanging:)])
594 [_delegate browserSelectionIsChanging:self];
596 if (column > [
self lastColumn])
605 if ([_delegate respondsToSelector:
@selector(browserSelectionDidChange:)])
606 [_delegate browserSelectionDidChange:self];
612 [_contentView setBackgroundColor:aColor];
615 - (BOOL)acceptsFirstResponder
622 - (void)registerForDraggedTypes:(
CPArray)types
625 [_tableViews makeObjectsPerformSelector:@selector(registerForDraggedTypes:) withObject:types];
628 - (BOOL)canDragRowsWithIndexes:(
CPIndexSet)rowIndexes inColumn:(
int)columnIndex withEvent:(
CPEvent)dragEvent
630 if ([_delegate respondsToSelector:
@selector(browser:canDragRowsWithIndexes:inColumn:withEvent:)])
631 return [_delegate browser:self canDragRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent];
636 - (
CPImage)draggingImageForRowsWithIndexes:(
CPIndexSet)rowIndexes inColumn:(
int)columnIndex withEvent:(
CPEvent)dragEvent offset:(CGPoint)dragImageOffset
638 if ([_delegate respondsToSelector:
@selector(browser:draggingImageForRowsWithIndexes:inColumn:withEvent:offset:)])
639 return [_delegate browser:self draggingImageForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
644 - (
CPView)draggingViewForRowsWithIndexes:(
CPIndexSet)rowIndexes inColumn:(
int)columnIndex withEvent:(
CPEvent)dragEvent offset:(CGPoint)dragImageOffset
646 if ([_delegate respondsToSelector:
@selector(browser:draggingViewForRowsWithIndexes:inColumn:withEvent:offset:)])
647 return [_delegate browser:self draggingViewForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
664 _allowsEmptySelection = [aCoder decodeBoolForKey:@"CPBrowserAllowsEmptySelectionKey"];
665 _allowsMultipleSelection = [aCoder decodeBoolForKey:@"CPBrowserAllowsMultipleSelectionKey"];
666 _prototypeView = [aCoder decodeObjectForKey:@"CPBrowserPrototypeViewKey"];
667 _rowHeight = [aCoder decodeFloatForKey:@"CPBrowserRowHeightKey"];
668 _imageWidth = [aCoder decodeFloatForKey:@"CPBrowserImageWidthKey"];
669 _minColumnWidth = [aCoder decodeFloatForKey:@"CPBrowserMinColumnWidthKey"];
670 _columnWidths = [aCoder decodeObjectForKey:@"CPBrowserColumnWidthsKey"];
672 [
self setDelegate:[aCoder decodeObjectForKey:@"CPBrowserDelegateKey"]];
682 var actualSubviews = _subviews;
685 _subviews = actualSubviews;
687 [aCoder encodeBool:[
self autohidesScroller] forKey:@"CPBrowserAutohidesScrollerKey"];
688 [aCoder encodeBool:_allowsEmptySelection forKey:@"CPBrowserAllowsEmptySelectionKey"];
689 [aCoder encodeBool:_allowsMultipleSelection forKey:@"CPBrowserAllowsMultipleSelectionKey"];
690 [aCoder encodeObject:_delegate forKey:@"CPBrowserDelegateKey"];
691 [aCoder encodeObject:_prototypeView forKey:@"CPBrowserPrototypeViewKey"];
692 [aCoder encodeFloat:_rowHeight forKey:@"CPBrowserRowHeightKey"];
693 [aCoder encodeFloat:_imageWidth forKey:@"CPBrowserImageWidthKey"];
694 [aCoder encodeFloat:_minColumnWidth forKey:@"CPBrowserMinColumnWidthKey"];
695 [aCoder encodeObject:_columnWidths forKey:@"CPBrowserColumnWidthsKey"];
701 var _CPBrowserResizeControlBackgroundImage = nil;
703 @implementation _CPBrowserResizeControl :
CPView
713 if (!_CPBrowserResizeControlBackgroundImage)
717 size:CGSizeMake(15, 14)];
720 return _CPBrowserResizeControlBackgroundImage;
723 - (id)initWithFrame:(CGRect)aFrame
725 if (
self = [super initWithFrame:aFrame])
731 - (void)mouseDown:(
CPEvent)anEvent
734 _browser = [[
self superview] _browser];
735 _index = [_browser columnOfTableView:[[
self superview] documentView]];
736 _width = [_browser widthOfColumn:_index];
739 - (void)mouseDragged:(
CPEvent)anEvent
742 [_browser setWidth:_width + deltaX ofColumn:_index];
745 - (void)mouseUp:(
CPEvent)anEvent
753 _CPBrowserResizeControl _resizeControl;
757 - (void)initWithFrame:(CGRect)aFrame
759 if (
self = [super initWithFrame:aFrame])
761 _resizeControl = [[_CPBrowserResizeControl alloc] initWithFrame:CGRectMakeZero()];
762 [
self addSubview:_resizeControl];
768 - (void)reflectScrolledClipView:(
CPClipView)aClipView
770 [
super reflectScrolledClipView:aClipView];
772 var
frame = [_verticalScroller frame];
773 frame.size.height = CGRectGetHeight([
self bounds]) - 14.0 -
frame.origin.y;
774 [_verticalScroller setFrameSize:frame.size];
776 var resizeFrame = CGRectMake(CGRectGetMinX(
frame), CGRectGetMaxY(
frame), [
CPScroller scrollerWidth], 14.0);
777 [_resizeControl setFrame:resizeFrame];
787 - (id)initWithFrame:(CGRect)aFrame browser:(
CPBrowser)aBrowser
789 if (
self = [super initWithFrame:aFrame])
795 - (BOOL)acceptsFirstResponder
800 - (void)mouseDown:(
CPEvent)anEvent
802 [
super mouseDown:anEvent];
803 [[
self window] makeFirstResponder:_browser];
811 - (BOOL)canDragRowsWithIndexes:(
CPIndexSet)rowIndexes atPoint:(CGPoint)mouseDownPoint
813 return [_browser canDragRowsWithIndexes:rowIndexes inColumn:[_browser columnOfTableView:self] withEvent:[CPApp currentEvent]];
816 - (
CPImage)dragImageForRowsWithIndexes:(
CPIndexSet)dragRows tableColumns:(
CPArray)theTableColumns event:(
CPEvent)dragEvent offset:(CPPointPointer)dragImageOffset
818 return [_browser draggingImageForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragImageOffset] ||
819 [
super dragImageForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragImageOffset];
822 - (
CPView)dragViewForRowsWithIndexes:(
CPIndexSet)dragRows tableColumns:(
CPArray)theTableColumns event:(
CPEvent)dragEvent offset:(CPPoint)dragViewOffset
824 var count = theTableColumns.length;
827 if ([theTableColumns[count] identifier] ===
"Leaf")
828 [theTableColumns removeObject:theTableColumns[count]];
831 return [_browser draggingViewForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragViewOffset] ||
832 [
super dragViewForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragViewOffset];
835 - (void)moveUp:(
id)sender
837 [
super moveUp:sender];
838 [_browser selectRow:[
self selectedRow] inColumn:[_browser selectedColumn]];
841 - (void)moveDown:(
id)sender
843 [
super moveDown:sender];
844 [_browser selectRow:[
self selectedRow] inColumn:[_browser selectedColumn]];
847 - (void)moveLeft:(
id)sender
849 var previousColumn = [_browser selectedColumn] - 1,
850 selectedRow = [_browser selectedRowInColumn:previousColumn];
852 [_browser selectRow:selectedRow inColumn:previousColumn];
855 - (void)moveRight:(
id)sender
857 [_browser selectRow:0 inColumn:[_browser selectedColumn] + 1];
863 @implementation _CPBrowserTableDelegate :
CPObject
871 - (unsigned)numberOfRowsInTableView:(
CPTableView)aTableView
873 return [_delegate browser:_browser numberOfChildrenOfItem:_item];
878 if ([column identifier] ===
"Image")
879 return [_delegate browser:_browser imageValueForItem:[
self childAtIndex:row]];
880 else if ([column identifier] ===
"Leaf")
881 return ![_browser isLeafItem:[
self childAtIndex:row]];
883 return [_delegate browser:_browser objectValueForItem:[
self childAtIndex:row]];
886 - (void)_tableViewDoubleClicked:(
CPTableView)aTableView
888 [_browser doDoubleClick:self];
894 [_browser _column:_index clickedRow:[selectedIndexes count] === 1 ? [selectedIndexes firstIndex] : -1];
899 var selectedIndexes = [[aNotification
object] selectedRowIndexes];
900 [_browser selectRowIndexes:selectedIndexes inColumn:_index];
903 - (id)childAtIndex:(
unsigned)index
905 return [_delegate browser:_browser child:index ofItem:_item];
908 - (BOOL)
tableView:(
CPTableView)aTableView acceptDrop:(
id)info row:(
int)row dropOperation:(CPTableViewDropOperation)operation
910 if ([_delegate respondsToSelector:
@selector(browser:acceptDrop:atRow:column:dropOperation:)])
911 return [_delegate browser:_browser acceptDrop:info atRow:row column:_index dropOperation:operation];
916 - (CPDragOperation)
tableView:(
CPTableView)aTableView validateDrop:(
id)info proposedRow:(
int)row proposedDropOperation:(CPTableViewDropOperation)operation
918 if ([_delegate respondsToSelector:
@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
919 return [_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
926 if ([_delegate respondsToSelector:
@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)])
927 return [_delegate browser:_browser writeRowsWithIndexes:rowIndexes inColumn:_index toPasteboard:pboard];
932 - (BOOL)respondsToSelector:(
SEL)aSelector
934 if (aSelector ===
@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:))
935 return [_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)];
937 return [
super respondsToSelector:aSelector];
942 @implementation _CPBrowserLeafView :
CPView
946 CPImage _highlightedBranchImage;
954 - (void)setObjectValue:(
id)aValue
957 [
self setNeedsLayout];
960 - (CGRect)rectForEphemeralSubviewNamed:(
CPString)aName
962 if (aName ===
"image-view")
963 return CGRectInset([
self bounds], 1, 1);
965 return [
super rectForEphemeralSubviewNamed:aName];
970 if (aName ===
"image-view")
973 return [
super createEphemeralSubviewNamed:aName];
976 - (void)layoutSubviews
978 var imageView = [
self layoutEphemeralSubviewNamed:@"image-view"
979 positioned:CPWindowAbove
980 relativeToEphemeralSubviewNamed:nil],
983 [imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
984 [imageView setImageScaling:CPImageScaleNone];
987 - (void)encodeWithCoder:(
CPCoder)aCoder
989 [
super encodeWithCoder:aCoder];
991 [aCoder encodeBool:_isLeaf forKey:"_CPBrowserLeafViewIsLeafKey"];
992 [aCoder encodeObject:_branchImage forKey:"_CPBrowserLeafViewBranchImageKey"];
993 [aCoder encodeObject:_highlightedBranchImage forKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
996 - (void)initWithCoder:(
CPCoder)aCoder
998 if (
self = [super initWithCoder:aCoder])
1000 _isLeaf = [aCoder decodeBoolForKey:"_CPBrowserLeafViewIsLeafKey"];
1001 _branchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewBranchImageKey"];
1002 _highlightedBranchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
1017 return _doubleAction;
1023 - (void)setDoubleAction:(
SEL)aValue
1025 _doubleAction = aValue;
1031 - (Class)tableViewClass
1033 return _tableViewClass;
1039 - (void)setTableViewClass:(Class)aValue
1041 _tableViewClass = aValue;
1047 - (float)defaultColumnWidth
1049 return _defaultColumnWidth;
1055 - (void)setDefaultColumnWidth:(
float)aValue
1057 _defaultColumnWidth = aValue;