00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import "CPTableColumn.j"
00024 @import "CPTableView.j"
00025
00026 #include "CoreGraphics/CGGeometry.h"
00027
00028
00029 CPOutlineViewColumnDidMoveNotification = @"CPOutlineViewColumnDidMoveNotification";
00030 CPOutlineViewColumnDidResizeNotification = @"CPOutlineViewColumnDidResizeNotification";
00031 CPOutlineViewItemDidCollapseNotification = @"CPOutlineViewItemDidCollapseNotification";
00032 CPOutlineViewItemDidExpandNotification = @"CPOutlineViewItemDidExpandNotification";
00033 CPOutlineViewItemWillCollapseNotification = @"CPOutlineViewItemWillCollapseNotification";
00034 CPOutlineViewItemWillExpandNotification = @"CPOutlineViewItemWillExpandNotification";
00035 CPOutlineViewSelectionDidChangeNotification = @"CPOutlineViewSelectionDidChangeNotification";
00036 CPOutlineViewSelectionIsChangingNotification = @"CPOutlineViewSelectionIsChangingNotification";
00037
00038 var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_ = 1 << 1,
00039 CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_ = 1 << 2,
00040
00041 CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_ = 1 << 3,
00042 CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_ = 1 << 4,
00043 CPOutlineViewDataSource_outlineView_validateDrop_proposedRow_proposedDropOperation_ = 1 << 5,
00044 CPOutlineViewDataSource_outlineView_namesOfPromisedFilesDroppedAtDestination_forDraggedItems_ = 1 << 6,
00045
00046 CPOutlineViewDataSource_outlineView_itemForPersistentObject_ = 1 << 7,
00047 CPOutlineViewDataSource_outlineView_persistentObjectForItem_ = 1 << 8,
00048
00049 CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_ = 1 << 9,
00050
00051 CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 10;
00052
00053
00054 var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ = 1 << 1,
00055 CPOutlineViewDelegate_outlineView_shouldSelectItem_ = 1 << 2,
00056 CPOutlineViewDelegate_outlineView_heightOfRowByItem_ = 1 << 3,
00057 CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 4,
00058 CPOutlineViewDelegate_outlineView_isGroupItem_ = 1 << 5;
00059
00060 CPOutlineViewDropOnItemIndex = -1;
00061
00062 @implementation CPOutlineView : CPTableView
00063 {
00064 id _outlineViewDataSource;
00065 id _outlineViewDelegate;
00066 CPTableColumn _outlineTableColumn;
00067
00068 float _indentationPerLevel;
00069 BOOL _indentationMarkerFollowsDataView;
00070
00071 CPInteger _implementedOutlineViewDataSourceMethods;
00072 CPInteger _implementedOutlineViewDelegateMethods;
00073
00074 Object _rootItemInfo;
00075 CPMutableArray _itemsForRows;
00076 Object _itemInfosForItems;
00077
00078 CPControl _disclosureControlPrototype;
00079 CPArray _disclosureControlsForRows;
00080 CPData _disclosureControlData;
00081 CPArray _disclosureControlQueue;
00082
00083 BOOL _shouldRetargetItem;
00084 id _retargetedItem;
00085
00086 BOOL _shouldRetargetChildIndex;
00087 CPInteger _retargedChildIndex;
00088 }
00089
00090 - (id)initWithFrame:(CGRect)aFrame
00091 {
00092 self = [super initWithFrame:aFrame];
00093
00094 if (self)
00095 {
00096
00097 _selectionHighlightStyle = CPTableViewSelectionHighlightStyleSourceList;
00098
00099
00100 _rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 };
00101
00102 _itemsForRows = [];
00103 _itemInfosForItems = { };
00104 _disclosureControlsForRows = [];
00105
00106 _retargetedItem = nil;
00107 _shouldRetargetItem = NO;
00108
00109 _retargedChildIndex = nil;
00110 _shouldRetargetChildIndex = NO;
00111
00112 [self setIndentationPerLevel:16.0];
00113 [self setIndentationMarkerFollowsDataView:YES];
00114
00115 [super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
00116 [super setDelegate:[[_CPOutlineViewTableViewDelegate alloc] initWithOutlineView:self]];
00117
00118 [self setDisclosureControlPrototype:[[CPDisclosureButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)]];
00119 }
00120
00121 return self;
00122 }
00123
00124 - (void)setDataSource:(id)aDataSource
00125 {
00126 if (_outlineViewDataSource === aDataSource)
00127 return;
00128
00129 if (![aDataSource respondsToSelector:@selector(outlineView:child:ofItem:)])
00130 [CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:child:ofItem:'"];
00131
00132 if (![aDataSource respondsToSelector:@selector(outlineView:isItemExpandable:)])
00133 [CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:isItemExpandable:'"];
00134
00135 if (![aDataSource respondsToSelector:@selector(outlineView:numberOfChildrenOfItem:)])
00136 [CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:numberOfChildrenOfItem:'"];
00137
00138 if (![aDataSource respondsToSelector:@selector(outlineView:objectValueForTableColumn:byItem:)])
00139 [CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:objectValueForTableColumn:byItem:'"];
00140
00141 _outlineViewDataSource = aDataSource;
00142 _implementedOutlineViewDataSourceMethods = 0;
00143
00144 if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:setObjectValue:forTableColumn:byItem:)])
00145 _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_;
00146
00147 if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:shouldDeferDisplayingChildrenOfItem:)])
00148 _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_;
00149
00150 if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:acceptDrop:item:childIndex:)])
00151 _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_;
00152
00153 if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:validateDrop:proposedItem:proposedChildIndex:)])
00154 _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_;
00155
00156 if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:validateDrop:proposedRow:proposedDropOperation:)])
00157 _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_validateDrop_proposedRow_proposedDropOperation_;
00158
00159 if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:namesOfPromisedFilesDroppedAtDestination:forDraggedItems:)])
00160 _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_namesOfPromisedFilesDroppedAtDestination_forDraggedItems_;
00161
00162 if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:itemForPersistentObject:)])
00163 _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_itemForPersistentObject_;
00164
00165 if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:persistentObjectForItem:)])
00166 _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_persistentObjectForItem_;
00167
00168 if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:writeItems:toPasteboard:)])
00169 _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_;
00170
00171 if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:sortDescriptorsDidChange:)])
00172 _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_;
00173
00174 [self reloadData];
00175 }
00176
00177 - (id)dataSource
00178 {
00179 return _outlineViewDataSource;
00180 }
00181
00182 - (BOOL)isExpandable:(id)anItem
00183 {
00184 if (!anItem)
00185 return YES;
00186
00187 var itemInfo = _itemInfosForItems[[anItem UID]];
00188
00189 if (!itemInfo)
00190 return NO;
00191
00192 return itemInfo.isExpandable;
00193 }
00194
00195 - (void)isItemExpanded:(id)anItem
00196 {
00197 if (!anItem)
00198 return YES;
00199
00200 var itemInfo = _itemInfosForItems[[anItem UID]];
00201
00202 if (!itemInfo)
00203 return NO;
00204
00205 return itemInfo.isExpanded;
00206 }
00207
00208 - (void)expandItem:(id)anItem
00209 {
00210 [self expandItem:anItem expandChildren:NO];
00211 }
00212
00213 - (void)expandItem:(id)anItem expandChildren:(BOOL)shouldExpandChildren
00214 {
00215 var itemInfo = null;
00216
00217 if (!anItem)
00218 itemInfo = _rootItemInfo;
00219 else
00220 itemInfo = _itemInfosForItems[[anItem UID]];
00221
00222 if (!itemInfo)
00223 return;
00224
00225 itemInfo.isExpanded = YES;
00226 [self reloadItem:anItem reloadChildren:YES];
00227
00228 if (shouldExpandChildren)
00229 {
00230 var children = itemInfo.children,
00231 childIndex = children.length;
00232
00233 while (childIndex--)
00234 [self expandItem:children[childIndex] expandChildren:YES];
00235 }
00236 }
00237
00238 - (void)collapseItem:(id)anItem
00239 {
00240 if (!anItem)
00241 return;
00242
00243 var itemInfo = _itemInfosForItems[[anItem UID]];
00244
00245 if (!itemInfo)
00246 return;
00247
00248 if (!itemInfo.isExpanded)
00249 return;
00250
00251 itemInfo.isExpanded = NO;
00252
00253 [self reloadItem:anItem reloadChildren:YES];
00254 }
00255
00256 - (void)reloadItem:(id)anItem
00257 {
00258 [self reloadItem:anItem reloadChildren:NO];
00259 }
00260
00261 - (void)reloadItem:(id)anItem reloadChildren:(BOOL)shouldReloadChildren
00262 {
00263 if (!!shouldReloadChildren || !anItem)
00264 _loadItemInfoForItem(self, anItem);
00265 else
00266 _reloadItem(self, anItem);
00267
00268 [super reloadData];
00269 }
00270
00271 - (id)itemAtRow:(CPInteger)aRow
00272 {
00273 return _itemsForRows[aRow] || nil;
00274 }
00275
00276 - (CPInteger)rowForItem:(id)anItem
00277 {
00278 if (!anItem)
00279 return _rootItemInfo.row;
00280
00281 var itemInfo = _itemInfosForItems[[anItem UID]];
00282
00283 if (!itemInfo)
00284 return CPNotFound;
00285
00286 return itemInfo.row;
00287 }
00288
00289 - (void)setOutlineTableColumn:(CPTableColumn)aTableColumn
00290 {
00291 if (_outlineTableColumn === aTableColumn)
00292 return;
00293
00294 _outlineTableColumn = aTableColumn;
00295
00296
00297 [self reloadData];
00298 }
00299
00300 - (CPTableColumn)outlineTableColumn
00301 {
00302 return _outlineTableColumn;
00303 }
00304
00305 - (CPInteger)levelForItem:(id)anItem
00306 {
00307 if (!anItem)
00308 return _rootItemInfo.level;
00309
00310 var itemInfo = _itemInfosForItems[[anItem UID]];
00311
00312 if (!itemInfo)
00313 return CPNotFound;
00314
00315 return itemInfo.level;
00316 }
00317
00318 - (CPInteger)levelForRow:(CPInteger)aRow
00319 {
00320 return [self levelForItem:[self itemAtRow:aRow]];
00321 }
00322
00323 - (void)setIndentationPerLevel:(float)anIndentationWidth
00324 {
00325 if (_indentationPerLevel === anIndentationWidth)
00326 return;
00327
00328 _indentationPerLevel = anIndentationWidth;
00329
00330
00331 [self reloadData];
00332 }
00333
00334 - (float)indentationPerLevel
00335 {
00336 return _indentationPerLevel;
00337 }
00338
00339 - (void)setIndentationMarkerFollowsDataView:(BOOL)indentationMarkerShouldFollowDataView
00340 {
00341 if (_indentationMarkerFollowsDataView === indentationMarkerShouldFollowDataView)
00342 return;
00343
00344 _indentationMarkerFollowsDataView = indentationMarkerShouldFollowDataView;
00345
00346
00347 [self reloadData];
00348 }
00349
00350 - (BOOL)indentationMarkerFollowsDataView
00351 {
00352 return _indentationMarkerFollowsDataView;
00353 }
00354
00355 - (id)parentForItem:(id)anItem
00356 {
00357 if (!anItem)
00358 return nil;
00359
00360 var itemInfo = _itemInfosForItems[[anItem UID]];
00361
00362 if (!itemInfo)
00363 return nil;
00364
00365 var parent = itemInfo.parent;
00366
00367
00368 if (itemInfo[[parent UID]] === _rootItemInfo)
00369 parent = nil;
00370
00371 return parent;
00372 }
00373
00374 - (CGRect)frameOfOutlineDataViewAtColumn:(CPInteger)aColumn row:(CPInteger)aRow
00375 {
00376 var frame = [super frameOfDataViewAtColumn:aColumn row:aRow],
00377 indentationWidth = ([self levelForRow:aRow] + 1) * [self indentationPerLevel];
00378
00379 frame.origin.x += indentationWidth;
00380 frame.size.width -= indentationWidth;
00381
00382 return frame;
00383 }
00384
00385 - (void)selectRowIndexes:(CPIndexSet)rows byExtendingSelection:(BOOL)shouldExtendSelection
00386 {
00387
00388 var previousSelectedRows = [];
00389 [[self selectedRowIndexes] getIndexes:previousSelectedRows maxCount:-1 inIndexRange:nil];
00390
00391 var index = [previousSelectedRows count];
00392 while (index--)
00393 {
00394 var rowIndex = previousSelectedRows[index],
00395 item = [self itemAtRow:rowIndex];
00396
00397 if (![self isExpandable:item])
00398 continue;
00399
00400 var control = _disclosureControlsForRows[rowIndex];
00401 [control setHighlighted:NO];
00402 }
00403
00404 [super selectRowIndexes:rows byExtendingSelection:shouldExtendSelection];
00405
00406
00407 var selectedRows = [];
00408 [rows getIndexes:selectedRows maxCount:-1 inIndexRange:nil];
00409
00410 var index = [selectedRows count];
00411 while (index--)
00412 {
00413 var rowIndex = selectedRows[index],
00414 item = [self itemAtRow:rowIndex];
00415
00416 if (![self isExpandable:item])
00417 continue;
00418
00419 var control = _disclosureControlsForRows[rowIndex];
00420 [control setHighlighted:YES];
00421 }
00422 }
00423
00424 - (void)setDelegate:(id)aDelegate
00425 {
00426 if (_outlineViewDelegate === aDelegate)
00427 return;
00428
00429 var defaultCenter = [CPNotificationCenter defaultCenter];
00430
00431 if (_outlineViewDelegate)
00432 {
00433 if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)])
00434 [defaultCenter
00435 removeObserver:_outlineViewDelegate
00436 name:CPOutlineViewColumnDidMoveNotification
00437 object:self];
00438
00439 if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidResize:)])
00440 [defaultCenter
00441 removeObserver:_outlineViewDelegate
00442 name:CPOutlineViewColumnDidResizeNotification
00443 object:self];
00444
00445 if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewSelectionDidChange:)])
00446 [defaultCenter
00447 removeObserver:_outlineViewDelegate
00448 name:CPOutlineViewSelectionDidChangeNotification
00449 object:self];
00450
00451 if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewSelectionIsChanging:)])
00452 [defaultCenter
00453 removeObserver:_outlineViewDelegate
00454 name:CPOutlineViewSelectionIsChangingNotification
00455 object:self];
00456 }
00457
00458 _outlineViewDelegate = aDelegate;
00459 _implementedOutlineViewDelegateMethods = 0;
00460
00461 if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:dataViewForTableColumn:item:)])
00462 _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_;
00463
00464 if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:shouldSelectItem:)])
00465 _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_shouldSelectItem_;
00466
00467 if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:heightOfRowByItem:)])
00468 _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_heightOfRowByItem_;
00469
00470 if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:willDisplayView:forTableColumn:item:)])
00471 _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_;
00472
00473 if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:isGroupItem:)])
00474 _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_isGroupItem_;
00475
00476 if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)])
00477 [defaultCenter
00478 addObserver:_outlineViewDelegate
00479 selector:@selector(outlineViewColumnDidMove:)
00480 name:CPOutlineViewColumnDidMoveNotification
00481 object:self];
00482
00483 if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidResize:)])
00484 [defaultCenter
00485 addObserver:_outlineViewDelegate
00486 selector:@selector(outlineViewColumnDidMove:)
00487 name:CPOutlineViewColumnDidResizeNotification
00488 object:self];
00489
00490 if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewSelectionDidChange:)])
00491 [defaultCenter
00492 addObserver:_outlineViewDelegate
00493 selector:@selector(outlineViewSelectionDidChange:)
00494 name:CPOutlineViewSelectionDidChangeNotification
00495 object:self];
00496
00497 if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewSelectionIsChanging:)])
00498 [defaultCenter
00499 addObserver:_outlineViewDelegate
00500 selector:@selector(outlineViewSelectionIsChanging:)
00501 name:CPOutlineViewSelectionIsChangingNotification
00502 object:self];
00503 }
00504
00505 - (id)delegate
00506 {
00507 return _outlineViewDelegate;
00508 }
00509
00510 - (void)setDisclosureControlPrototype:(CPControl)aControl
00511 {
00512 _disclosureControlPrototype = aControl;
00513 _disclosureControlData = nil;
00514 _disclosureControlQueue = [];
00515
00516
00517 [self reloadData];
00518 }
00519
00520 - (void)reloadData
00521 {
00522 [self reloadItem:nil reloadChildren:YES];
00523 }
00524
00525 - (CGRect)frameOfDataViewAtColumn:(CPInteger)aColumn row:(CPInteger)aRow
00526 {
00527 var tableColumn = [self tableColumns][aColumn];
00528
00529 if (tableColumn === _outlineTableColumn)
00530 return [self frameOfOutlineDataViewAtColumn:aColumn row:aRow];
00531
00532 return [super frameOfDataViewAtColumn:aColumn row:aRow];
00533 }
00534
00535 - (void)setDropItem:(id)theItem dropChildIndex:(int)theIndex
00536 {
00537 _retargetedItem = theItem;
00538 _shouldRetargetItem = YES;
00539
00540 _retargedChildIndex = theIndex;
00541 _shouldRetargetChildIndex = YES;
00542 }
00543
00544 - (id)_parentItemForUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex atMouseOffset:(CPPoint)theOffset
00545 {
00546 if (_shouldRetargetItem)
00547 return _retargetedItem;
00548
00549 var lowerLevel = [self levelForRow:theLowerRowIndex]
00550 upperItem = [self itemAtRow:theUpperRowIndex];
00551 upperLevel = [self levelForItem:upperItem];
00552
00553
00554
00555
00556 while (upperLevel > lowerLevel)
00557 {
00558 upperLevel = [self levelForItem:upperItem];
00559
00560
00561 if (theOffset.x > (upperLevel + 1) * [self indentationPerLevel])
00562 return [self parentForItem:upperItem];
00563
00564
00565 upperItem = [self parentForItem:upperItem];
00566 }
00567
00568 return [self parentForItem:[self itemAtRow:theLowerRowIndex]];
00569 }
00570
00571 - (CPRect)_rectForDropHighlightViewBetweenUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex offset:(CPPoint)theOffset
00572 {
00573
00574 var rect = [super _rectForDropHighlightViewBetweenUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex offset:theOffset],
00575 parentItem = [self _parentItemForUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex atMouseOffset:theOffset],
00576 level = [self levelForItem:parentItem];
00577
00578 rect.origin.x = (level + 1) * [self indentationPerLevel];
00579 rect.size.width -= rect.origin.x;
00580
00581 return rect;
00582 }
00583
00584 - (void)_loadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
00585 {
00586 [super _loadDataViewsInRows:rows columns:columns];
00587
00588 var outlineColumn = [[self tableColumns] indexOfObjectIdenticalTo:[self outlineTableColumn]];
00589
00590 if (![columns containsIndex:outlineColumn])
00591 return;
00592
00593 var rowArray = [];
00594
00595 [rows getIndexes:rowArray maxCount:-1 inIndexRange:nil];
00596
00597 var rowIndex = 0,
00598 rowsCount = rowArray.length;
00599
00600 for (; rowIndex < rowsCount; ++rowIndex)
00601 {
00602 var row = rowArray[rowIndex],
00603 item = _itemsForRows[row],
00604 isExpandable = [self isExpandable:item];
00605
00606 if (!isExpandable)
00607 continue;
00608
00609 var control = [self _dequeueDisclosureControl],
00610 frame = [control frame],
00611 dataViewFrame = [self frameOfDataViewAtColumn:outlineColumn row:row];
00612
00613 frame.origin.x = _indentationMarkerFollowsDataView ? _CGRectGetMinX(dataViewFrame) - _CGRectGetWidth(frame) : 0.0;
00614 frame.origin.y = _CGRectGetMinY(dataViewFrame);
00615 frame.size.height = _CGRectGetHeight(dataViewFrame);
00616
00617
00618
00619 _disclosureControlsForRows[row] = control;
00620
00621 [control setState:[self isItemExpanded:item] ? CPOnState : CPOffState];
00622 [control setFrame:frame];
00623
00624 [self addSubview:control];
00625 }
00626 }
00627
00628 - (void)_unloadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
00629 {
00630 [super _unloadDataViewsInRows:rows columns:columns];
00631
00632 var outlineColumn = [[self tableColumns] indexOfObjectIdenticalTo:[self outlineTableColumn]];
00633
00634 if (![columns containsIndex:outlineColumn])
00635 return;
00636
00637 var rowArray = [];
00638
00639 [rows getIndexes:rowArray maxCount:-1 inIndexRange:nil];
00640
00641 var rowIndex = 0,
00642 rowsCount = rowArray.length;
00643
00644 for (; rowIndex < rowsCount; ++rowIndex)
00645 {
00646 var row = rowArray[rowIndex],
00647 control = _disclosureControlsForRows[row];
00648
00649 if (!control)
00650 continue;
00651
00652 [control removeFromSuperview];
00653
00654 [self _enqueueDisclosureControl:control];
00655
00656 _disclosureControlsForRows[row] = nil;
00657 }
00658 }
00659
00660 - (void)_toggleFromDisclosureControl:(CPControl)aControl
00661 {
00662 var controlFrame = [aControl frame],
00663 item = [self itemAtRow:[self rowAtPoint:_CGPointMake(_CGRectGetMinX(controlFrame), _CGRectGetMidY(controlFrame))]];
00664
00665 if ([self isItemExpanded:item])
00666 [self collapseItem:item];
00667
00668 else
00669 [self expandItem:item];
00670 }
00671
00672 - (void)_enqueueDisclosureControl:(CPControl)aControl
00673 {
00674 _disclosureControlQueue.push(aControl);
00675 }
00676
00677 - (CPControl)_dequeueDisclosureControl
00678 {
00679 if (_disclosureControlQueue.length)
00680 return _disclosureControlQueue.pop();
00681
00682 if (!_disclosureControlData)
00683 if (!_disclosureControlPrototype)
00684 return nil;
00685 else
00686 _disclosureControlData = [CPKeyedArchiver archivedDataWithRootObject:_disclosureControlPrototype];
00687
00688 var disclosureControl = [CPKeyedUnarchiver unarchiveObjectWithData:_disclosureControlData];
00689
00690 [disclosureControl setTarget:self];
00691 [disclosureControl setAction:@selector(_toggleFromDisclosureControl:)];
00692
00693 return disclosureControl;
00694 }
00695
00696 - (void)_noteSelectionIsChanging
00697 {
00698 [[CPNotificationCenter defaultCenter]
00699 postNotificationName:CPOutlineViewSelectionIsChangingNotification
00700 object:self
00701 userInfo:nil];
00702 }
00703
00704 - (void)_noteSelectionDidChange
00705 {
00706 [[CPNotificationCenter defaultCenter]
00707 postNotificationName:CPOutlineViewSelectionDidChangeNotification
00708 object:self
00709 userInfo:nil];
00710 }
00711
00712 @end
00713
00714
00715 var _reloadItem = function( anOutlineView, anItem)
00716 {
00717 if (!anItem)
00718 return;
00719
00720 with(anOutlineView)
00721 {
00722
00723 var itemInfosForItems = _itemInfosForItems,
00724 dataSource = _outlineViewDataSource,
00725 itemUID = [anItem UID],
00726 itemInfo = itemInfosForItems[itemUID];
00727
00728
00729 if (!itemInfo)
00730 return [];
00731
00732
00733 var parent = itemInfo.parent,
00734 parentItemInfo = parent ? itemInfosForItems[[parent UID]] : _rootItemInfo,
00735 parentChildren = parentItemInfo.children,
00736 index = [parentChildren indexOfObjectIdenticalTo:anItem],
00737 newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent];
00738
00739 if (anItem !== newItem)
00740 {
00741 itemInfosForItems[[anItem UID]] = nil;
00742 itemInfosForItems[[newItem UID]] = itemInfo;
00743
00744 parentChildren[index] = newItem;
00745 _itemsForRows[itemInfo.row] = newItem;
00746 }
00747
00748 itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
00749 itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded;
00750 }
00751 }
00752
00753
00754 var _loadItemInfoForItem = function( anOutlineView, anItem, isIntermediate)
00755 {
00756 with(anOutlineView)
00757 {
00758 var itemInfosForItems = _itemInfosForItems,
00759 dataSource = _outlineViewDataSource;
00760
00761 if (!anItem)
00762 var itemInfo = _rootItemInfo;
00763
00764 else
00765 {
00766
00767 var itemUID = [anItem UID],
00768 itemInfo = itemInfosForItems[itemUID];
00769
00770
00771 if (!itemInfo)
00772 return [];
00773
00774 itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem];
00775
00776
00777
00778 if (!itemInfo.isExpandable && itemInfo.isExpanded)
00779 {
00780 itemInfo.isExpanded = NO;
00781 itemInfo.children = [];
00782 }
00783 }
00784
00785
00786 var weight = itemInfo.weight,
00787 descendants = anItem ? [anItem] : [];
00788
00789 if (itemInfo.isExpanded && (!(_implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) ||
00790 ![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem]))
00791 {
00792 var index = 0,
00793 count = [dataSource outlineView:anOutlineView numberOfChildrenOfItem:anItem],
00794 level = itemInfo.level + 1;
00795
00796 itemInfo.children = [];
00797
00798 for (; index < count; ++index)
00799 {
00800 var childItem = [dataSource outlineView:anOutlineView child:index ofItem:anItem],
00801 childItemInfo = itemInfosForItems[[childItem UID]];
00802
00803 if (!childItemInfo)
00804 {
00805 childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 };
00806 itemInfosForItems[[childItem UID]] = childItemInfo;
00807 }
00808
00809 itemInfo.children[index] = childItem;
00810
00811 var childDescendants = _loadItemInfoForItem(anOutlineView, childItem, YES);
00812
00813 childItemInfo.parent = anItem;
00814 childItemInfo.level = level;
00815 descendants = descendants.concat(childDescendants);
00816 }
00817 }
00818
00819 itemInfo.weight = descendants.length;
00820
00821 if (!isIntermediate)
00822 {
00823
00824 var index = MAX(itemInfo.row, 0),
00825 itemsForRows = _itemsForRows;
00826
00827 descendants.unshift(index, weight);
00828
00829 itemsForRows.splice.apply(itemsForRows, descendants);
00830
00831 var count = itemsForRows.length;
00832
00833 for (; index < count; ++index)
00834 itemInfosForItems[[itemsForRows[index] UID]].row = index;
00835
00836 var deltaWeight = itemInfo.weight - weight;
00837
00838 if (deltaWeight !== 0)
00839 {
00840 var parent = itemInfo.parent;
00841
00842 while (parent)
00843 {
00844 var parentItemInfo = itemInfosForItems[[parent UID]];
00845
00846 parentItemInfo.weight += deltaWeight;
00847 parent = parentItemInfo.parent;
00848 }
00849
00850 if (anItem)
00851 _rootItemInfo.weight += deltaWeight;
00852 }
00853 }
00854 }
00855 return descendants;
00856 }
00857
00858 @implementation _CPOutlineViewTableViewDataSource : CPObject
00859 {
00860 CPObject _outlineView;
00861 }
00862
00863 - (id)initWithOutlineView:(CPOutlineView)anOutlineView
00864 {
00865 self = [super init];
00866
00867 if (self)
00868 _outlineView = anOutlineView;
00869
00870 return self;
00871 }
00872
00873 - (CPInteger)numberOfRowsInTableView:(CPTableView)anOutlineView
00874 {
00875 return _outlineView._itemsForRows.length;
00876 }
00877
00878 - (id)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)aTableColumn row:(CPInteger)aRow
00879 {
00880 return [_outlineView._outlineViewDataSource outlineView:_outlineView objectValueForTableColumn:aTableColumn byItem:_outlineView._itemsForRows[aRow]];
00881 }
00882
00883 - (BOOL)tableView:(CPTableView)aTableColumn writeRowsWithIndexes:(CPIndexSet)theIndexes toPasteboard:(CPPasteboard)thePasteboard
00884 {
00885 if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_))
00886 return NO;
00887
00888 var rowIndexes = [];
00889 [theIndexes getIndexes:rowIndexes maxCount:[theIndexes count] inIndexRange:nil];
00890
00891 var rowIndex = [rowIndexes count],
00892 items = [];
00893
00894 while (rowIndex--)
00895 [items addObject:[_outlineView itemAtRow:[rowIndexes objectAtIndex:rowIndex]]];
00896
00897 return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard];
00898 }
00899
00900 - (int)_childIndexForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset
00901 {
00902 if (_outlineView._shouldRetargetChildIndex)
00903 return _outlineView._retargedChildIndex;
00904
00905 var childIndex = CPNotFound;
00906
00907 if (theDropOperation === CPTableViewDropAbove)
00908 {
00909 var parentItem = [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset],
00910 itemInfo = (parentItem !== nil) ? _outlineView._itemInfosForItems[[parentItem UID]] : _outlineView._rootItemInfo,
00911 children = itemInfo.children;
00912
00913 childIndex = [children indexOfObject:[_outlineView itemAtRow:theRow]];
00914
00915 if (childIndex === CPNotFound)
00916 childIndex = children.length;
00917 }
00918 else if (theDropOperation === CPTableViewDropOn)
00919 childIndex = -1;
00920
00921 return childIndex;
00922 }
00923
00924 - (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset
00925 {
00926 if (theDropOperation === CPTableViewDropAbove)
00927 return [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset]
00928
00929 return [_outlineView itemAtRow:theRow];
00930 }
00931
00932 - (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id < CPDraggingInfo >)theInfo
00933 proposedRow:(int)theRow proposedDropOperation:(CPTableViewDropOperation)theOperation
00934 {
00935 if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_))
00936 return CPDragOperationNone;
00937
00938
00939 _outlineView._retargetedItem = nil;
00940 _outlineView._shouldRetargetItem = NO;
00941
00942 _outlineView._retargedChildIndex = nil;
00943 _outlineView._shouldRetargetChildIndex = NO;
00944
00945 var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
00946 parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location];
00947 childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
00948
00949 return [_outlineView._outlineViewDataSource outlineView:_outlineView validateDrop:theInfo proposedItem:parentItem proposedChildIndex:childIndex];
00950 }
00951
00952 - (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id <CPDraggingInfo>)theInfo row:(int)theRow dropOperation:(CPTableViewDropOperation)theOperation
00953 {
00954 if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_))
00955 return NO;
00956
00957 var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
00958 parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location];
00959 childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
00960
00961 _outlineView._retargetedItem = nil;
00962 _outlineView._shouldRetargetItem = NO;
00963
00964 _outlineView._retargedChildIndex = nil;
00965 _outlineView._shouldRetargetChildIndex = NO;
00966
00967 return [_outlineView._outlineViewDataSource outlineView:_outlineView acceptDrop:theInfo item:parentItem childIndex:childIndex];
00968 }
00969
00970 @end
00971
00972 @implementation _CPOutlineViewTableViewDelegate : CPObject
00973 {
00974 CPOutlineView _outlineView;
00975 }
00976
00977 - (id)initWithOutlineView:(CPOutlineView)anOutlineView
00978 {
00979 self = [super init];
00980
00981 if (self)
00982 _outlineView = anOutlineView;
00983
00984 return self;
00985 }
00986
00987 - (CPView)tableView:(CPTableView)theTableView dataViewForTableColumn:(CPTableColumn)theTableColumn row:(int)theRow
00988 {
00989 var dataView = nil;
00990
00991 if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_))
00992 dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView
00993 dataViewForTableColumn:theTableColumn
00994 item:[_outlineView itemAtRow:theRow]];
00995
00996 if (!dataView)
00997 dataView = [theTableColumn dataViewForRow:theRow];
00998
00999 return dataView;
01000 }
01001
01002 - (BOOL)tableView:(CPTableView)theTableView shouldSelectRow:(int)theRow
01003 {
01004 if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_))
01005 return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectItem:[_outlineView itemAtRow:theRow]];
01006
01007 return YES;
01008 }
01009
01010 - (float)tableView:(CPTableView)theTableView heightOfRow:(int)theRow
01011 {
01012 if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_heightOfRowByItem_))
01013 return [_outlineView._outlineViewDelegate outlineView:_outlineView heightOfRowByItem:[_outlineView itemAtRow:theRow]];
01014
01015 return [theTableView rowHeight];
01016 }
01017
01018 - (void)tableView:(CPTableView)aTableView willDisplayView:(id)aView forTableColumn:(CPTableColumn)aTableColumn row:(int)aRowIndex
01019 {
01020 if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_))
01021 {
01022 var item = [_outlineView itemAtRow:aRowIndex];
01023 [_outlineView._outlineViewDelegate outlineView:_outlineView willDisplayView:aView forTableColumn:aTableColumn item:item];
01024 }
01025 }
01026
01027 - (BOOL)tableView:(CPTableView)aTableView isGroupRow:(int)row
01028 {
01029 if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_isGroupItem_))
01030 return [_outlineView._outlineViewDelegate outlineView:_outlineView isGroupItem:[_outlineView itemAtRow:theRow]];
01031
01032 return NO;
01033 }
01034
01035 @end
01036
01037 @implementation CPDisclosureButton : CPButton
01038 {
01039 float _angle;
01040 }
01041
01042 - (id)initWithFrame:(CGRect)aFrame
01043 {
01044 self = [super initWithFrame:aFrame];
01045
01046 if (self)
01047 [self setBordered:NO];
01048
01049 return self;
01050 }
01051
01052 - (void)setState:(CPState)aState
01053 {
01054 [super setState:aState];
01055
01056 if ([self state] === CPOnState)
01057 _angle = 0.0;
01058
01059 else
01060 _angle = -PI_2;
01061 }
01062
01063 - (void)drawRect:(CGRect)aRect
01064 {
01065 var bounds = [self bounds],
01066 context = [[CPGraphicsContext currentContext] graphicsPort];
01067
01068 CGContextBeginPath(context);
01069
01070 CGContextTranslateCTM(context, _CGRectGetWidth(bounds) / 2.0, _CGRectGetHeight(bounds) / 2.0);
01071 CGContextRotateCTM(context, _angle);
01072 CGContextTranslateCTM(context, -_CGRectGetWidth(bounds) / 2.0, -_CGRectGetHeight(bounds) / 2.0);
01073
01074
01075 CGContextTranslateCTM(context, FLOOR((_CGRectGetWidth(bounds) - 9.0) / 2.0), FLOOR((_CGRectGetHeight(bounds) - 8.0) / 2.0));
01076
01077 CGContextMoveToPoint(context, 0.0, 0.0);
01078 CGContextAddLineToPoint(context, 9.0, 0.0);
01079 CGContextAddLineToPoint(context, 4.5, 8.0);
01080 CGContextAddLineToPoint(context, 0.0, 0.0);
01081
01082 CGContextClosePath(context);
01083
01084 CGContextSetFillColor(context, [self isHighlighted] ? [CPColor whiteColor] : [CPColor grayColor]);
01085 CGContextFillPath(context);
01086 }
01087
01088 @end