84 #define SELECTION_SHOULD_CHANGE(anOutlineView) (!((anOutlineView)._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_selectionShouldChangeInOutlineView_) || [(anOutlineView)._outlineViewDelegate selectionShouldChangeInOutlineView:(anOutlineView)])
86 #define SHOULD_SELECT_ITEM(anOutlineView, anItem) (!((anOutlineView)._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_) || [(anOutlineView)._outlineViewDelegate outlineView:(anOutlineView) shouldSelectItem:(anItem)])
105 id _outlineViewDataSource;
106 id _outlineViewDelegate;
109 float _indentationPerLevel;
110 BOOL _indentationMarkerFollowsDataView;
112 CPInteger _implementedOutlineViewDataSourceMethods;
113 CPInteger _implementedOutlineViewDelegateMethods;
115 Object _rootItemInfo;
117 Object _itemInfosForItems;
120 CPArray _disclosureControlsForRows;
121 CPData _disclosureControlData;
122 CPArray _disclosureControlQueue;
124 BOOL _shouldRetargetItem;
127 BOOL _shouldRetargetChildIndex;
128 CPInteger _retargedChildIndex;
132 BOOL _coalesceSelectionNotificationState;
135 - (id)initWithFrame:(CGRect)aFrame
141 _selectionHighlightStyle = CPTableViewSelectionHighlightStyleSourceList;
144 _rootItemInfo = { isExpanded:YES, isExpandable:NO, shouldShowOutlineDisclosureControl:NO, level:-1, row:-1, children:[], weight:0 };
147 _itemInfosForItems = { };
148 _disclosureControlsForRows = [];
150 _retargetedItem = nil;
151 _shouldRetargetItem = NO;
153 _retargedChildIndex = nil;
154 _shouldRetargetChildIndex = NO;
159 [
super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
160 [
super setDelegate:[[_CPOutlineViewTableViewDelegate alloc] initWithOutlineView:self]];
218 - (void)setDataSource:(
id)aDataSource
220 if (_outlineViewDataSource === aDataSource)
223 if (![aDataSource respondsToSelector:
@selector(outlineView:child:ofItem:)])
224 [
CPException raise:CPInternalInconsistencyException
reason:"Data source must implement 'outlineView:child:ofItem:'"];
226 if (![aDataSource respondsToSelector:
@selector(outlineView:isItemExpandable:)])
227 [
CPException raise:CPInternalInconsistencyException
reason:"Data source must implement 'outlineView:isItemExpandable:'"];
229 if (![aDataSource respondsToSelector:
@selector(outlineView:numberOfChildrenOfItem:)])
230 [
CPException raise:CPInternalInconsistencyException
reason:"Data source must implement 'outlineView:numberOfChildrenOfItem:'"];
232 _outlineViewDataSource = aDataSource;
233 _implementedOutlineViewDataSourceMethods = 0;
235 if ([_outlineViewDataSource respondsToSelector:
@selector(outlineView:objectValueForTableColumn:byItem:)])
238 if ([_outlineViewDataSource respondsToSelector:
@selector(outlineView:setObjectValue:forTableColumn:byItem:)])
241 if ([_outlineViewDataSource respondsToSelector:
@selector(outlineView:shouldDeferDisplayingChildrenOfItem:)])
244 if ([_outlineViewDataSource respondsToSelector:
@selector(outlineView:acceptDrop:item:childIndex:)])
247 if ([_outlineViewDataSource respondsToSelector:
@selector(outlineView:validateDrop:proposedItem:proposedChildIndex:)])
250 if ([_outlineViewDataSource respondsToSelector:
@selector(outlineView:validateDrop:proposedRow:proposedDropOperation:)])
253 if ([_outlineViewDataSource respondsToSelector:
@selector(outlineView:namesOfPromisedFilesDroppedAtDestination:forDraggedItems:)])
256 if ([_outlineViewDataSource respondsToSelector:
@selector(outlineView:itemForPersistentObject:)])
259 if ([_outlineViewDataSource respondsToSelector:
@selector(outlineView:persistentObjectForItem:)])
262 if ([_outlineViewDataSource respondsToSelector:
@selector(outlineView:writeItems:toPasteboard:)])
265 if ([_outlineViewDataSource respondsToSelector:
@selector(outlineView:sortDescriptorsDidChange:)])
278 return _outlineViewDataSource;
288 - (BOOL)isExpandable:(
id)anItem
293 var itemInfo = _itemInfosForItems[[anItem UID]];
298 return itemInfo.isExpandable;
301 - (BOOL)_shouldShowOutlineDisclosureControlForItem:(
id)anItem
306 var itemInfo = _itemInfosForItems[[anItem UID]];
311 return itemInfo.shouldShowOutlineDisclosureControl;
321 - (BOOL)isItemExpanded:(
id)anItem
326 var itemInfo = _itemInfosForItems[[anItem UID]];
331 return itemInfo.isExpanded;
339 - (void)expandItem:(
id)anItem
350 - (void)expandItem:(
id)anItem expandChildren:(BOOL)shouldExpandChildren
352 if ([
self _delegateRespondsToShouldExpandItem])
353 if ([_outlineViewDelegate outlineView:
self shouldExpandItem:anItem] == NO)
359 itemInfo = _rootItemInfo;
361 itemInfo = _itemInfosForItems[[anItem UID]];
370 if (!_coalesceSelectionNotificationState)
377 if (!itemInfo.isExpanded)
379 [
self _noteItemWillExpand:anItem];
381 var previousRowCount = [
self numberOfRows];
383 itemInfo.isExpanded = YES;
385 [
self _noteItemDidExpand:anItem];
388 var rowCountDelta = [
self numberOfRows] - previousRowCount;
391 var selection = [
self selectedRowIndexes],
394 if ([selection intersectsIndexesInRange:
CPMakeRange(expandIndex, _itemsForRows.length)])
396 [
self _noteSelectionIsChanging];
397 [selection shiftIndexesStartingAtIndex:expandIndex by:rowCountDelta];
398 [
self _setSelectedRowIndexes:selection];
403 if (shouldExpandChildren)
405 var children = itemInfo.children,
406 childIndex = children.length;
414 var r = _coalesceSelectionNotificationState;
417 [
self _noteSelectionDidChange];
426 - (void)collapseItem:(
id)anItem
431 if ([
self _delegateRespondsToShouldCollapseItem])
432 if ([_outlineViewDelegate outlineView:
self shouldCollapseItem:anItem] == NO)
435 var itemInfo = _itemInfosForItems[[anItem UID]];
440 if (!itemInfo.isExpanded)
446 [
self _noteItemWillCollapse:anItem];
450 var collapseTopIndex = [
self rowForItem:anItem],
452 collapseEndIndex = collapseTopIndex;
454 while (collapseEndIndex + 1 < _itemsForRows.length && [
self levelForRow:collapseEndIndex + 1] > topLevel)
457 var collapseRange =
CPMakeRange(collapseTopIndex + 1, collapseEndIndex - collapseTopIndex);
459 if (collapseRange.length)
461 var selection = [
self selectedRowIndexes];
463 if ([selection intersectsIndexesInRange:collapseRange])
465 [
self _noteSelectionIsChanging];
466 [selection removeIndexesInRange:collapseRange];
467 [
self _setSelectedRowIndexes:selection];
471 if ([selection intersectsIndexesInRange:
CPMakeRange(collapseEndIndex + 1, _itemsForRows.length)])
473 [
self _noteSelectionIsChanging];
474 [selection shiftIndexesStartingAtIndex:collapseEndIndex + 1 by:-collapseRange.length];
475 [
self _setSelectedRowIndexes:selection];
478 itemInfo.isExpanded = NO;
481 [
self _noteItemDidCollapse:anItem];
485 var r = _coalesceSelectionNotificationState;
488 [
self _noteSelectionDidChange];
496 - (void)reloadItem:(
id)anItem
507 - (void)reloadItem:(
id)anItem reloadChildren:(BOOL)shouldReloadChildren
509 if (!!shouldReloadChildren || !anItem)
510 _loadItemInfoForItem(
self, anItem);
512 _reloadItem(
self, anItem);
523 - (id)itemAtRow:(CPInteger)aRow
525 return _itemsForRows[aRow] || nil;
534 - (CPInteger)rowForItem:(
id)anItem
537 return _rootItemInfo.row;
539 var itemInfo = _itemInfosForItems[[anItem UID]];
555 if (_outlineTableColumn === aTableColumn)
558 _outlineTableColumn = aTableColumn;
571 return _outlineTableColumn;
582 - (CPInteger)levelForItem:(
id)anItem
585 return _rootItemInfo.level;
587 var itemInfo = _itemInfosForItems[[anItem UID]];
592 return itemInfo.level;
602 - (CPInteger)levelForRow:(CPInteger)aRow
612 - (void)setIndentationPerLevel:(
float)anIndentationWidth
614 if (_indentationPerLevel === anIndentationWidth)
617 _indentationPerLevel = anIndentationWidth;
628 - (float)indentationPerLevel
630 return _indentationPerLevel;
640 - (void)setIndentationMarkerFollowsDataView:(BOOL)indentationMarkerShouldFollowDataView
642 if (_indentationMarkerFollowsDataView === indentationMarkerShouldFollowDataView)
645 _indentationMarkerFollowsDataView = indentationMarkerShouldFollowDataView;
658 - (BOOL)indentationMarkerFollowsDataView
660 return _indentationMarkerFollowsDataView;
670 - (id)parentForItem:(
id)anItem
675 var itemInfo = _itemInfosForItems[[anItem UID]];
680 var parent = itemInfo.parent;
683 if (itemInfo[[parent UID]] === _rootItemInfo)
694 - (CGRect)_frameOfOutlineDataViewAtRow:(CPInteger)aRow
696 var columnIndex = [[
self tableColumns] indexOfObject:_outlineTableColumn],
697 frame = [
super frameOfDataViewAtColumn:columnIndex row:aRow],
698 indentationWidth = ([
self levelForRow:aRow] + 1) * [self indentationPerLevel];
700 frame.origin.x += indentationWidth;
701 frame.size.width -= indentationWidth;
714 - (CGRect)frameOfOutlineDisclosureControlAtRow:(CPInteger)aRow
717 if (![
self isExpandable:theItem] || ![
self _shouldShowOutlineDisclosureControlForItem:theItem])
718 return CGRectMakeZero();
720 var dataViewFrame = [
self _frameOfOutlineDataViewAtRow:aRow],
721 disclosureWidth = CGRectGetWidth([_disclosureControlPrototype
frame]),
722 frame = CGRectMake(CGRectGetMinX(dataViewFrame) - disclosureWidth, CGRectGetMinY(dataViewFrame), disclosureWidth, CGRectGetHeight(dataViewFrame));
731 - (void)_setSelectedRowIndexes:(
CPIndexSet)rows
733 if (_disclosureControlsForRows.length)
735 var indexes = [_selectedRowIndexes copy];
736 [indexes removeIndexesInRange:CPMakeRange(_disclosureControlsForRows.length, _itemsForRows.length - _disclosureControlsForRows.length)];
737 [[_disclosureControlsForRows objectsAtIndexes:indexes] makeObjectsPerformSelector:@selector(unsetThemeState:) withObject:CPThemeStateSelected];
740 [
super _setSelectedRowIndexes:rows];
742 if (_disclosureControlsForRows.length)
744 var indexes = [_selectedRowIndexes copy];
745 [indexes removeIndexesInRange:CPMakeRange(_disclosureControlsForRows.length, _itemsForRows.length - _disclosureControlsForRows.length)];
746 [[_disclosureControlsForRows objectsAtIndexes:indexes] makeObjectsPerformSelector:@selector(setThemeState:) withObject:CPThemeStateSelected];
826 - (void)setDelegate:(
id)aDelegate
828 if (_outlineViewDelegate === aDelegate)
833 if (_outlineViewDelegate)
835 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewColumnDidMove:)])
837 removeObserver:_outlineViewDelegate
838 name:CPOutlineViewColumnDidMoveNotification
841 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewColumnDidResize:)])
843 removeObserver:_outlineViewDelegate
844 name:CPOutlineViewColumnDidResizeNotification
847 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewSelectionDidChange:)])
849 removeObserver:_outlineViewDelegate
850 name:CPOutlineViewSelectionDidChangeNotification
853 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewSelectionIsChanging:)])
855 removeObserver:_outlineViewDelegate
856 name:CPOutlineViewSelectionIsChangingNotification
859 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewItemWillExpand:)])
861 removeObserver:_outlineViewDelegate
862 name:CPOutlineViewItemWillExpandNotification
865 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewItemDidExpand:)])
867 removeObserver:_outlineViewDelegate
868 name:CPOutlineViewItemDidExpandNotification
871 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewItemWillCollapse:)])
873 removeObserver:_outlineViewDelegate
874 name:CPOutlineViewItemWillCollapseNotification
877 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewItemDidCollapse:)])
879 removeObserver:_outlineViewDelegate
880 name:CPOutlineViewItemDidCollapseNotification
884 _outlineViewDelegate = aDelegate;
885 _implementedOutlineViewDelegateMethods = 0;
887 var delegateMethods = [
888 CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ , @selector(outlineView:dataViewForTableColumn:item:),
889 CPOutlineViewDelegate_outlineView_viewForTableColumn_item_ , @selector(outlineView:viewForTableColumn:item:),
890 CPOutlineViewDelegate_outlineView_didClickTableColumn_ , @selector(outlineView:didClickTableColumn:),
891 CPOutlineViewDelegate_outlineView_didDragTableColumn_ , @selector(outlineView:didDragTableColumn:),
892 CPOutlineViewDelegate_outlineView_heightOfRowByItem_ , @selector(outlineView:heightOfRowByItem:),
893 CPOutlineViewDelegate_outlineView_isGroupItem_ , @selector(outlineView:isGroupItem:),
894 CPOutlineViewDelegate_outlineView_mouseDownInHeaderOfTableColumn_ , @selector(outlineView:mouseDownInHeaderOfTableColumn:),
895 CPOutlineViewDelegate_outlineView_nextTypeSelectMatchFromItem_toItem_forString_ , @selector(outlineView:nextTypeSelectMatchFromItem:toItem:forString:),
896 CPOutlineViewDelegate_outlineView_selectionIndexesForProposedSelection_ , @selector(outlineView:selectionIndexesForProposedSelection:),
897 CPOutlineViewDelegate_outlineView_shouldCollapseItem_ , @selector(outlineView:shouldCollapseItem:),
898 CPOutlineViewDelegate_outlineView_shouldEditTableColumn_item_ , @selector(outlineView:shouldEditTableColumn:item:),
899 CPOutlineViewDelegate_outlineView_shouldExpandItem_ , @selector(outlineView:shouldExpandItem:),
900 CPOutlineViewDelegate_outlineView_shouldReorderColumn_toColumn_ , @selector(outlineView:shouldReorderColumn:toColumn:),
901 CPOutlineViewDelegate_outlineView_shouldSelectItem_ , @selector(outlineView:shouldSelectItem:),
902 CPOutlineViewDelegate_outlineView_shouldSelectTableColumn_ , @selector(outlineView:shouldSelectTableColumn:),
903 CPOutlineViewDelegate_outlineView_shouldShowOutlineDisclosureControlForItem_ , @selector(outlineView:shouldShowOutlineDisclosureControlForItem:),
904 CPOutlineViewDelegate_outlineView_shouldShowViewExpansionForTableColumn_item_ , @selector(outlineView:shouldShowViewExpansionForTableColumn:item:),
905 CPOutlineViewDelegate_outlineView_shouldTrackView_forTableColumn_item_ , @selector(outlineView:shouldTrackView:forTableColumn:item:),
906 CPOutlineViewDelegate_outlineView_shouldTypeSelectForEvent_withCurrentSearchString_ , @selector(outlineView:shouldTypeSelectForEvent:withCurrentSearchString:),
907 CPOutlineViewDelegate_outlineView_sizeToFitWidthOfColumn_ , @selector(outlineView:sizeToFitWidthOfColumn:),
908 CPOutlineViewDelegate_outlineView_toolTipForView_rect_tableColumn_item_mouseLocation_, @selector(outlineView:toolTipForView:rect:tableColumn:item:mouseLocation:),
909 CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ , @selector(outlineView:typeSelectStringForTableColumn:item:),
910 CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ , @selector(outlineView:willDisplayOutlineView:forTableColumn:item:),
911 CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ , @selector(outlineView:willDisplayView:forTableColumn:item:),
912 CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ , @selector(selectionShouldChangeInOutlineView:),
913 CPOutlineViewDelegate_outlineView_menuForTableColumn_item_ , @selector(outlineView:menuForTableColumn:item:)
915 delegateCount = [delegateMethods count];
917 for (var i = 0; i < delegateCount; i += 2)
919 var bitMask = delegateMethods[i],
920 selector = delegateMethods[i + 1];
922 if ([_outlineViewDelegate respondsToSelector:selector])
923 _implementedOutlineViewDelegateMethods |= bitMask;
926 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewColumnDidMove:)])
928 addObserver:_outlineViewDelegate
929 selector:@selector(outlineViewColumnDidMove:)
930 name:CPOutlineViewColumnDidMoveNotification
933 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewColumnDidResize:)])
935 addObserver:_outlineViewDelegate
936 selector:@selector(outlineViewColumnDidMove:)
937 name:CPOutlineViewColumnDidResizeNotification
940 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewSelectionDidChange:)])
942 addObserver:_outlineViewDelegate
943 selector:@selector(outlineViewSelectionDidChange:)
944 name:CPOutlineViewSelectionDidChangeNotification
947 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewSelectionIsChanging:)])
949 addObserver:_outlineViewDelegate
950 selector:@selector(outlineViewSelectionIsChanging:)
951 name:CPOutlineViewSelectionIsChangingNotification
954 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewItemWillExpand:)])
956 addObserver:_outlineViewDelegate
957 selector:@selector(outlineViewItemWillExpand:)
958 name:CPOutlineViewItemWillExpandNotification
961 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewItemDidExpand:)])
963 addObserver:_outlineViewDelegate
964 selector:@selector(outlineViewItemDidExpand:)
965 name:CPOutlineViewItemDidExpandNotification
968 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewItemWillCollapse:)])
970 addObserver:_outlineViewDelegate
971 selector:@selector(outlineViewItemWillCollapse:)
972 name:CPOutlineViewItemWillCollapseNotification
975 if ([_outlineViewDelegate respondsToSelector:
@selector(outlineViewItemDidCollapse:)])
977 addObserver:_outlineViewDelegate
978 selector:@selector(outlineViewItemDidCollapse:)
979 name:CPOutlineViewItemDidCollapseNotification
982 [
self _updateIsViewBased];
984 if ([
self _delegateRespondsToDataViewForTableColumn])
985 CPLog.warn(
"outlineView:dataViewForTableColumn:item: is deprecated. You should use -outlineView:viewForTableColumn:item: where you can request the view with -makeViewWithIdentifier:owner:");
988 - (BOOL)_sendDelegateDeleteKeyPressed
990 if ([[
self delegate] respondsToSelector:
@selector(outlineViewDeleteKeyPressed:)])
992 [[
self delegate] outlineViewDeleteKeyPressed:self];
1004 return _outlineViewDelegate;
1016 _disclosureControlPrototype = aControl;
1017 _disclosureControlData = nil;
1018 _disclosureControlQueue = [];
1044 [
super addTableColumn:aTableColumn];
1046 if ([
self numberOfColumns] === 1)
1047 _outlineTableColumn = aTableColumn;
1054 if (aTableColumn === [
self outlineTableColumn])
1055 CPLog(
"CPOutlineView cannot remove outlineTableColumn with removeTableColumn:. User setOutlineTableColumn: instead.");
1057 [
super removeTableColumn:aTableColumn];
1064 - (CGRect)frameOfDataViewAtColumn:(CPInteger)aColumn row:(CPInteger)aRow
1066 var tableColumn = [
self tableColumns][aColumn];
1068 if (tableColumn === _outlineTableColumn)
1069 return [
self _frameOfOutlineDataViewAtRow:aRow];
1071 return [
super frameOfDataViewAtColumn:aColumn row:aRow];
1078 - (
CPView)_dragViewForColumn:(CPInteger)theColumnIndex event:(
CPEvent)theDragEvent offset:(CGPoint)theDragViewOffset
1080 var dragView = [[_CPColumnDragView alloc] initWithLineColor:[
self gridColor]],
1081 tableColumn = [[
self tableColumns] objectAtIndex:theColumnIndex],
1082 defaultRowHeight = [
self valueForThemeAttribute:@"default-row-height"],
1083 bounds = CGRectMake(0.0, 0.0, [tableColumn
width], CGRectGetHeight([
self exposedRect]) + defaultRowHeight),
1084 columnRect = [
self rectOfColumn:theColumnIndex],
1085 headerView = [tableColumn headerView],
1086 row = [_exposedRows firstIndex];
1090 var dataView = [
self _newDataViewForRow:row tableColumn:tableColumn],
1091 dataViewFrame = [
self frameOfDataViewAtColumn:theColumnIndex row:row];
1094 dataViewFrame.origin.x = 0.0;
1097 dataViewFrame.origin.y = (CGRectGetMinY(dataViewFrame) - CGRectGetMinY([self exposedRect])) + defaultRowHeight;
1098 [dataView setFrame:dataViewFrame];
1100 [dataView setObjectValue:[
self _objectValueForTableColumn:tableColumn row:row]];
1103 if (tableColumn === _outlineTableColumn)
1106 var indentationWidth = ([
self levelForRow:row] + 1) * [self indentationPerLevel];
1108 dataViewFrame.origin.x += indentationWidth;
1109 dataViewFrame.size.width -= indentationWidth;
1111 [dataView setFrame:dataViewFrame];
1114 [dragView addSubview:dataView];
1116 row = [_exposedRows indexGreaterThanIndex:row];
1120 var headerFrame = [headerView frame];
1121 headerFrame.origin = CGPointMakeZero();
1123 var columnHeaderView = [[_CPTableColumnHeaderView alloc] initWithFrame:headerFrame];
1124 [columnHeaderView setStringValue:[headerView stringValue]];
1125 [columnHeaderView setThemeState:[headerView themeState]];
1126 [dragView addSubview:columnHeaderView];
1129 [dragView setAlphaValue:0.7];
1130 [dragView setFrame:bounds];
1150 - (void)setDropItem:(
id)theItem dropChildIndex:(
int)theIndex
1152 if (_dropItem !== theItem && theIndex < 0 && [
self isExpandable:theItem] && ![
self isItemExpanded:theItem])
1154 if (_dragHoverTimer)
1155 [_dragHoverTimer invalidate];
1157 var autoExpandCallBack =
function()
1161 [_dropOperationFeedbackView blink];
1171 [_dragHoverTimer invalidate];
1172 _dragHoverTimer = nil;
1175 _dropItem = theItem;
1176 _retargetedItem = theItem;
1177 _shouldRetargetItem = YES;
1179 _retargedChildIndex = theIndex;
1180 _shouldRetargetChildIndex = YES;
1183 var retargetedItemInfo = (_retargetedItem !== nil) ? _itemInfosForItems[[_retargetedItem UID]] : _rootItemInfo;
1185 if (_retargedChildIndex === [retargetedItemInfo.children count])
1187 var retargetedChildItem = [retargetedItemInfo.children lastObject];
1188 _retargetedDropRow = [
self rowForItem:retargetedChildItem] + 1;
1192 var retargetedChildItem = (_retargedChildIndex !==
CPOutlineViewDropOnItemIndex) ? retargetedItemInfo.children[_retargedChildIndex] : _retargetedItem;
1193 _retargetedDropRow = [
self rowForItem:retargetedChildItem];
1200 - (void)_draggingEnded
1202 [
super _draggingEnded];
1204 [_dragHoverTimer invalidate];
1205 _dragHoverTimer = nil;
1211 - (id)_parentItemForUpperRow:(CPInteger)theUpperRowIndex andLowerRow:(CPInteger)theLowerRowIndex atMouseOffset:(CGPoint)theOffset
1213 if (_shouldRetargetItem)
1214 return _retargetedItem;
1216 var lowerLevel = [
self levelForRow:theLowerRowIndex],
1217 upperItem = [
self itemAtRow:theUpperRowIndex],
1218 upperLevel = [
self levelForItem:upperItem];
1223 while (upperLevel > lowerLevel)
1225 upperLevel = [
self levelForItem:upperItem];
1228 if (theOffset.x > (upperLevel + 1) * [
self indentationPerLevel])
1229 return [
self parentForItem:upperItem];
1232 upperItem = [
self parentForItem:upperItem];
1235 return [
self parentForItem:[
self itemAtRow:theLowerRowIndex]];
1241 - (CGRect)_rectForDropHighlightViewBetweenUpperRow:(CPInteger)theUpperRowIndex andLowerRow:(CPInteger)theLowerRowIndex offset:(CGPoint)theOffset
1244 var rect = [
super _rectForDropHighlightViewBetweenUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex offset:theOffset],
1245 parentItem = [
self _parentItemForUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex atMouseOffset:theOffset],
1246 level = [
self levelForItem:parentItem];
1248 rect.origin.x = (level + 1) * [self indentationPerLevel];
1249 rect.size.width -= rect.origin.x;
1266 var columnIndex = 0,
1267 columnsCount = columnArray.length;
1269 for (; columnIndex < columnsCount; ++columnIndex)
1271 var column = columnArray[columnIndex],
1272 tableColumn = _tableColumns[column],
1273 tableColumnUID = [tableColumn UID],
1274 dataViewsForTableColumn = _dataViewsForTableColumns[tableColumnUID],
1276 rowsCount = rowArray.length;
1278 for (; rowIndex < rowsCount; ++rowIndex)
1280 var row = rowArray[rowIndex],
1281 dataView = dataViewsForTableColumn[row],
1282 dataViewFrame = [
self frameOfDataViewAtColumn:column row:row];
1284 [dataView setFrame:dataViewFrame];
1286 if (tableColumn === _outlineTableColumn)
1288 var control = _disclosureControlsForRows[row],
1289 frame = [
self frameOfOutlineDisclosureControlAtRow:row];
1291 [control setFrame:frame];
1302 [
super _loadDataViewsInRows:rows columns:columns];
1304 var outlineColumn = [[
self tableColumns] indexOfObjectIdenticalTo:[
self outlineTableColumn]];
1306 if (![columns containsIndex:outlineColumn] || [
self outlineTableColumn] === _draggedColumn)
1314 rowsCount = rowArray.length;
1316 for (; rowIndex < rowsCount; ++rowIndex)
1318 var row = rowArray[rowIndex],
1319 item = _itemsForRows[row],
1320 isExpandable = [
self isExpandable:item];
1325 var disclosureControlFrame = [
self frameOfOutlineDisclosureControlAtRow:row];
1327 if (CGRectIsEmpty(disclosureControlFrame))
1330 var control = [
self _dequeueDisclosureControl];
1332 _disclosureControlsForRows[row] = control;
1334 [control setState:[
self isItemExpanded:item] ? CPOnState : CPOffState];
1335 var selector = [
self isRowSelected:row] ?
@"setThemeState:" :
@"unsetThemeState:";
1336 [control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected];
1337 [control setFrame:disclosureControlFrame];
1339 [
self addSubview:control];
1348 [
super _unloadDataViewsInRows:rows columns:columns];
1350 var outlineColumn = [[
self tableColumns] indexOfObjectIdenticalTo:[
self outlineTableColumn]];
1352 if (![columns containsIndex:outlineColumn])
1360 rowsCount = rowArray.length;
1362 for (; rowIndex < rowsCount; ++rowIndex)
1364 var row = rowArray[rowIndex],
1365 control = _disclosureControlsForRows[row];
1370 [control removeFromSuperview];
1372 [
self _enqueueDisclosureControl:control];
1374 _disclosureControlsForRows[row] = nil;
1381 - (void)_toggleFromDisclosureControl:(
CPControl)aControl
1383 var controlFrame = [aControl frame],
1384 item = [
self itemAtRow:[
self rowAtPoint:CGPointMake(CGRectGetMinX(controlFrame), CGRectGetMidY(controlFrame))]];
1386 if ([
self isItemExpanded:item])
1387 [
self collapseItem:item];
1390 [
self expandItem:item expandChildren:([[CPApp currentEvent] modifierFlags] & CPAlternateKeyMask)];
1396 - (void)_enqueueDisclosureControl:(
CPControl)aControl
1398 _disclosureControlQueue.push(aControl);
1406 if (_disclosureControlQueue.length)
1407 return _disclosureControlQueue.pop();
1409 if (!_disclosureControlData)
1410 if (!_disclosureControlPrototype)
1417 [disclosureControl setTarget:self];
1418 [disclosureControl setAction:@selector(_toggleFromDisclosureControl:)];
1420 return disclosureControl;
1426 - (void)_noteSelectionIsChanging
1443 - (void)_noteSelectionDidChange
1445 if (!_coalesceSelectionNotificationState)
1460 - (void)_noteItemWillExpand:(
id)item
1471 - (void)_noteItemDidExpand:(
id)item
1482 - (void)_noteItemWillCollapse:(
id)item
1493 - (void)_noteItemDidCollapse:(
id)item
1503 var character = [anEvent charactersIgnoringModifiers],
1504 modifierFlags = [anEvent modifierFlags];
1510 return [
super keyDown:anEvent];
1512 var rows = [
self selectedRowIndexes],
1516 [rows getIndexes:indexes maxCount:-1 inIndexRange:nil];
1519 c = [indexes count];
1522 items.push([
self itemAtRow:indexes[i]]);
1526 for (var i = 0; i < c; i++)
1527 [
self expandItem:items[i]];
1535 var theItem = items[0];
1536 if (![
self isItemExpanded:theItem])
1544 [
self scrollRowToVisible:rowIndex];
1550 for (var i = 0; i < c; i++)
1551 [
self collapseItem:items[i]];
1554 [
super keyDown:anEvent];
1559 return [_outlineViewDelegate outlineView:self viewForTableColumn:aTableColumn item:[
self itemAtRow:aRow]];
1562 - (
CPView)_sendDelegateDataViewForTableColumn:(
CPTableColumn)aTableColumn row:(CPInteger)aRow
1564 return [_outlineViewDelegate outlineView:self dataViewForTableColumn:aTableColumn item:[
self itemAtRow:aRow]];
1567 - (BOOL)_dataSourceRespondsToObjectValueForTableColumn
1572 - (BOOL)_delegateRespondsToViewForTableColumn
1577 - (BOOL)_delegateRespondsToDataViewForTableColumn
1582 - (BOOL)_delegateRespondsToShouldExpandItem
1587 - (BOOL)_delegateRespondsToShouldCollapseItem
1596 - (BOOL)_delegateRespondsToSelectionIndexesForProposedSelection
1605 - (BOOL)_delegateRespondsToShouldSelectRow
1613 var _reloadItem =
function( anOutlineView, anItem)
1618 with (anOutlineView)
1621 var itemInfosForItems = _itemInfosForItems,
1622 dataSource = _outlineViewDataSource,
1623 itemUID = [anItem UID],
1624 itemInfo = itemInfosForItems[itemUID];
1631 var parent = itemInfo.parent,
1632 parentItemInfo = parent ? itemInfosForItems[[parent UID]] : _rootItemInfo,
1633 parentChildren = parentItemInfo.children,
1634 index = [parentChildren indexOfObjectIdenticalTo:anItem],
1635 newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent];
1637 if (anItem !== newItem)
1639 itemInfosForItems[[anItem UID]] = nil;
1640 itemInfosForItems[[newItem UID]] = itemInfo;
1642 parentChildren[index] = newItem;
1643 _itemsForRows[itemInfo.row] = newItem;
1646 itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
1647 itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded;
1653 var _loadItemInfoForItem =
function( anOutlineView, anItem, isIntermediate)
1655 with (anOutlineView)
1657 var itemInfosForItems = _itemInfosForItems,
1658 dataSource = _outlineViewDataSource;
1661 var itemInfo = _rootItemInfo;
1666 var itemUID = [anItem UID],
1667 itemInfo = itemInfosForItems[itemUID];
1673 itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem];
1678 if (!itemInfo.isExpandable && itemInfo.isExpanded)
1680 itemInfo.isExpanded = NO;
1681 itemInfo.children = [];
1686 var weight = itemInfo.weight,
1687 descendants = anItem ? [anItem] : [];
1690 ![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem]))
1693 count = [dataSource outlineView:anOutlineView numberOfChildrenOfItem:anItem],
1694 level = itemInfo.level + 1;
1696 itemInfo.children = [];
1698 for (; index < count; ++index)
1700 var childItem = [dataSource outlineView:anOutlineView child:index ofItem:anItem],
1701 childItemInfo = itemInfosForItems[[childItem UID]];
1705 childItemInfo = { isExpanded:NO, isExpandable:NO, shouldShowOutlineDisclosureControl:YES, children:[], weight:1 };
1706 itemInfosForItems[[childItem UID]] = childItemInfo;
1709 itemInfo.children[index] = childItem;
1711 var childDescendants = _loadItemInfoForItem(anOutlineView, childItem, YES);
1713 childItemInfo.parent = anItem;
1714 childItemInfo.level = level;
1715 descendants = descendants.concat(childDescendants);
1719 itemInfo.weight = descendants.length;
1721 if (!isIntermediate)
1724 var index = MAX(itemInfo.row, 0),
1725 itemsForRows = _itemsForRows;
1727 descendants.unshift(index, weight);
1729 itemsForRows.splice.apply(itemsForRows, descendants);
1731 var count = itemsForRows.length;
1733 for (; index < count; ++index)
1734 itemInfosForItems[[itemsForRows[index] UID]].row = index;
1736 var deltaWeight = itemInfo.weight - weight;
1738 if (deltaWeight !== 0)
1740 var parent = itemInfo.parent;
1744 var parentItemInfo = itemInfosForItems[[parent UID]];
1746 parentItemInfo.weight += deltaWeight;
1747 parent = parentItemInfo.parent;
1751 _rootItemInfo.weight += deltaWeight;
1758 @implementation _CPOutlineViewTableViewDataSource :
CPObject
1765 self = [
super init];
1768 _outlineView = anOutlineView;
1773 - (CPInteger)numberOfRowsInTableView:(
CPTableView)anOutlineView
1775 return _outlineView._itemsForRows.length;
1780 return [_outlineView._outlineViewDataSource outlineView:_outlineView objectValueForTableColumn:aTableColumn byItem:_outlineView._itemsForRows[aRow]];
1783 - (void)tableView:(
CPTableView)aTableView setObjectValue:(
id)aValue forTableColumn:(
CPTableColumn)aColumn row:(CPInteger)aRow
1787 [_outlineView._outlineViewDataSource outlineView:_outlineView setObjectValue:aValue forTableColumn:aColumn byItem:_outlineView._itemsForRows[aRow]];
1796 index = [theIndexes firstIndex];
1800 [items addObject:[_outlineView itemAtRow:index]]
1804 return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard];
1807 - (int)_childIndexForDropOperation:(CPTableViewDropOperation)theDropOperation row:(CPInteger)theRow offset:(CGPoint)theOffset
1809 if (_outlineView._shouldRetargetChildIndex)
1810 return _outlineView._retargedChildIndex;
1814 if (theDropOperation === CPTableViewDropAbove)
1816 var parentItem = [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset],
1817 itemInfo = (parentItem !== nil) ? _outlineView._itemInfosForItems[[parentItem UID]] : _outlineView._rootItemInfo,
1818 children = itemInfo.children;
1820 childIndex = [children indexOfObject:[_outlineView itemAtRow:theRow]];
1823 childIndex = children.length;
1825 else if (theDropOperation === CPTableViewDropOn)
1831 - (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(CPInteger)theRow offset:(CGPoint)theOffset
1833 if (theDropOperation === CPTableViewDropAbove)
1834 return [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset]
1836 return [_outlineView itemAtRow:theRow];
1839 - (CPDragOperation)tableView:(
CPTableView)aTableView validateDrop:(
id )theInfo
1840 proposedRow:(CPInteger)theRow proposedDropOperation:(CPTableViewDropOperation)theOperation
1846 _outlineView._retargetedItem = nil;
1847 _outlineView._shouldRetargetItem = NO;
1849 _outlineView._retargedChildIndex = nil;
1850 _outlineView._shouldRetargetChildIndex = NO;
1852 var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
1853 parentItem = [
self _parentItemForDropOperation:theOperation row:theRow offset:location],
1854 childIndex = [
self _childIndexForDropOperation:theOperation row:theRow offset:location];
1856 return [_outlineView._outlineViewDataSource outlineView:_outlineView validateDrop:theInfo proposedItem:parentItem proposedChildIndex:childIndex];
1859 - (BOOL)tableView:(
CPTableView)aTableView acceptDrop:(
id )theInfo row:(CPInteger)theRow dropOperation:(CPTableViewDropOperation)theOperation
1864 var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
1865 parentItem = [
self _parentItemForDropOperation:theOperation row:theRow offset:location],
1866 childIndex = [
self _childIndexForDropOperation:theOperation row:theRow offset:location];
1868 _outlineView._retargetedItem = nil;
1869 _outlineView._shouldRetargetItem = NO;
1871 _outlineView._retargedChildIndex = nil;
1872 _outlineView._shouldRetargetChildIndex = NO;
1874 return [_outlineView._outlineViewDataSource outlineView:_outlineView acceptDrop:theInfo item:parentItem childIndex:childIndex];
1877 - (void)tableView:(
CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldSortDescriptors
1879 if ((_outlineView._implementedOutlineViewDataSourceMethods &
1882 [[_outlineView dataSource] outlineView:_outlineView sortDescriptorsDidChange:oldSortDescriptors];
1888 @implementation _CPOutlineViewTableViewDelegate :
CPObject
1895 self = [
super init];
1898 _outlineView = anOutlineView;
1903 - (BOOL)tableView:(
CPTableView)theTableView shouldSelectRow:(CPInteger)theRow
1908 - (BOOL)selectionShouldChangeInTableView:(
CPTableView)theTableView
1916 return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldEditTableColumn:aColumn item:[_outlineView itemAtRow:aRow]];
1921 - (float)tableView:(
CPTableView)theTableView heightOfRow:(CPInteger)theRow
1924 return [_outlineView._outlineViewDelegate outlineView:_outlineView heightOfRowByItem:[_outlineView itemAtRow:theRow]];
1926 return [theTableView rowHeight];
1929 - (void)tableView:(
CPTableView)aTableView willDisplayView:(
id)aView forTableColumn:(
CPTableColumn)aTableColumn row:(CPInteger)aRowIndex
1933 var item = [_outlineView itemAtRow:aRowIndex];
1934 [_outlineView._outlineViewDelegate outlineView:_outlineView willDisplayView:aView forTableColumn:aTableColumn item:item];
1938 - (BOOL)tableView:(
CPTableView)aTableView isGroupRow:(CPInteger)aRow
1941 return [_outlineView._outlineViewDelegate outlineView:_outlineView isGroupItem:[_outlineView itemAtRow:aRow]];
1950 var item = [_outlineView itemAtRow:aRow];
1951 return [_outlineView._outlineViewDelegate outlineView:_outlineView menuForTableColumn:aTableColumn item:item]
1956 return [_outlineView menu] || [[_outlineView class] defaultMenu];
1962 return [_outlineView._outlineViewDelegate outlineView:_outlineView selectionIndexesForProposedSelection:anIndexSet];
1970 return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectTableColumn:aTableColumn];
1982 - (id)initWithFrame:(CGRect)aFrame
1992 - (void)setState:(CPInteger)aState
2003 - (void)drawRect:(CGRect)aRect
2005 var bounds = [
self bounds],
2007 width = CGRectGetWidth(bounds),
2008 height = CGRectGetHeight(bounds);
2014 var centre = CGPointMake(FLOOR(
width / 2.0), FLOOR(height / 2.0));
2030 [
self hasThemeState:CPThemeStateHighlighted]));
2061 _rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 };
2064 _itemInfosForItems = { };
2065 _disclosureControlsForRows = [];
2070 _outlineTableColumn = [aCoder decodeObjectForKey:CPOutlineViewOutlineTableColumnKey];
2071 _indentationPerLevel = [aCoder decodeFloatForKey:CPOutlineViewIndentationPerLevelKey];
2073 _outlineViewDataSource = [aCoder decodeObjectForKey:CPOutlineViewDataSourceKey];
2074 _outlineViewDelegate = [aCoder decodeObjectForKey:CPOutlineViewDelegateKey];
2076 [
super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
2077 [
super setDelegate:[[_CPOutlineViewTableViewDelegate alloc] initWithOutlineView:self]];
2079 [
self _updateIsViewBased];
2088 var internalDelegate = _delegate,
2089 internalDataSource = _dataSource;
2093 _delegate = internalDelegate;
2094 _dataSource = internalDataSource;
2096 [aCoder encodeObject:_outlineTableColumn forKey:CPOutlineViewOutlineTableColumnKey];
2097 [aCoder encodeFloat:_indentationPerLevel forKey:CPOutlineViewIndentationPerLevelKey];
2099 [aCoder encodeObject:_outlineViewDataSource forKey:CPOutlineViewDataSourceKey];
2100 [aCoder encodeObject:_outlineViewDelegate forKey:CPOutlineViewDelegateKey];
2113 ? [
CPColor colorWithCalibratedWhite:0.4 alpha: 1.0]
2114 : [
CPColor colorWithCalibratedWhite:0.5 alpha: 1.0]);