00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import <Foundation/CPArray.j>
00024 @import <AppKit/CGGradient.j>
00025
00026 @import "CPControl.j"
00027 @import "CPTableColumn.j"
00028 @import "_CPCornerView.j"
00029 @import "CPScroller.j"
00030
00031
00032 CPTableViewColumnDidMoveNotification = @"CPTableViewColumnDidMoveNotification";
00033 CPTableViewColumnDidResizeNotification = @"CPTableViewColumnDidResizeNotification";
00034 CPTableViewSelectionDidChangeNotification = @"CPTableViewSelectionDidChangeNotification";
00035 CPTableViewSelectionIsChangingNotification = @"CPTableViewSelectionIsChangingNotification";
00036
00037 #include "CoreGraphics/CGGeometry.h"
00038
00039 var CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_ = 1 << 2,
00040
00041 CPTableViewDataSource_tableView_acceptDrop_row_dropOperation_ = 1 << 3,
00042 CPTableViewDataSource_tableView_namesOfPromisedFilesDroppedAtDestination_forDraggedRowsWithIndexes_ = 1 << 4,
00043 CPTableViewDataSource_tableView_validateDrop_proposedRow_proposedDropOperation_ = 1 << 5,
00044 CPTableViewDataSource_tableView_writeRowsWithIndexes_toPasteboard_ = 1 << 6,
00045
00046 CPTableViewDataSource_tableView_sortDescriptorsDidChange_ = 1 << 7;
00047
00048 var CPTableViewDelegate_selectionShouldChangeInTableView_ = 1 << 0,
00049 CPTableViewDelegate_tableView_dataViewForTableColumn_row_ = 1 << 1,
00050 CPTableViewDelegate_tableView_didClickTableColumn_ = 1 << 2,
00051 CPTableViewDelegate_tableView_didDragTableColumn_ = 1 << 3,
00052 CPTableViewDelegate_tableView_heightOfRow_ = 1 << 4,
00053 CPTableViewDelegate_tableView_isGroupRow_ = 1 << 5,
00054 CPTableViewDelegate_tableView_mouseDownInHeaderOfTableColumn_ = 1 << 6,
00055 CPTableViewDelegate_tableView_nextTypeSelectMatchFromRow_toRow_forString_ = 1 << 7,
00056 CPTableViewDelegate_tableView_selectionIndexesForProposedSelection_ = 1 << 8,
00057 CPTableViewDelegate_tableView_shouldEditTableColumn_row_ = 1 << 9,
00058 CPTableViewDelegate_tableView_shouldSelectRow_ = 1 << 10,
00059 CPTableViewDelegate_tableView_shouldSelectTableColumn_ = 1 << 11,
00060 CPTableViewDelegate_tableView_shouldShowViewExpansionForTableColumn_row_ = 1 << 12,
00061 CPTableViewDelegate_tableView_shouldTrackView_forTableColumn_row_ = 1 << 13,
00062 CPTableViewDelegate_tableView_shouldTypeSelectForEvent_withCurrentSearchString_ = 1 << 14,
00063 CPTableViewDelegate_tableView_toolTipForView_rect_tableColumn_row_mouseLocation_ = 1 << 15,
00064 CPTableViewDelegate_tableView_typeSelectStringForTableColumn_row_ = 1 << 16,
00065 CPTableViewDelegate_tableView_willDisplayView_forTableColumn_row_ = 1 << 17,
00066 CPTableViewDelegate_tableViewSelectionDidChange_ = 1 << 18,
00067 CPTableViewDelegate_tableViewSelectionIsChanging_ = 1 << 19;
00068
00069
00070 CPTableViewDraggingDestinationFeedbackStyleNone = -1;
00071 CPTableViewDraggingDestinationFeedbackStyleRegular = 0;
00072 CPTableViewDraggingDestinationFeedbackStyleSourceList = 1;
00073
00074
00075 CPTableViewDropOn = 0;
00076 CPTableViewDropAbove = 1;
00077
00078
00079
00080 CPTableViewSelectionHighlightStyleNone = -1;
00081 CPTableViewSelectionHighlightStyleRegular = 0;
00082 CPTableViewSelectionHighlightStyleSourceList = 1;
00083
00084 CPTableViewGridNone = 0;
00085 CPTableViewSolidVerticalGridLineMask = 1 << 0;
00086 CPTableViewSolidHorizontalGridLineMask = 1 << 1;
00087
00088 CPTableViewNoColumnAutoresizing = 0;
00089 CPTableViewUniformColumnAutoresizingStyle = 1;
00090 CPTableViewSequentialColumnAutoresizingStyle = 2;
00091 CPTableViewReverseSequentialColumnAutoresizingStyle = 3;
00092 CPTableViewLastColumnOnlyAutoresizingStyle = 4;
00093 CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
00094
00095
00096 #define NUMBER_OF_COLUMNS() (_tableColumns.length)
00097 #define UPDATE_COLUMN_RANGES_IF_NECESSARY() if (_dirtyTableColumnRangeIndex !== CPNotFound) [self _recalculateTableColumnRanges];
00098
00099 @implementation _CPTableDrawView : CPView
00100 {
00101 CPTableView _tableView;
00102 }
00103
00104 - (id)initWithTableView:(CPTableView)aTableView
00105 {
00106 self = [super init];
00107
00108 if (self)
00109 _tableView = aTableView;
00110
00111 return self;
00112 }
00113
00114 - (void)drawRect:(CGRect)aRect
00115 {
00116 var frame = [self frame],
00117 context = [[CPGraphicsContext currentContext] graphicsPort];
00118
00119 CGContextTranslateCTM(context, -_CGRectGetMinX(frame), -_CGRectGetMinY(frame));
00120
00121 [_tableView _drawRect:aRect];
00122 }
00123
00124 @end
00125
00135 @implementation CPTableView : CPControl
00136 {
00137 id _dataSource;
00138 CPInteger _implementedDataSourceMethods;
00139
00140 id _delegate;
00141 CPInteger _implementedDelegateMethods;
00142
00143 CPArray _tableColumns;
00144 CPArray _tableColumnRanges;
00145 CPInteger _dirtyTableColumnRangeIndex;
00146 CPInteger _numberOfHiddenColumns;
00147
00148 BOOL _reloadAllRows;
00149 Object _objectValues;
00150 CPIndexSet _exposedRows;
00151 CPIndexSet _exposedColumns;
00152
00153 Object _dataViewsForTableColumns;
00154 Object _cachedDataViews;
00155
00156
00157 BOOL _allowsColumnReordering;
00158 BOOL _allowsColumnResizing;
00159 BOOL _allowsColumnSelection;
00160 BOOL _allowsMultipleSelection;
00161 BOOL _allowsEmptySelection;
00162
00163 CPArray _sortDescriptors;
00164
00165 CGSize _intercellSpacing;
00166 float _rowHeight;
00167
00168 BOOL _usesAlternatingRowBackgroundColors;
00169 CPArray _alternatingRowBackgroundColors;
00170
00171 unsigned _selectionHighlightStyle;
00172 CPTableColumn _currentHighlightedTableColumn;
00173 unsigned _gridStyleMask;
00174 CPColor _gridColor;
00175
00176 unsigned _numberOfRows;
00177
00178
00179 CPTableHeaderView _headerView;
00180 _CPCornerView _cornerView;
00181
00182 CPIndexSet _selectedColumnIndexes;
00183 CPIndexSet _selectedRowIndexes;
00184 CPInteger _selectionAnchorRow;
00185 CPInteger _lastSelectedRow;
00186 CPIndexSet _previouslySelectedRowIndexes;
00187 CGPoint _startTrackingPoint;
00188 CPDate _startTrackingTimestamp;
00189 BOOL _trackingPointMovedOutOfClickSlop;
00190 CGPoint _editingCellIndex;
00191
00192 _CPTableDrawView _tableDrawView;
00193
00194 SEL _doubleAction;
00195 unsigned _columnAutoResizingStyle;
00196
00197 CGPoint _originalMouseDownPoint;
00198 BOOL _verticalMotionCanDrag;
00199 unsigned _destinationDragStyle;
00200 BOOL _isSelectingSession;
00201 CPIndexSet _draggedRowIndexes;
00202 _dropOperationDrawingView _dropOperationFeedbackView;
00203 CPDragOperation _dragOperationDefaultMask;
00204 int _retargetedDropRow;
00205 CPDragOperation _retargetedDropOperation;
00206
00207 BOOL _disableAutomaticResizing @accessors(property=disableAutomaticResizing);
00208 BOOL _lastColumnShouldSnap;
00209
00210 CPGradient _sourceListActiveGradient;
00211 CPColor _sourceListActiveTopLineColor;
00212 CPColor _sourceListActiveBottomLineColor;
00213
00214
00215
00216
00217
00218 }
00219
00220 - (id)initWithFrame:(CGRect)aFrame
00221 {
00222 self = [super initWithFrame:aFrame];
00223
00224 if (self)
00225 {
00226
00227 _allowsColumnReordering = YES;
00228 _allowsColumnResizing = YES;
00229 _allowsMultipleSelection = NO;
00230 _allowsEmptySelection = YES;
00231 _allowsColumnSelection = NO;
00232 _disableAutomaticResizing = NO;
00233 _tableViewFlags = 0;
00234
00235
00236 _selectionHighlightStyle = CPTableViewSelectionHighlightStyleRegular;
00237
00238 [self setUsesAlternatingRowBackgroundColors:NO];
00239 [self setAlternatingRowBackgroundColors:[[CPColor whiteColor], [CPColor colorWithHexString:@"f5f9fc"]]];
00240
00241 _tableColumns = [];
00242 _tableColumnRanges = [];
00243 _dirtyTableColumnRangeIndex = CPNotFound;
00244 _numberOfHiddenColumns = 0;
00245
00246 _objectValues = { };
00247 _dataViewsForTableColumns = { };
00248 _dataViews= [];
00249 _numberOfRows = 0;
00250 _exposedRows = [CPIndexSet indexSet];
00251 _exposedColumns = [CPIndexSet indexSet];
00252 _cachedDataViews = { };
00253 _intercellSpacing = _CGSizeMake(0.0, 0.0);
00254 _rowHeight = 23.0;
00255
00256 [self setGridColor:[CPColor colorWithHexString:@"dce0e2"]];
00257 [self setGridStyleMask:CPTableViewGridNone];
00258
00259 _headerView = [[CPTableHeaderView alloc] initWithFrame:CGRectMake(0, 0, [self bounds].size.width, _rowHeight)];
00260
00261 [_headerView setTableView:self];
00262
00263 _cornerView = [[_CPCornerView alloc] initWithFrame:CGRectMake(0, 0, [CPScroller scrollerWidth], CGRectGetHeight([_headerView frame]))];
00264
00265 _lastSelectedRow = -1;
00266 _selectedColumnIndexes = [CPIndexSet indexSet];
00267 _selectedRowIndexes = [CPIndexSet indexSet];
00268 _currentHighlightedTableColumn = nil;
00269
00270 _sortDescriptors = [CPArray array];
00271
00272 _draggedRowIndexes = [CPIndexSet indexSet];
00273 _verticalMotionCanDrag = YES;
00274 _isSelectingSession = NO;
00275 _retargetedDropRow = nil;
00276 _retargetedDropOperation = nil;
00277 _dragOperationDefaultMask = nil;
00278 _destinationDragStyle = CPTableViewDraggingDestinationFeedbackStyleRegular;
00279
00280 _tableDrawView = [[_CPTableDrawView alloc] initWithTableView:self];
00281 [_tableDrawView setBackgroundColor:[CPColor clearColor]];
00282 [self addSubview:_tableDrawView];
00283 [self _init];
00284
00285 }
00286
00287 return self;
00288 }
00289
00290
00291 - (void)_init
00292 {
00293 _dropOperationFeedbackView = [[_dropOperationDrawingView alloc] initWithFrame:_CGRectMakeZero()];
00294 [_dropOperationFeedbackView setTableView:self];
00295
00296 _lastColumnShouldSnap = NO;
00297 _backgroundColor = [CPColor whiteColor];
00298
00299
00300 _sourceListActiveGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [89.0/255.0, 153.0/255.0, 209.0/255.0,1.0, 33.0/255.0, 94.0/255.0, 208.0/255.0,1.0], [0,1], 2);
00301 _sourceListActiveTopLineColor = [CPColor colorWithCalibratedRed:(61.0/255.0) green:(123.0/255.0) blue:(218.0/255.0) alpha:1.0];
00302 _sourceListActiveBottomLineColor = [CPColor colorWithCalibratedRed:(31.0/255.0) green:(92.0/255.0) blue:(207.0/255.0) alpha:1.0];
00303
00304
00305
00306
00307
00308
00309 }
00310
00315 - (void)setDataSource:(id)aDataSource
00316 {
00317 if (_dataSource === aDataSource)
00318 return;
00319
00320 _dataSource = aDataSource;
00321 _implementedDataSourceMethods = 0;
00322
00323 if (!_dataSource)
00324 return;
00325
00326 if (![_dataSource respondsToSelector:@selector(numberOfRowsInTableView:)])
00327 [CPException raise:CPInternalInconsistencyException
00328 reason:[aDataSource description] + " does not implement numberOfRowsInTableView:."];
00329
00330 if (![_dataSource respondsToSelector:@selector(tableView:objectValueForTableColumn:row:)])
00331 [CPException raise:CPInternalInconsistencyException
00332 reason:[aDataSource description] + " does not implement tableView:objectValueForTableColumn:row:"];
00333
00334 if ([_dataSource respondsToSelector:@selector(tableView:setObjectValue:forTableColumn:row:)])
00335 _implementedDataSourceMethods |= CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_;
00336
00337 if ([_dataSource respondsToSelector:@selector(tableView:acceptDrop:row:dropOperation:)])
00338 _implementedDataSourceMethods |= CPTableViewDataSource_tableView_acceptDrop_row_dropOperation_;
00339
00340 if ([_dataSource respondsToSelector:@selector(tableView:namesOfPromisedFilesDroppedAtDestination:forDraggedRowsWithIndexes:)])
00341 _implementedDataSourceMethods |= CPTableViewDataSource_tableView_namesOfPromisedFilesDroppedAtDestination_forDraggedRowsWithIndexes_;
00342
00343 if ([_dataSource respondsToSelector:@selector(tableView:validateDrop:proposedRow:proposedDropOperation:)])
00344 _implementedDataSourceMethods |= CPTableViewDataSource_tableView_validateDrop_proposedRow_proposedDropOperation_;
00345
00346 if ([_dataSource respondsToSelector:@selector(tableView:writeRowsWithIndexes:toPasteboard:)])
00347 _implementedDataSourceMethods |= CPTableViewDataSource_tableView_writeRowsWithIndexes_toPasteboard_;
00348
00349 if ([_dataSource respondsToSelector:@selector(tableView:sortDescriptorsDidChange:)])
00350 _implementedDataSourceMethods |= CPTableViewDataSource_tableView_sortDescriptorsDidChange_;
00351
00352 [self reloadData];
00353 }
00354
00358 - (id)dataSource
00359 {
00360 return _dataSource;
00361 }
00362
00363
00364
00370 - (void)reloadDataForRowIndexes:(CPIndexSet)rowIndexes columnIndexes:(CPIndexSet)columnIndexes
00371 {
00372 [self reloadData];
00373
00374
00375 }
00376
00381 - (void)reloadData
00382 {
00383 if (!_dataSource)
00384 return;
00385
00386 _reloadAllRows = YES;
00387 _objectValues = { };
00388
00389
00390 [self noteNumberOfRowsChanged];
00391
00392 [self setNeedsLayout];
00393 [self setNeedsDisplay:YES];
00394 }
00395
00396
00403 - (void)setDoubleAction:(SEL)anAction
00404 {
00405 _doubleAction = anAction;
00406 }
00407
00408 - (SEL)doubleAction
00409 {
00410 return _doubleAction;
00411 }
00412
00413
00414
00415
00416
00417
00418
00419 - (void)setAllowsColumnReordering:(BOOL)shouldAllowColumnReordering
00420 {
00421 _allowsColumnReordering = !!shouldAllowColumnReordering;
00422 }
00423
00424 - (BOOL)allowsColumnReordering
00425 {
00426 return _allowsColumnReordering;
00427 }
00428
00429 - (void)setAllowsColumnResizing:(BOOL)shouldAllowColumnResizing
00430 {
00431 _allowsColumnResizing = !!shouldAllowColumnResizing;
00432 }
00433
00434 - (BOOL)allowsColumnResizing
00435 {
00436 return _allowsColumnResizing;
00437 }
00438
00443 - (void)setAllowsMultipleSelection:(BOOL)shouldAllowMultipleSelection
00444 {
00445 _allowsMultipleSelection = !!shouldAllowMultipleSelection;
00446 }
00447
00448 - (BOOL)allowsMultipleSelection
00449 {
00450 return _allowsMultipleSelection;
00451 }
00452
00457 - (void)setAllowsEmptySelection:(BOOL)shouldAllowEmptySelection
00458 {
00459 _allowsEmptySelection = !!shouldAllowEmptySelection;
00460 }
00461
00462 - (BOOL)allowsEmptySelection
00463 {
00464 return _allowsEmptySelection;
00465 }
00466
00472 - (void)setAllowsColumnSelection:(BOOL)shouldAllowColumnSelection
00473 {
00474 _allowsColumnSelection = !!shouldAllowColumnSelection;
00475 }
00476
00477 - (BOOL)allowsColumnSelection
00478 {
00479 return _allowsColumnSelection;
00480 }
00481
00482
00483
00484 - (void)setIntercellSpacing:(CGSize)aSize
00485 {
00486 if (_CGSizeEqualToSize(_intercellSpacing, aSize))
00487 return;
00488
00489 _intercellSpacing = _CGSizeMakeCopy(aSize);
00490
00491 [self setNeedsLayout];
00492 }
00493
00494 - (void)setThemeState:(int)astae
00495 {
00496 }
00497
00498 - (CGSize)intercellSpacing
00499 {
00500 return _CGSizeMakeCopy(_intercellSpacing);
00501 }
00502
00503 - (void)setRowHeight:(unsigned)aRowHeight
00504 {
00505 aRowHeight = +aRowHeight;
00506
00507 if (_rowHeight === aRowHeight)
00508 return;
00509
00510 _rowHeight = MAX(0.0, aRowHeight);
00511
00512 [self setNeedsLayout];
00513 }
00514
00515 - (unsigned)rowHeight
00516 {
00517 return _rowHeight;
00518 }
00519
00524 - (void)setUsesAlternatingRowBackgroundColors:(BOOL)shouldUseAlternatingRowBackgroundColors
00525 {
00526 _usesAlternatingRowBackgroundColors = shouldUseAlternatingRowBackgroundColors;
00527 }
00528
00529 - (BOOL)usesAlternatingRowBackgroundColors
00530 {
00531 return _usesAlternatingRowBackgroundColors;
00532 }
00533
00539 - (void)setAlternatingRowBackgroundColors:(CPArray)alternatingRowBackgroundColors
00540 {
00541 if ([_alternatingRowBackgroundColors isEqual:alternatingRowBackgroundColors])
00542 return;
00543
00544 _alternatingRowBackgroundColors = alternatingRowBackgroundColors;
00545
00546 [self setNeedsDisplay:YES];
00547 }
00548
00549 - (CPArray)alternatingRowBackgroundColors
00550 {
00551 return _alternatingRowBackgroundColors;
00552 }
00553
00554 - (unsigned)selectionHighlightStyle
00555 {
00556 return _selectionHighlightStyle;
00557 }
00558
00559 - (void)setSelectionHighlightStyle:(unsigned)aSelectionHighlightStyle
00560 {
00561
00562 if (aSelectionHighlightStyle == CPTableViewSelectionHighlightStyleSourceList && !CPFeatureIsCompatible(CPHTMLCanvasFeature))
00563 return;
00564
00565 _selectionHighlightStyle = aSelectionHighlightStyle;
00566
00567 if (aSelectionHighlightStyle === CPTableViewSelectionHighlightStyleSourceList)
00568 _destinationDragStyle = CPTableViewDraggingDestinationFeedbackStyleSourceList;
00569 else
00570 _destinationDragStyle = CPTableViewDraggingDestinationFeedbackStyleRegular;
00571 }
00572
00577 - (void)setGridColor:(CPColor)aColor
00578 {
00579 if (_gridColor === aColor)
00580 return;
00581
00582 _gridColor = aColor;
00583
00584 [self setNeedsDisplay:YES];
00585 }
00586
00587 - (CPColor)gridColor
00588 {
00589 return _gridColor;
00590 }
00591
00597 - (void)setGridStyleMask:(unsigned)aGrideStyleMask
00598 {
00599 if (_gridStyleMask === aGrideStyleMask)
00600 return;
00601
00602 _gridStyleMask = aGrideStyleMask;
00603
00604 [self setNeedsDisplay:YES];
00605 }
00606
00607 - (unsigned)gridStyleMask
00608 {
00609 return _gridStyleMask;
00610 }
00611
00612
00613
00618 - (void)addTableColumn:(CPTableColumn)aTableColumn
00619 {
00620 [_tableColumns addObject:aTableColumn];
00621 [aTableColumn setTableView:self];
00622
00623 if (_dirtyTableColumnRangeIndex < 0)
00624 _dirtyTableColumnRangeIndex = NUMBER_OF_COLUMNS() - 1;
00625 else
00626 _dirtyTableColumnRangeIndex = MIN(NUMBER_OF_COLUMNS() - 1, _dirtyTableColumnRangeIndex);
00627
00628 [self setNeedsLayout];
00629 }
00630
00635 - (void)removeTableColumn:(CPTableColumn)aTableColumn
00636 {
00637 if ([aTableColumn tableView] !== self)
00638 return;
00639
00640 var index = [_tableColumns indexOfObjectIdenticalTo:aTableColumn];
00641
00642 if (index === CPNotFound)
00643 return;
00644
00645 [aTableColumn setTableView:nil];
00646 [_tableColumns removeObjectAtIndex:index];
00647
00648 var tableColumnUID = [aTableColumn UID];
00649
00650 if (_objectValues[tableColumnUID])
00651 _objectValues[tableColumnUID] = nil;
00652
00653 if (_dirtyTableColumnRangeIndex < 0)
00654 _dirtyTableColumnRangeIndex = index;
00655 else
00656 _dirtyTableColumnRangeIndex = MIN(index, _dirtyTableColumnRangeIndex);
00657
00658 [self setNeedsLayout];
00659 }
00660
00661
00667 - (void)moveColumn:(unsigned)fromIndex toColumn:(unsigned)toIndex
00668 {
00669 fromIndex = +fromIndex;
00670 toIndex = +toIndex;
00671
00672 if (fromIndex === toIndex)
00673 return;
00674
00675 if (_dirtyTableColumnRangeIndex < 0)
00676 _dirtyTableColumnRangeIndex = MIN(fromIndex, toIndex);
00677 else
00678 _dirtyTableColumnRangeIndex = MIN(fromIndex, toIndex, _dirtyTableColumnRangeIndex);
00679
00680 if (toIndex > fromIndex)
00681 --toIndex;
00682
00683 var tableColumn = _tableColumns[fromIndex];
00684
00685 [_tableColumns removeObjectAtIndex:fromIndex];
00686 [_tableColumns insertObject:tableColumn atIndex:toIndex];
00687
00688 [self setNeedsLayout];
00689 }
00690
00691 - (CPArray)tableColumns
00692 {
00693 return _tableColumns;
00694 }
00695
00696 - (CPInteger)columnWithIdentifier:(CPString)anIdentifier
00697 {
00698 var index = 0,
00699 count = NUMBER_OF_COLUMNS();
00700
00701 for (; index < count; ++index)
00702 if ([_tableColumns[index] identifier] === anIdentifier)
00703 return index;
00704
00705 return CPNotFound;
00706 }
00707
00708 - (CPTableColumn)tableColumnWithIdentifier:(CPString)anIdentifier
00709 {
00710 var index = [self columnWithIdentifier:anIdentifier];
00711
00712 if (index === CPNotFound)
00713 return nil;
00714
00715 return _tableColumns[index];
00716 }
00717
00718
00719
00725 - (void)selectColumnIndexes:(CPIndexSet)columns byExtendingSelection:(BOOL)shouldExtendSelection
00726 {
00727
00728 if (([columns firstIndex] != CPNotFound && [columns firstIndex] < 0) || [columns lastIndex] >= [self numberOfColumns])
00729 return;
00730
00731
00732 if ([_selectedRowIndexes count] > 0)
00733 {
00734 [self _updateHighlightWithOldRows:_selectedRowIndexes newRows:[CPIndexSet indexSet]];
00735 _selectedRowIndexes = [CPIndexSet indexSet];
00736 }
00737
00738 var previousSelectedIndexes = [_selectedColumnIndexes copy];
00739
00740 if (shouldExtendSelection)
00741 [_selectedColumnIndexes addIndexes:columns];
00742 else
00743 _selectedColumnIndexes = [columns copy];
00744
00745 [self _updateHighlightWithOldColumns:previousSelectedIndexes newColumns:_selectedColumnIndexes];
00746 [_tableDrawView display];
00747
00748 if (_headerView)
00749 [_headerView setNeedsDisplay:YES];
00750
00751 [self _noteSelectionDidChange];
00752 }
00753
00759 - (void)selectRowIndexes:(CPIndexSet)rows byExtendingSelection:(BOOL)shouldExtendSelection
00760 {
00761 if ([rows isEqualToIndexSet:_selectedRowIndexes] ||
00762 (([rows firstIndex] != CPNotFound && [rows firstIndex] < 0) || [rows lastIndex] >= [self numberOfRows]))
00763 return;
00764
00765
00766 if ([_selectedColumnIndexes count] > 0)
00767 {
00768 [self _updateHighlightWithOldColumns:_selectedColumnIndexes newColumns:[CPIndexSet indexSet]];
00769 _selectedColumnIndexes = [CPIndexSet indexSet];
00770 if (_headerView)
00771 [_headerView setNeedsDisplay:YES];
00772 }
00773
00774 var previousSelectedIndexes = [_selectedRowIndexes copy];
00775
00776 if (shouldExtendSelection)
00777 [_selectedRowIndexes addIndexes:rows];
00778 else
00779 _selectedRowIndexes = [rows copy];
00780
00781 [self _updateHighlightWithOldRows:previousSelectedIndexes newRows:_selectedRowIndexes];
00782 [_tableDrawView display];
00783
00784 [self _noteSelectionDidChange];
00785 }
00786
00787 - (void)_updateHighlightWithOldRows:(CPIndexSet)oldRows newRows:(CPIndexSet)newRows
00788 {
00789 var firstExposedRow = [_exposedRows firstIndex],
00790 exposedLength = [_exposedRows lastIndex] - firstExposedRow + 1,
00791 deselectRows = [],
00792 selectRows = [],
00793 deselectRowIndexes = [oldRows copy],
00794 selectRowIndexes = [newRows copy];
00795
00796 [deselectRowIndexes removeMatches:selectRowIndexes];
00797 [deselectRowIndexes getIndexes:deselectRows maxCount:-1 inIndexRange:CPMakeRange(firstExposedRow, exposedLength)];
00798 [selectRowIndexes getIndexes:selectRows maxCount:-1 inIndexRange:CPMakeRange(firstExposedRow, exposedLength)];
00799
00800 for (var identifier in _dataViewsForTableColumns)
00801 {
00802 var dataViewsInTableColumn = _dataViewsForTableColumns[identifier];
00803
00804 var count = deselectRows.length;
00805 while (count--)
00806 {
00807 var rowIndex = deselectRows[count];
00808 var view = dataViewsInTableColumn[rowIndex];
00809 [view unsetThemeState:CPThemeStateSelected];
00810 }
00811
00812 count = selectRows.length;
00813 while (count--)
00814 {
00815 var rowIndex = selectRows[count];
00816 var view = dataViewsInTableColumn[rowIndex];
00817 [view setThemeState:CPThemeStateSelected];
00818 }
00819 }
00820 }
00821
00822 - (void)_updateHighlightWithOldColumns:(CPIndexSet)oldColumns newColumns:(CPIndexSet)newColumns
00823 {
00824 var firstExposedColumn = [_exposedColumns firstIndex],
00825 exposedLength = [_exposedColumns lastIndex] - firstExposedColumn +1,
00826 deselectColumns = [],
00827 selectColumns = [],
00828 deselectColumnIndexes = [oldColumns copy],
00829 selectColumnIndexes = [newColumns copy],
00830 selectRows = [];
00831
00832 [deselectColumnIndexes removeMatches:selectColumnIndexes];
00833 [deselectColumnIndexes getIndexes:deselectColumns maxCount:-1 inIndexRange:CPMakeRange(firstExposedColumn, exposedLength)];
00834 [selectColumnIndexes getIndexes:selectColumns maxCount:-1 inIndexRange:CPMakeRange(firstExposedColumn, exposedLength)];
00835 [_exposedRows getIndexes:selectRows maxCount:-1 inIndexRange:nil];
00836
00837 var rowsCount = selectRows.length,
00838 count = deselectColumns.length;
00839 while (count--)
00840 {
00841 var columnIndex = deselectColumns[count],
00842 identifier = [_tableColumns[columnIndex] UID],
00843 dataViewsInTableColumn = _dataViewsForTableColumns[identifier];
00844
00845 for (var i = 0; i < rowsCount; i++)
00846 {
00847 var rowIndex = selectRows[i],
00848 dataView = dataViewsInTableColumn[rowIndex];
00849 [dataView unsetThemeState:CPThemeStateSelected];
00850 }
00851
00852 if (_headerView)
00853 {
00854 var headerView = [_tableColumns[columnIndex] headerView];
00855 [headerView unsetThemeState:CPThemeStateSelected];
00856 }
00857 }
00858
00859 count = selectColumns.length;
00860 while (count--)
00861 {
00862 var columnIndex = selectColumns[count],
00863 identifier = [_tableColumns[columnIndex] UID],
00864 dataViewsInTableColumn = _dataViewsForTableColumns[identifier];
00865
00866 for (var i = 0; i < rowsCount; i++)
00867 {
00868 var rowIndex = selectRows[i],
00869 dataView = dataViewsInTableColumn[rowIndex];
00870 [dataView setThemeState:CPThemeStateSelected];
00871 }
00872 if (_headerView)
00873 {
00874 var headerView = [_tableColumns[columnIndex] headerView];
00875 [headerView setThemeState:CPThemeStateSelected];
00876 }
00877 }
00878 }
00879
00880 - (int)selectedColumn
00881 {
00882 [_selectedColumnIndexes lastIndex];
00883 }
00884
00885 - (CPIndexSet)selectedColumnIndexes
00886 {
00887 return _selectedColumnIndexes;
00888 }
00889
00890 - (int)selectedRow
00891 {
00892 return [_selectedRowIndexes lastIndex];
00893 }
00894
00895 - (CPIndexSet)selectedRowIndexes
00896 {
00897 return _selectedRowIndexes;
00898 }
00899
00900 - (void)deselectColumn:(CPInteger)aColumn
00901 {
00902 var selectedColumnIndexes = [_selectedColumnIndexes copy];
00903 [selectedColumnIndexes removeIndex:aColumn];
00904 [self selectColumnIndexes:selectedColumnIndexes byExtendingSelection:NO];
00905 [self _noteSelectionDidChange];
00906 }
00907
00908 - (void)deselectRow:(CPInteger)aRow
00909 {
00910 var selectedRowIndexes = [_selectedRowIndexes copy];
00911 [selectedRowIndexes removeIndex:aRow];
00912 [self selectRowIndexes:selectedRowIndexes byExtendingSelection:NO];
00913 [self _noteSelectionDidChange];
00914 }
00915
00916 - (CPInteger)numberOfSelectedColumns
00917 {
00918 return [_selectedColumnIndexes count];
00919 }
00920
00921 - (CPInteger)numberOfSelectedRows
00922 {
00923 return [_selectedRowIndexes count];
00924 }
00925
00926
00927
00928
00929
00930
00931 - (BOOL)isColumnSelected:(CPInteger)aColumn
00932 {
00933 return [_selectedColumnIndexes containsIndex:aColumn];
00934 }
00935
00936 - (BOOL)isRowSelected:(CPInteger)aRow
00937 {
00938 return [_selectedRowIndexes containsIndex:aRow];
00939 }
00940
00941
00942
00943
00944
00945
00946
00950 - (void)deselectAll
00951 {
00952 [self selectRowIndexes:[CPIndexSet indexSet] byExtendingSelection:NO];
00953 [self selectColumnIndexes:[CPIndexSet indexSet] byExtendingSelection:NO];
00954 }
00955
00956
00957
00958 - (int)numberOfColumns
00959 {
00960 return NUMBER_OF_COLUMNS();
00961 }
00962
00963
00964
00965
00966 - (int)numberOfRows
00967 {
00968 if (!_dataSource)
00969 return 0;
00970
00971 return [_dataSource numberOfRowsInTableView:self];
00972 }
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992 - (CPView)cornerView
00993 {
00994 return _cornerView;
00995 }
00996
00997 - (void)setCornerView:(CPView)aView
00998 {
00999 if (_cornerView === aView)
01000 return;
01001
01002 _cornerView = aView;
01003
01004 var scrollView = [[self superview] superview];
01005
01006 if ([scrollView isKindOfClass:[CPScrollView class]] && [scrollView documentView] === self)
01007 [scrollView _updateCornerAndHeaderView];
01008 }
01009
01010 - (CPView)headerView
01011 {
01012 return _headerView;
01013 }
01014
01015 - (void)setHeaderView:(CPView)aHeaderView
01016 {
01017 if (_headerView === aHeaderView)
01018 return;
01019
01020 [_headerView setTableView:nil];
01021
01022 _headerView = aHeaderView;
01023
01024 if (_headerView)
01025 {
01026 [_headerView setTableView:self];
01027 [_headerView setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), _CGRectGetHeight([_headerView frame]))];
01028 }
01029
01030 var scrollView = [[self superview] superview];
01031
01032 if ([scrollView isKindOfClass:[CPScrollView class]] && [scrollView documentView] === self)
01033 [scrollView _updateCornerAndHeaderView];
01034 }
01035
01036
01037
01038
01039
01040 - (void)_recalculateTableColumnRanges
01041 {
01042 if (_dirtyTableColumnRangeIndex < 0)
01043 return;
01044
01045 var index = _dirtyTableColumnRangeIndex,
01046 count = NUMBER_OF_COLUMNS(),
01047 x = index === 0 ? 0.0 : CPMaxRange(_tableColumnRanges[index - 1]);
01048
01049 for (; index < count; ++index)
01050 {
01051 var tableColumn = _tableColumns[index];
01052
01053 if ([tableColumn isHidden])
01054 _tableColumnRanges[index] = CPMakeRange(x, 0.0);
01055
01056 else
01057 {
01058 var width = [_tableColumns[index] width];
01059
01060 _tableColumnRanges[index] = CPMakeRange(x, width);
01061
01062 x += width;
01063 }
01064 }
01065
01066 _tableColumnRanges.length = count;
01067 _dirtyTableColumnRangeIndex = CPNotFound;
01068 }
01069
01070
01071
01072 - (CGRect)rectOfColumn:(CPInteger)aColumnIndex
01073 {
01074 aColumnIndex = +aColumnIndex;
01075
01076 if (aColumnIndex < 0 || aColumnIndex >= NUMBER_OF_COLUMNS())
01077 return _CGRectMakeZero();
01078
01079 UPDATE_COLUMN_RANGES_IF_NECESSARY();
01080
01081 var range = _tableColumnRanges[aColumnIndex];
01082
01083 return _CGRectMake(range.location, 0.0, range.length, CGRectGetHeight([self bounds]));
01084 }
01085
01086 - (CGRect)rectOfRow:(CPInteger)aRowIndex
01087 {
01088 if (NO)
01089 return NULL;
01090
01091
01092 return _CGRectMake(0.0, (aRowIndex * (_rowHeight + _intercellSpacing.height)), _CGRectGetWidth([self bounds]), _rowHeight);
01093 }
01094
01095
01096
01102 - (CPRange)rowsInRect:(CGRect)aRect
01103 {
01104
01105 if (_numberOfRows <= 0)
01106 return CPMakeRange(0, 0);
01107
01108 var bounds = [self bounds];
01109
01110
01111 if (!CGRectIntersectsRect(aRect, bounds))
01112 return CPMakeRange(0, 0);
01113
01114 var firstRow = [self rowAtPoint:aRect.origin];
01115
01116
01117 if (firstRow < 0)
01118 firstRow = 0;
01119
01120 var lastRow = [self rowAtPoint:_CGPointMake(0.0, _CGRectGetMaxY(aRect))];
01121
01122
01123 if (lastRow < 0)
01124 lastRow = _numberOfRows - 1;
01125
01126 return CPMakeRange(firstRow, lastRow - firstRow + 1);
01127 }
01128
01129
01130
01131
01132
01137 - (CPIndexSet)columnIndexesInRect:(CGRect)aRect
01138 {
01139 var column = MAX(0, [self columnAtPoint:_CGPointMake(aRect.origin.x, 0.0)]),
01140 lastColumn = [self columnAtPoint:_CGPointMake(_CGRectGetMaxX(aRect), 0.0)];
01141
01142 if (lastColumn === CPNotFound)
01143 lastColumn = NUMBER_OF_COLUMNS() - 1;
01144
01145
01146 if (_numberOfHiddenColumns <= 0)
01147 return [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(column, lastColumn - column + 1)];
01148
01149
01150 var indexSet = [CPIndexSet indexSet];
01151
01152 for (; column <= lastColumn; ++column)
01153 {
01154 var tableColumn = _tableColumns[column];
01155
01156 if (![tableColumn isHidden])
01157 [indexSet addIndex:column];
01158 }
01159
01160 return indexSet;
01161 }
01162
01163
01164
01165
01166 - (CPInteger)columnAtPoint:(CGPoint)aPoint
01167 {
01168 var bounds = [self bounds];
01169
01170 if (!_CGRectContainsPoint(bounds, aPoint))
01171 return CPNotFound;
01172
01173 UPDATE_COLUMN_RANGES_IF_NECESSARY();
01174
01175 var x = aPoint.x,
01176 low = 0,
01177 high = _tableColumnRanges.length - 1;
01178
01179 while (low <= high)
01180 {
01181 var middle = FLOOR(low + (high - low) / 2),
01182 range = _tableColumnRanges[middle];
01183
01184 if (x < range.location)
01185 high = middle - 1;
01186
01187 else if (x >= CPMaxRange(range))
01188 low = middle + 1;
01189
01190 else
01191 {
01192 var numberOfColumns = _tableColumnRanges.length;
01193
01194 while (middle < numberOfColumns && [_tableColumns[middle] isHidden])
01195 ++middle;
01196
01197 if (middle < numberOfColumns)
01198 return middle;
01199
01200 return CPNotFound;
01201 }
01202 }
01203
01204 return CPNotFound;
01205 }
01206
01207 - (CPInteger)rowAtPoint:(CGPoint)aPoint
01208 {
01209 var y = aPoint.y;
01210
01211 var row = FLOOR(y / (_rowHeight + _intercellSpacing.height));
01212
01213 if (row >= _numberOfRows)
01214 return -1;
01215
01216 return row;
01217 }
01218
01219 - (CGRect)frameOfDataViewAtColumn:(CPInteger)aColumn row:(CPInteger)aRow
01220 {
01221 UPDATE_COLUMN_RANGES_IF_NECESSARY();
01222
01223 var tableColumnRange = _tableColumnRanges[aColumn],
01224 rectOfRow = [self rectOfRow:aRow];
01225
01226 return _CGRectMake(tableColumnRange.location, _CGRectGetMinY(rectOfRow), tableColumnRange.length, _CGRectGetHeight(rectOfRow));
01227 }
01228
01229
01230 - (void)resizeWithOldSuperviewSize:(CGSize)aSize
01231 {
01232 [super resizeWithOldSuperviewSize:aSize];
01233
01234 if (_disableAutomaticResizing)
01235 return;
01236
01237 var mask = _columnAutoResizingStyle;
01238
01239 if(mask === CPTableViewUniformColumnAutoresizingStyle)
01240 {
01241 [self _resizeAllColumnUniformlyWithOldSize:aSize];
01242 }
01243
01244 if(mask === CPTableViewLastColumnOnlyAutoresizingStyle)
01245 {
01246 [self sizeLastColumnToFit];
01247 }
01248
01249 if(mask === CPTableViewFirstColumnOnlyAutoresizingStyle)
01250 {
01251 var superview = [self superview];
01252
01253 if (!superview)
01254 return;
01255
01256 var superviewSize = [superview bounds].size;
01257
01258 UPDATE_COLUMN_RANGES_IF_NECESSARY();
01259
01260 var count = NUMBER_OF_COLUMNS();
01261
01262 var visColumns = [[CPArray alloc] init];
01263 var totalWidth = 0;
01264
01265 for(var i=0; i < count; i++)
01266 {
01267 if(![_tableColumns[i] isHidden])
01268 {
01269 [visColumns addObject:i];
01270 totalWidth += [_tableColumns[i] width];
01271 }
01272 }
01273
01274 count = [visColumns count];
01275
01276
01277 if (count > 0)
01278 {
01279 var columnToResize = _tableColumns[visColumns[0]];
01280 var newWidth = superviewSize.width - totalWidth;
01281 newWidth += [columnToResize width];
01282 newWidth = (newWidth < [columnToResize minWidth]) ? [columnToResize minWidth] : newWidth;
01283 newWidth = (newWidth > [columnToResize maxWidth]) ? [columnToResize maxWidth] : newWidth;
01284
01285 [columnToResize setWidth:FLOOR(newWidth)];
01286 }
01287
01288 [self setNeedsLayout];
01289 }
01290
01291 }
01292
01293 - (void)_resizeAllColumnUniformlyWithOldSize:(CGSize)oldSize
01294 {
01295 var superview = [self superview];
01296
01297 if (!superview)
01298 return;
01299
01300 var superviewSize = [superview bounds].size;
01301
01302 if (_dirtyTableColumnRangeIndex !== CPNotFound) [self _recalculateTableColumnRanges];
01303
01304 var count = _tableColumns.length,
01305 visColumns = [[CPArray alloc] init],
01306 buffer = 0.0;
01307
01308
01309 for(var i=0; i < count; i++)
01310 {
01311 var tableColumn = _tableColumns[i];
01312 if(![tableColumn isHidden] && ([tableColumn resizingMask] & CPTableColumnAutoresizingMask))
01313 [visColumns addObject:i];
01314 }
01315
01316
01317 count = [visColumns count];
01318
01319
01320 if (count > 0)
01321 {
01322 var maxXofColumns = CGRectGetMaxX([self rectOfColumn:visColumns[count - 1]]);
01323
01324
01325 if (!_lastColumnShouldSnap && (maxXofColumns >= superviewSize.width && maxXofColumns <= oldSize.width || maxXofColumns <= superviewSize.width && maxXofColumns >= oldSize.width))
01326 {
01327
01328 _lastColumnShouldSnap = YES;
01329
01330 [self _resizeAllColumnUniformlyWithOldSize:CGSizeMake(maxXofColumns, 0)];
01331 }
01332
01333 if(!_lastColumnShouldSnap)
01334 return;
01335
01336
01337
01338
01339
01340
01341 for (var i = 0; i < count; i++)
01342 {
01343 var column = visColumns[i];
01344 columnToResize = _tableColumns[column],
01345 currentBuffer = buffer / (count - i),
01346 realNewWidth = ([columnToResize width] / oldSize.width * [superview bounds].size.width) + currentBuffer ,
01347 newWidth = MAX([columnToResize minWidth], realNewWidth);
01348 newWidth = MIN([columnToResize maxWidth], realNewWidth);
01349 buffer -= currentBuffer;
01350
01351
01352 buffer += realNewWidth - newWidth;
01353
01354 [columnToResize setWidth:newWidth];
01355 }
01356
01357
01358 if(buffer !== 0)
01359 _lastColumnShouldSnap = NO;
01360 }
01361
01362 [self setNeedsLayout];
01363 }
01364
01371 - (void)setColumnAutoresizingStyle:(unsigned)style
01372 {
01373
01374 _columnAutoResizingStyle = style;
01375 }
01376
01377 - (unsigned)columnAutoresizingStyle
01378 {
01379 return _columnAutoResizingStyle;
01380 }
01381
01385 - (void)sizeLastColumnToFit
01386 {
01387 var superview = [self superview];
01388
01389 if (!superview)
01390 return;
01391
01392 var superviewSize = [superview bounds].size;
01393
01394 UPDATE_COLUMN_RANGES_IF_NECESSARY();
01395
01396 var count = NUMBER_OF_COLUMNS();
01397
01398
01399 while (count-- && [_tableColumns[count] isHidden]) ;
01400
01401
01402 if (count >= 0)
01403 {
01404 var columnToResize = _tableColumns[count];
01405 var newSize = MAX(0.0, superviewSize.width - CGRectGetMinX([self rectOfColumn:count]));
01406
01407 if (newSize > 0)
01408 {
01409 newSize = MAX([columnToResize minWidth], newSize);
01410 newSize = MIN([columnToResize maxWidth], newSize);
01411 [columnToResize setWidth:newSize];
01412 }
01413 }
01414
01415 [self setNeedsLayout];
01416 }
01417
01418 - (void)noteNumberOfRowsChanged
01419 {
01420 _numberOfRows = [_dataSource numberOfRowsInTableView:self];
01421
01422 [self tile];
01423 }
01424
01425 - (void)tile
01426 {
01427 UPDATE_COLUMN_RANGES_IF_NECESSARY();
01428
01429
01430 var width = _tableColumnRanges.length > 0 ? CPMaxRange([_tableColumnRanges lastObject]) : 0.0,
01431 height = (_rowHeight + _intercellSpacing.height) * _numberOfRows,
01432 superview = [self superview];
01433
01434 if ([superview isKindOfClass:[CPClipView class]])
01435 {
01436 var superviewSize = [superview bounds].size;
01437
01438 width = MAX(superviewSize.width, width);
01439 height = MAX(superviewSize.height, height);
01440 }
01441
01442 [self setFrameSize:_CGSizeMake(width, height)];
01443
01444 [self setNeedsLayout];
01445 [self setNeedsDisplay:YES];
01446 }
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01463 - (void)scrollRowToVisible:(int)rowIndex
01464 {
01465 [self scrollRectToVisible:[self rectOfRow:rowIndex]];
01466 }
01467
01472 - (void)scrollColumnToVisible:(int)columnIndex
01473 {
01474 [self scrollRectToVisible:[self rectOfColumn:columnIndex]];
01475
01476 }
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488 - (void)setDelegate:(id)aDelegate
01489 {
01490 if (_delegate === aDelegate)
01491 return;
01492
01493 var defaultCenter = [CPNotificationCenter defaultCenter];
01494
01495 if (_delegate)
01496 {
01497 if ([_delegate respondsToSelector:@selector(tableViewColumnDidMove:)])
01498 [defaultCenter
01499 removeObserver:_delegate
01500 name:CPTableViewColumnDidMoveNotification
01501 object:self];
01502
01503 if ([_delegate respondsToSelector:@selector(tableViewColumnDidResize:)])
01504 [defaultCenter
01505 removeObserver:_delegate
01506 name:CPTableViewColumnDidResizeNotification
01507 object:self];
01508
01509 if ([_delegate respondsToSelector:@selector(tableViewSelectionDidChange:)])
01510 [defaultCenter
01511 removeObserver:_delegate
01512 name:CPTableViewSelectionDidChangeNotification
01513 object:self];
01514
01515 if ([_delegate respondsToSelector:@selector(tableViewSelectionIsChanging:)])
01516 [defaultCenter
01517 removeObserver:_delegate
01518 name:CPTableViewSelectionIsChangingNotification
01519 object:self];
01520 }
01521
01522 _delegate = aDelegate;
01523 _implementedDelegateMethods = 0;
01524
01525 if ([_delegate respondsToSelector:@selector(selectionShouldChangeInTableView:)])
01526 _implementedDelegateMethods |= CPTableViewDelegate_selectionShouldChangeInTableView_;
01527
01528 if ([_delegate respondsToSelector:@selector(tableView:dataViewForTableColumn:row:)])
01529 _implementedDelegateMethods |= CPTableViewDelegate_tableView_dataViewForTableColumn_row_;
01530
01531 if ([_delegate respondsToSelector:@selector(tableView:didClickTableColumn:)])
01532 _implementedDelegateMethods |= CPTableViewDelegate_tableView_didClickTableColumn_;
01533
01534 if ([_delegate respondsToSelector:@selector(tableView:didDragTableColumn:)])
01535 _implementedDelegateMethods |= CPTableViewDelegate_tableView_didDragTableColumn_;
01536
01537 if ([_delegate respondsToSelector:@selector(tableView:heightOfRow:)])
01538 _implementedDelegateMethods |= CPTableViewDelegate_tableView_heightOfRow_;
01539
01540 if ([_delegate respondsToSelector:@selector(tableView:isGroupRow:)])
01541 _implementedDelegateMethods |= CPTableViewDelegate_tableView_isGroupRow_;
01542
01543 if ([_delegate respondsToSelector:@selector(tableView:mouseDownInHeaderOfTableColumn:)])
01544 _implementedDelegateMethods |= CPTableViewDelegate_tableView_mouseDownInHeaderOfTableColumn_;
01545
01546 if ([_delegate respondsToSelector:@selector(tableView:nextTypeSelectMatchFromRow:toRow:forString:)])
01547 _implementedDelegateMethods |= CPTableViewDelegate_tableView_nextTypeSelectMatchFromRow_toRow_forString_;
01548
01549 if ([_delegate respondsToSelector:@selector(tableView:selectionIndexesForProposedSelection:)])
01550 _implementedDelegateMethods |= CPTableViewDelegate_tableView_selectionIndexesForProposedSelection_;
01551
01552 if ([_delegate respondsToSelector:@selector(tableView:shouldEditTableColumn:row:)])
01553 _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldEditTableColumn_row_;
01554
01555 if ([_delegate respondsToSelector:@selector(tableView:shouldSelectRow:)])
01556 _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldSelectRow_;
01557
01558 if ([_delegate respondsToSelector:@selector(tableView:shouldSelectTableColumn:)])
01559 _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldSelectTableColumn_;
01560
01561 if ([_delegate respondsToSelector:@selector(tableView:shouldShowViewExpansionForTableColumn:row:)])
01562 _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldShowViewExpansionForTableColumn_row_;
01563
01564 if ([_delegate respondsToSelector:@selector(tableView:shouldTrackView:forTableColumn:row:)])
01565 _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldTrackView_forTableColumn_row_;
01566
01567 if ([_delegate respondsToSelector:@selector(tableView:shouldTypeSelectForEvent:withCurrentSearchString:)])
01568 _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldTypeSelectForEvent_withCurrentSearchString_;
01569
01570 if ([_delegate respondsToSelector:@selector(tableView:toolTipForView:rect:tableColumn:row:mouseLocation:)])
01571 _implementedDelegateMethods |= CPTableViewDelegate_tableView_toolTipForView_rect_tableColumn_row_mouseLocation_;
01572
01573 if ([_delegate respondsToSelector:@selector(tableView:typeSelectStringForTableColumn:row:)])
01574 _implementedDelegateMethods |= CPTableViewDelegate_tableView_typeSelectStringForTableColumn_row_;
01575
01576 if ([_delegate respondsToSelector:@selector(tableView:willDisplayView:forTableColumn:row:)])
01577 _implementedDelegateMethods |= CPTableViewDelegate_tableView_willDisplayView_forTableColumn_row_;
01578
01579 if ([_delegate respondsToSelector:@selector(tableViewColumnDidMove:)])
01580 [defaultCenter
01581 addObserver:_delegate
01582 selector:@selector(tableViewColumnDidMove:)
01583 name:CPTableViewColumnDidMoveNotification
01584 object:self];
01585
01586 if ([_delegate respondsToSelector:@selector(tableViewColumnDidResize:)])
01587 [defaultCenter
01588 addObserver:_delegate
01589 selector:@selector(tableViewColumnDidResize:)
01590 name:CPTableViewColumnDidResizeNotification
01591 object:self];
01592
01593 if ([_delegate respondsToSelector:@selector(tableViewSelectionDidChange:)])
01594 [defaultCenter
01595 addObserver:_delegate
01596 selector:@selector(tableViewSelectionDidChange:)
01597 name:CPTableViewSelectionDidChangeNotification
01598 object:self];
01599
01600 if ([_delegate respondsToSelector:@selector(tableViewSelectionIsChanging:)])
01601 [defaultCenter
01602 addObserver:_delegate
01603 selector:@selector(tableViewSelectionIsChanging:)
01604 name:CPTableViewSelectionIsChangingNotification
01605 object:self];
01606 }
01607
01608 - (id)delegate
01609 {
01610 return _delegate;
01611 }
01612
01613 - (void)_sendDelegateDidClickColumn:(int)column
01614 {
01615 if (_implementedDelegateMethods & CPTableViewDelegate_tableView_didClickTableColumn_)
01616 [_delegate tableView:self didClickTableColumn:_tableColumns[column]];
01617 }
01618
01619 - (void)_sendDelegateDidDragColumn:(int)column
01620 {
01621 if (_implementedDelegateMethods & CPTableViewDelegate_tableView_didDragTableColumn_)
01622 [_delegate tableView:self didDragTableColumn:_tableColumns[column]];
01623 }
01624
01625 - (void)_sendDelegateDidMouseDownInHeader:(int)column
01626 {
01627 if (_implementedDelegateMethods & CPTableViewDelegate_tableView_mouseDownInHeaderOfTableColumn_)
01628 [_delegate tableView:self mouseDownInHeaderOfTableColumn:_tableColumns[column]];
01629 }
01630
01631 - (void)_sendDataSourceSortDescriptorsDidChange:(CPArray)oldDescriptors
01632 {
01633 if (_implementedDataSourceMethods & CPTableViewDataSource_tableView_sortDescriptorsDidChange_)
01634 [_dataSource tableView:self sortDescriptorsDidChange:oldDescriptors];
01635 }
01636
01637 - (void)_didClickTableColumn:(int)clickedColumn modifierFlags:(unsigned)modifierFlags
01638 {
01639 [self _sendDelegateDidClickColumn:clickedColumn];
01640
01641 if (_allowsColumnSelection)
01642 {
01643 if (modifierFlags & CPCommandKeyMask)
01644 {
01645 if ([self isColumnSelected:clickedColumn])
01646 [self deselectColumn:clickedColumn];
01647 else if ([self allowsMultipleSelection] == YES)
01648 [self selectColumnIndexes:[CPIndexSet indexSetWithIndex:clickedColumn] byExtendingSelection:YES];
01649
01650 return;
01651 }
01652 else if (modifierFlags & CPShiftKeyMask)
01653 {
01654
01655 var startColumn = MIN(clickedColumn, [_selectedColumnIndexes lastIndex]),
01656 endColumn = MAX(clickedColumn, [_selectedColumnIndexes firstIndex]);
01657
01658 [self selectColumnIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(startColumn, endColumn - startColumn + 1)]
01659 byExtendingSelection:YES];
01660
01661 return;
01662 }
01663 else
01664 [self selectColumnIndexes:[CPIndexSet indexSetWithIndex:clickedColumn] byExtendingSelection:NO];
01665 }
01666
01667 [self _changeSortDescriptorsForClickOnColumn:clickedColumn];
01668 }
01669
01670
01671 - (void)_changeSortDescriptorsForClickOnColumn:(int)column
01672 {
01673 var tableColumn = [_tableColumns objectAtIndex:column],
01674 newMainSortDescriptor = [tableColumn sortDescriptorPrototype];
01675
01676 if (!newMainSortDescriptor)
01677 return;
01678
01679 var oldMainSortDescriptor = nil,
01680 oldSortDescriptors = [self sortDescriptors],
01681 newSortDescriptors = [CPArray arrayWithArray:oldSortDescriptors],
01682
01683 e = [newSortDescriptors objectEnumerator],
01684 descriptor = nil,
01685 outdatedDescriptors = [CPArray array];
01686
01687 if ([_sortDescriptors count] > 0)
01688 oldMainSortDescriptor = [[self sortDescriptors] objectAtIndex: 0];
01689
01690
01691 while ((descriptor = [e nextObject]) != nil)
01692 {
01693 if ([[descriptor key] isEqual: [newMainSortDescriptor key]])
01694 [outdatedDescriptors addObject:descriptor];
01695 }
01696
01697
01698 if ([[newMainSortDescriptor key] isEqual:[oldMainSortDescriptor key]])
01699 newMainSortDescriptor = [oldMainSortDescriptor reversedSortDescriptor];
01700
01701 [newSortDescriptors removeObjectsInArray:outdatedDescriptors];
01702 [newSortDescriptors insertObject:newMainSortDescriptor atIndex:0];
01703
01704
01705 var image = [newMainSortDescriptor ascending] ? [CPTableView _defaultTableHeaderSortImage] : [CPTableView _defaultTableHeaderReverseSortImage];
01706
01707 [self setIndicatorImage:nil inTableColumn:_currentHighlightedTableColumn];
01708 [self setIndicatorImage:image inTableColumn:tableColumn];
01709 [self setHighlightedTableColumn:tableColumn];
01710
01711 [self setSortDescriptors:newSortDescriptors];
01712 }
01713
01714 - (void)setIndicatorImage:(CPImage)anImage inTableColumn:(CPTableColumn)aTableColumn
01715 {
01716 if (aTableColumn)
01717 [[aTableColumn headerView] _setIndicatorImage:anImage];
01718 }
01719
01720 + (CPImage)_defaultTableHeaderSortImage
01721 {
01722 return CPAppKitImage("tableview-headerview-ascending.png", CGSizeMake(9.0, 8.0));
01723 }
01724
01725 + (CPImage)_defaultTableHeaderReverseSortImage
01726 {
01727 return CPAppKitImage("tableview-headerview-descending.png", CGSizeMake(9.0, 8.0));
01728 }
01729
01730
01731
01732 - (CPTableColumn)highlightedTableColumn
01733 {
01734 return _currentHighlightedTableColumn;
01735 }
01736
01737 - (void)setHighlightedTableColumn:(CPTableColumn)aTableColumn
01738 {
01739 if (_currentHighlightedTableColumn == aTableColumn)
01740 return;
01741
01742 if (_headerView)
01743 {
01744 if (_currentHighlightedTableColumn != nil)
01745 [[_currentHighlightedTableColumn headerView] unsetThemeState:CPThemeStateSelected];
01746
01747 if (aTableColumn != nil)
01748 [[aTableColumn headerView] setThemeState:CPThemeStateSelected];
01749 }
01750
01751 _currentHighlightedTableColumn = aTableColumn;
01752 }
01753
01759 - (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes atPoint:(CGPoint)mouseDownPoint
01760 {
01761 return YES;
01762 }
01763
01764 - (CPImage)dragImageForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPointPointer)dragImageOffset
01765 {
01766 return [[CPImage alloc] initWithContentsOfFile:@"Frameworks/AppKit/Resources/GenericFile.png" size:CGSizeMake(32,32)];
01767 }
01768
01769 - (CPView)dragViewForRowsWithIndexes:(CPIndexSet)theDraggedRows tableColumns:(CPArray)theTableColumns event:(CPEvent)theDragEvent offset:(CPPoint)dragViewOffset
01770 {
01771 var bounds = [self bounds],
01772 view = [[CPView alloc] initWithFrame:bounds];
01773
01774 [view setAlphaValue:0.7];
01775
01776
01777
01778
01779 var firstExposedColumn = [_exposedColumns firstIndex],
01780 firstExposedRow = [_exposedRows firstIndex],
01781 exposedColumnsLength = [_exposedColumns lastIndex] - firstExposedColumn + 1,
01782 exposedRowsLength = [_exposedRows lastIndex] - firstExposedRow + 1,
01783 columns = [],
01784 rows = [];
01785
01786 [_exposedColumns getIndexes:columns maxCount:-1 inIndexRange:CPMakeRange(firstExposedColumn, exposedColumnsLength)];
01787 [theDraggedRows getIndexes:rows maxCount:-1 inIndexRange:CPMakeRange(firstExposedRow, exposedRowsLength)];
01788
01789 var columnIndex = [columns count];
01790
01791 while (columnIndex--)
01792 {
01793 var column = columns[columnIndex],
01794 tableColumn = [_tableColumns objectAtIndex:column],
01795 rowIndex = [rows count];
01796
01797 while (rowIndex--)
01798 {
01799 var row = rows[rowIndex];
01800 var dataView = [self _newDataViewForRow:row tableColumn:tableColumn];
01801
01802 [dataView setFrame:[self frameOfDataViewAtColumn:column row:row]];
01803 [dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]];
01804
01805 [view addSubview:dataView];
01806 }
01807 }
01808
01809 var dragPoint = [self convertPoint:[theDragEvent locationInWindow] fromView:nil];
01810 dragViewOffset.x = CGRectGetWidth(bounds)/2 - dragPoint.x;
01811 dragViewOffset.y = CGRectGetHeight(bounds)/2 - dragPoint.y;
01812
01813 return view;
01814 }
01815
01816 - (void)setDraggingSourceOperationMask:(CPDragOperation)mask forLocal:(BOOL)isLocal
01817 {
01818
01819 _dragOperationDefaultMask = mask;
01820 }
01821
01827 - (void)setDropRow:(CPInteger)row dropOperation:(CPTableViewDropOperation)operation
01828 {
01829 if(row > [self numberOfRows] && operation === CPTableViewDropOn)
01830 {
01831 var numberOfRows = [self numberOfRows] + 1;
01832 var reason = @"Attempt to set dropRow=" + row +
01833 " dropOperation=CPTableViewDropOn when [0 - " + numberOfRows + "] is valid range of rows."
01834
01835 [[CPException exceptionWithName:@"Error" reason:reason userInfo:nil] raise];
01836 }
01837
01838
01839 _retargetedDropRow = row;
01840 _retargetedDropOperation = operation;
01841 }
01842
01850 - (void)setDraggingDestinationFeedbackStyle:(CPTableViewDraggingDestinationFeedbackStyle)aStyle
01851 {
01852
01853 _destinationDragStyle = aStyle;
01854 }
01855
01856 - (CPTableViewDraggingDestinationFeedbackStyle)draggingDestinationFeedbackStyle
01857 {
01858 return _destinationDragStyle;
01859 }
01860
01865 - (void)setVerticalMotionCanBeginDrag:(BOOL)aFlag
01866 {
01867 _verticalMotionCanDrag = aFlag;
01868 }
01869
01870 - (BOOL)verticalMotionCanBeginDrag
01871 {
01872 return _verticalMotionCanDrag;
01873 }
01874
01875
01876 - (void)setSortDescriptors:(CPArray)sortDescriptors
01877 {
01878 var oldSortDescriptors = [self sortDescriptors],
01879 newSortDescriptors = nil;
01880
01881 if (sortDescriptors == nil)
01882 newSortDescriptors = [CPArray array];
01883 else
01884 newSortDescriptors = [CPArray arrayWithArray:sortDescriptors];
01885
01886 if ([newSortDescriptors isEqual:oldSortDescriptors])
01887 return;
01888
01889 _sortDescriptors = newSortDescriptors;
01890
01891 [self _sendDataSourceSortDescriptorsDidChange:oldSortDescriptors];
01892 }
01893
01894 - (CPArray)sortDescriptors
01895 {
01896 return _sortDescriptors;
01897 }
01898
01899
01900
01901
01902
01903
01904
01905
01906
01907
01908 - (id)_objectValueForTableColumn:(CPTableColumn)aTableColumn row:(CPInteger)aRowIndex
01909 {
01910 var tableColumnUID = [aTableColumn UID],
01911 tableColumnObjectValues = _objectValues[tableColumnUID];
01912
01913 if (!tableColumnObjectValues)
01914 {
01915 tableColumnObjectValues = [];
01916 _objectValues[tableColumnUID] = tableColumnObjectValues;
01917 }
01918
01919 var objectValue = tableColumnObjectValues[aRowIndex];
01920
01921 if (objectValue === undefined)
01922 {
01923 objectValue = [_dataSource tableView:self objectValueForTableColumn:aTableColumn row:aRowIndex];
01924 tableColumnObjectValues[aRowIndex] = objectValue;
01925 }
01926
01927 return objectValue;
01928 }
01929
01930 - (CGRect)_exposedRect
01931 {
01932 var superview = [self superview];
01933
01934 if (![superview isKindOfClass:[CPClipView class]])
01935 return [self bounds];
01936
01937 return [self convertRect:CGRectIntersection([superview bounds], [self frame]) fromView:superview];
01938 }
01939
01940 - (void)load
01941 {
01942 if (_reloadAllRows)
01943 {
01944 [self _unloadDataViewsInRows:_exposedRows columns:_exposedColumns];
01945
01946 _exposedRows = [CPIndexSet indexSet];
01947 _exposedColumns = [CPIndexSet indexSet];
01948
01949 _reloadAllRows = NO;
01950 }
01951
01952 var exposedRect = [self _exposedRect],
01953 exposedRows = [CPIndexSet indexSetWithIndexesInRange:[self rowsInRect:exposedRect]],
01954 exposedColumns = [self columnIndexesInRect:exposedRect],
01955 obscuredRows = [_exposedRows copy],
01956 obscuredColumns = [_exposedColumns copy];
01957
01958 [obscuredRows removeIndexes:exposedRows];
01959 [obscuredColumns removeIndexes:exposedColumns];
01960
01961 var newlyExposedRows = [exposedRows copy],
01962 newlyExposedColumns = [exposedColumns copy];
01963
01964 [newlyExposedRows removeIndexes:_exposedRows];
01965 [newlyExposedColumns removeIndexes:_exposedColumns];
01966
01967 var previouslyExposedRows = [exposedRows copy],
01968 previouslyExposedColumns = [exposedColumns copy];
01969
01970 [previouslyExposedRows removeIndexes:newlyExposedRows];
01971 [previouslyExposedColumns removeIndexes:newlyExposedColumns];
01972
01973 [self _unloadDataViewsInRows:previouslyExposedRows columns:obscuredColumns];
01974 [self _unloadDataViewsInRows:obscuredRows columns:previouslyExposedColumns];
01975 [self _unloadDataViewsInRows:obscuredRows columns:obscuredColumns];
01976
01977 [self _loadDataViewsInRows:previouslyExposedRows columns:newlyExposedColumns];
01978 [self _loadDataViewsInRows:newlyExposedRows columns:previouslyExposedColumns];
01979 [self _loadDataViewsInRows:newlyExposedRows columns:newlyExposedColumns];
01980
01981 _exposedRows = exposedRows;
01982 _exposedColumns = exposedColumns;
01983
01984 [_tableDrawView setFrame:exposedRect];
01985
01986 [_tableDrawView display];
01987
01988
01989
01990 for (var identifier in _cachedDataViews)
01991 {
01992 var dataViews = _cachedDataViews[identifier],
01993 count = dataViews.length;
01994
01995 while (count--)
01996 [dataViews[count] removeFromSuperview];
01997 }
01998
01999 }
02000
02001 - (void)_unloadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
02002 {
02003 if (![rows count] || ![columns count])
02004 return;
02005
02006 var rowArray = [],
02007 columnArray = [];
02008
02009 [rows getIndexes:rowArray maxCount:-1 inIndexRange:nil];
02010 [columns getIndexes:columnArray maxCount:-1 inIndexRange:nil];
02011
02012 var columnIndex = 0,
02013 columnsCount = columnArray.length;
02014
02015 for (; columnIndex < columnsCount; ++columnIndex)
02016 {
02017 var column = columnArray[columnIndex],
02018 tableColumn = _tableColumns[column],
02019 tableColumnUID = [tableColumn UID];
02020
02021 var rowIndex = 0,
02022 rowsCount = rowArray.length;
02023
02024 for (; rowIndex < rowsCount; ++rowIndex)
02025 {
02026 var row = rowArray[rowIndex],
02027 dataView = _dataViewsForTableColumns[tableColumnUID][row];
02028
02029 _dataViewsForTableColumns[tableColumnUID][row] = nil;
02030
02031 [self _enqueueReusableDataView:dataView];
02032 }
02033 }
02034 }
02035
02036 - (void)_loadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
02037 {
02038 if (![rows count] || ![columns count])
02039 return;
02040
02041 var rowArray = [],
02042 rowRects = [],
02043 columnArray = [];
02044
02045 [rows getIndexes:rowArray maxCount:-1 inIndexRange:nil];
02046 [columns getIndexes:columnArray maxCount:-1 inIndexRange:nil];
02047
02048 UPDATE_COLUMN_RANGES_IF_NECESSARY();
02049
02050 var columnIndex = 0,
02051 columnsCount = columnArray.length;
02052
02053 for (; columnIndex < columnsCount; ++columnIndex)
02054 {
02055 var column = columnArray[columnIndex],
02056 tableColumn = _tableColumns[column],
02057 tableColumnUID = [tableColumn UID];
02058
02059 if (!_dataViewsForTableColumns[tableColumnUID])
02060 _dataViewsForTableColumns[tableColumnUID] = [];
02061
02062 var rowIndex = 0,
02063 rowsCount = rowArray.length;
02064
02065 var isColumnSelected = [_selectedColumnIndexes containsIndex:column];
02066 for (; rowIndex < rowsCount; ++rowIndex)
02067 {
02068 var row = rowArray[rowIndex],
02069 dataView = [self _newDataViewForRow:row tableColumn:tableColumn],
02070 isButton = [dataView isKindOfClass:[CPButton class]],
02071 isTextField = [dataView isKindOfClass:[CPTextField class]];
02072
02073 [dataView setFrame:[self frameOfDataViewAtColumn:column row:row]];
02074 [dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]];
02075
02076 if (isColumnSelected || [self isRowSelected:row])
02077 [dataView setThemeState:CPThemeStateSelected];
02078 else
02079 [dataView unsetThemeState:CPThemeStateSelected];
02080
02081 if (_implementedDelegateMethods & CPTableViewDelegate_tableView_willDisplayView_forTableColumn_row_)
02082 [_delegate tableView:self willDisplayView:dataView forTableColumn:tableColumn row:row];
02083
02084 if ([dataView superview] !== self)
02085 [self addSubview:dataView];
02086
02087 _dataViewsForTableColumns[tableColumnUID][row] = dataView;
02088
02089 if (isButton || (_editingCellIndex && _editingCellIndex.x === column && _editingCellIndex.y === row))
02090 {
02091 if (!isButton)
02092 _editingCellIndex = undefined;
02093
02094 if (isTextField)
02095 {
02096 [dataView setEditable:YES];
02097 [dataView setSendsActionOnEndEditing:YES];
02098 [dataView setSelectable:YES];
02099 [dataView selectText:nil];
02100 }
02101
02102 [dataView setTarget:self];
02103 [dataView setAction:@selector(_commitDataViewObjectValue:)];
02104 dataView.tableViewEditedColumnObj = tableColumn;
02105 dataView.tableViewEditedRowIndex = row;
02106 }
02107 else if (isTextField)
02108 {
02109 [dataView setEditable:NO];
02110 [dataView setSelectable:NO];
02111 }
02112 }
02113 }
02114 }
02115
02116 - (void)_layoutDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
02117 {
02118 var rowArray = [],
02119 columnArray = [];
02120
02121 [rows getIndexes:rowArray maxCount:-1 inIndexRange:nil];
02122 [columns getIndexes:columnArray maxCount:-1 inIndexRange:nil];
02123
02124 var columnIndex = 0,
02125 columnsCount = columnArray.length;
02126
02127 for (; columnIndex < columnsCount; ++columnIndex)
02128 {
02129 var column = columnArray[columnIndex],
02130 tableColumn = _tableColumns[column],
02131 tableColumnUID = [tableColumn UID],
02132 dataViewsForTableColumn = _dataViewsForTableColumns[tableColumnUID],
02133 columnRange = _tableColumnRanges[column];
02134
02135 var rowIndex = 0,
02136 rowsCount = rowArray.length;
02137
02138 for (; rowIndex < rowsCount; ++rowIndex)
02139 {
02140 var row = rowArray[rowIndex],
02141 dataView = dataViewsForTableColumn[row];
02142
02143 [dataView setFrame:[self frameOfDataViewAtColumn:column row:row]];
02144 }
02145 }
02146 }
02147
02148 - (void)_commitDataViewObjectValue:(id)sender
02149 {
02150 [_dataSource tableView:self setObjectValue:[sender objectValue] forTableColumn:sender.tableViewEditedColumnObj row:sender.tableViewEditedRowIndex];
02151
02152 if ([sender respondsToSelector:@selector(setEditable:)])
02153 [sender setEditable:NO];
02154 }
02155
02156 - (CPView)_newDataViewForRow:(CPInteger)aRow tableColumn:(CPTableColumn)aTableColumn
02157 {
02158 if ((_implementedDelegateMethods & CPTableViewDelegate_tableView_dataViewForTableColumn_row_))
02159 {
02160 var dataView = [_delegate tableView:self dataViewForTableColumn:aTableColumn row:aRow];
02161 [aTableColumn setDataView:dataView];
02162 }
02163
02164
02165 return [aTableColumn _newDataViewForRow:aRow];
02166 }
02167
02168 - (void)_enqueueReusableDataView:(CPView)aDataView
02169 {
02170
02171 var identifier = aDataView.identifier;
02172
02173 if (!_cachedDataViews[identifier])
02174 _cachedDataViews[identifier] = [aDataView];
02175 else
02176 _cachedDataViews[identifier].push(aDataView);
02177 }
02178
02179 - (void)setFrameSize:(CGSize)aSize
02180 {
02181 [super setFrameSize:aSize];
02182
02183 if (_headerView)
02184 [_headerView setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), _CGRectGetHeight([_headerView frame]))];
02185 }
02186
02187 - (CGRect)exposedClipRect
02188 {
02189 var superview = [self superview];
02190
02191 if (![superview isKindOfClass:[CPClipView class]])
02192 return [self bounds];
02193
02194 return [self convertRect:CGRectIntersection([superview bounds], [self frame]) fromView:superview];
02195 }
02196
02197 - (void)_drawRect:(CGRect)aRect
02198 {
02199
02200
02201
02202 var exposedRect = [self _exposedRect];
02203
02204 [self drawBackgroundInClipRect:exposedRect];
02205 [self drawGridInClipRect:exposedRect];
02206 [self highlightSelectionInClipRect:exposedRect];
02207 }
02208
02209 - (void)drawBackgroundInClipRect:(CGRect)aRect
02210 {
02211 if (!_usesAlternatingRowBackgroundColors)
02212 {
02213 var context = [[CPGraphicsContext currentContext] graphicsPort];
02214
02215 CGContextSetFillColor(context, _backgroundColor);
02216 CGContextFillRect(context, aRect);
02217
02218 return;
02219 }
02220
02221
02222 var rowColors = [self alternatingRowBackgroundColors],
02223 colorCount = [rowColors count];
02224
02225 if (colorCount === 0)
02226 return;
02227
02228 var context = [[CPGraphicsContext currentContext] graphicsPort];
02229
02230 if (colorCount === 1)
02231 {
02232 CGContextSetFillColor(context, rowColors[0]);
02233 CGContextFillRect(context, aRect);
02234
02235 return;
02236 }
02237
02238
02239 var exposedRows = [self rowsInRect:aRect],
02240 firstRow = exposedRows.location,
02241 lastRow = CPMaxRange(exposedRows) - 1,
02242 colorIndex = MIN(exposedRows.length, colorCount),
02243 heightFilled = 0.0;
02244
02245 while (colorIndex--)
02246 {
02247 var row = firstRow - firstRow % colorCount + colorIndex,
02248 fillRect = nil;
02249
02250 CGContextBeginPath(context);
02251
02252 for (; row <= lastRow; row += colorCount)
02253 if (row >= firstRow)
02254 CGContextAddRect(context, CGRectIntersection(aRect, fillRect = [self rectOfRow:row]));
02255
02256 if (row - colorCount === lastRow)
02257 heightFilled = _CGRectGetMaxY(fillRect);
02258
02259 CGContextClosePath(context);
02260
02261 CGContextSetFillColor(context, rowColors[colorIndex]);
02262 CGContextFillPath(context);
02263 }
02264
02265
02266 var totalHeight = _CGRectGetMaxY(aRect);
02267
02268 if (heightFilled >= totalHeight || _rowHeight <= 0.0)
02269 return;
02270
02271 var rowHeight = _rowHeight + _intercellSpacing.height,
02272 fillRect = _CGRectMake(_CGRectGetMinX(aRect), _CGRectGetMinY(aRect) + heightFilled, _CGRectGetWidth(aRect), rowHeight);
02273
02274 for (row = lastRow + 1; heightFilled < totalHeight; ++row)
02275 {
02276 CGContextSetFillColor(context, rowColors[row % colorCount]);
02277 CGContextFillRect(context, fillRect);
02278
02279 heightFilled += rowHeight;
02280 fillRect.origin.y += rowHeight;
02281 }
02282 }
02283
02284 - (void)drawGridInClipRect:(CGRect)aRect
02285 {
02286 var context = [[CPGraphicsContext currentContext] graphicsPort],
02287 gridStyleMask = [self gridStyleMask];
02288
02289 if (!(gridStyleMask & (CPTableViewSolidHorizontalGridLineMask | CPTableViewSolidVerticalGridLineMask)))
02290 return;
02291
02292 CGContextBeginPath(context);
02293
02294 if (gridStyleMask & CPTableViewSolidHorizontalGridLineMask)
02295 {
02296 var exposedRows = [self rowsInRect:aRect];
02297 row = exposedRows.location,
02298 lastRow = CPMaxRange(exposedRows) - 1,
02299 rowY = 0.0,
02300 minX = _CGRectGetMinX(aRect),
02301 maxX = _CGRectGetMaxX(aRect);
02302
02303 for (; row <= lastRow; ++row)
02304 {
02305
02306 var rowRect = [self rectOfRow:row],
02307 rowY = _CGRectGetMaxY(rowRect) - 0.5;
02308
02309 CGContextMoveToPoint(context, minX, rowY);
02310 CGContextAddLineToPoint(context, maxX, rowY);
02311 }
02312
02313 if (_rowHeight > 0.0)
02314 {
02315 var rowHeight = _rowHeight + _intercellSpacing.height,
02316 totalHeight = _CGRectGetMaxY(aRect);
02317
02318 while (rowY < totalHeight)
02319 {
02320 rowY += rowHeight;
02321
02322 CGContextMoveToPoint(context, minX, rowY);
02323 CGContextAddLineToPoint(context, maxX, rowY);
02324 }
02325 }
02326 }
02327
02328 if (gridStyleMask & CPTableViewSolidVerticalGridLineMask)
02329 {
02330 var exposedColumnIndexes = [self columnIndexesInRect:aRect],
02331 columnsArray = [];
02332
02333 [exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:nil];
02334
02335 var columnArrayIndex = 0,
02336 columnArrayCount = columnsArray.length,
02337 minY = _CGRectGetMinY(aRect),
02338 maxY = _CGRectGetMaxY(aRect);
02339
02340
02341 for (; columnArrayIndex < columnArrayCount; ++columnArrayIndex)
02342 {
02343 var columnRect = [self rectOfColumn:columnsArray[columnArrayIndex]],
02344 columnX = _CGRectGetMaxX(columnRect) + 0.5;
02345
02346 CGContextMoveToPoint(context, columnX, minY);
02347 CGContextAddLineToPoint(context, columnX, maxY);
02348 }
02349 }
02350
02351 CGContextClosePath(context);
02352 CGContextSetStrokeColor(context, _gridColor);
02353 CGContextStrokePath(context);
02354 }
02355
02356
02357 - (void)highlightSelectionInClipRect:(CGRect)aRect
02358 {
02359 var context = [[CPGraphicsContext currentContext] graphicsPort],
02360 indexes = [],
02361 rectSelector = @selector(rectOfRow:);
02362
02363 if ([_selectedRowIndexes count] >= 1)
02364 {
02365 var exposedRows = [CPIndexSet indexSetWithIndexesInRange:[self rowsInRect:aRect]],
02366 firstRow = [exposedRows firstIndex],
02367 exposedRange = CPMakeRange(firstRow, [exposedRows lastIndex] - firstRow + 1);
02368
02369 [_selectedRowIndexes getIndexes:indexes maxCount:-1 inIndexRange:exposedRange];
02370 }
02371
02372 else if ([_selectedColumnIndexes count] >= 1)
02373 {
02374 rectSelector = @selector(rectOfColumn:);
02375
02376 var exposedColumns = [self columnIndexesInRect:aRect],
02377 firstColumn = [exposedColumns firstIndex],
02378 exposedRange = CPMakeRange(firstColumn, [exposedColumns lastIndex] - firstColumn + 1);
02379
02380 [_selectedColumnIndexes getIndexes:indexes maxCount:-1 inIndexRange:exposedRange];
02381 }
02382
02383 var count = count2 = [indexes count];
02384
02385 if (!count)
02386 return;
02387
02388 var drawGradient = (_selectionHighlightStyle === CPTableViewSelectionHighlightStyleSourceList && [_selectedRowIndexes count] >= 1);
02389
02390 var deltaHeight = 0.5 * (_gridStyleMask & CPTableViewSolidHorizontalGridLineMask);
02391
02392 CGContextBeginPath(context);
02393 while (count--)
02394 {
02395 var rowRect = CGRectIntersection(objj_msgSend(self, rectSelector, indexes[count]), aRect);
02396 CGContextAddRect(context, rowRect);
02397
02398 if (drawGradient)
02399 {
02400 var minX = _CGRectGetMinX(rowRect),
02401 minY = _CGRectGetMinY(rowRect),
02402 maxX = _CGRectGetMaxX(rowRect),
02403 maxY = _CGRectGetMaxY(rowRect) - deltaHeight;
02404
02405 CGContextDrawLinearGradient(context, _sourceListActiveGradient, rowRect.origin, CGPointMake(minX, maxY), 0);
02406 CGContextClosePath(context);
02407
02408 CGContextBeginPath(context);
02409 CGContextMoveToPoint(context, minX, minY);
02410 CGContextAddLineToPoint(context, maxX, minY);
02411 CGContextClosePath(context);
02412 CGContextSetStrokeColor(context, _sourceListActiveTopLineColor);
02413 CGContextStrokePath(context);
02414
02415 CGContextBeginPath(context);
02416 CGContextMoveToPoint(context, minX, maxY);
02417 CGContextAddLineToPoint(context, maxX, maxY - 1);
02418 CGContextClosePath(context);
02419 CGContextSetStrokeColor(context, _sourceListActiveBottomLineColor);
02420 CGContextStrokePath(context);
02421 }
02422 }
02423
02424 CGContextClosePath(context);
02425
02426 if (!drawGradient)
02427 {
02428 [[CPColor selectionColor] setFill];
02429 CGContextFillPath(context);
02430 }
02431
02432 CGContextBeginPath(context);
02433 gridStyleMask = [self gridStyleMask];
02434 for(var i=0; i < count2; i++)
02435 {
02436 var rect = objj_msgSend(self, rectSelector, indexes[i]),
02437 minX = CGRectGetMinX(rect) - 0.5,
02438 maxX = CGRectGetMaxX(rect) - 0.5,
02439 minY = CGRectGetMinY(rect) - 0.5,
02440 maxY = CGRectGetMaxY(rect) - 0.5;
02441
02442 if ([_selectedRowIndexes count] >= 1 && gridStyleMask & CPTableViewSolidVerticalGridLineMask)
02443 {
02444 var exposedColumns = [self columnIndexesInRect:aRect],
02445 exposedColumnIndexes = [],
02446 firstExposedColumn = [exposedColumns firstIndex],
02447 exposedRange = CPMakeRange(firstExposedColumn, [exposedColumns lastIndex] - firstExposedColumn + 1);
02448 [exposedColumns getIndexes:exposedColumnIndexes maxCount:-1 inIndexRange:exposedRange];
02449 var exposedColumnCount = [exposedColumnIndexes count];
02450
02451 for(var c = firstExposedColumn; c < exposedColumnCount; c++)
02452 {
02453
02454 var colRect = [self rectOfColumn:exposedColumnIndexes[c]],
02455 colX = CGRectGetMaxX(colRect) + 0.5;
02456
02457 CGContextMoveToPoint(context, colX, minY);
02458 CGContextAddLineToPoint(context, colX, maxY);
02459 }
02460
02461 }
02462
02463
02464 if([indexes containsObject:indexes[i]+1])
02465 {
02466 CGContextMoveToPoint(context, minX, maxY);
02467 CGContextAddLineToPoint(context, maxX, maxY);
02468 }
02469 }
02470
02471 CGContextClosePath(context);
02472 CGContextSetStrokeColor(context, [CPColor colorWithHexString:@"e5e5e5"]);
02473 CGContextStrokePath(context);
02474 }
02475
02476 - (void)layoutSubviews
02477 {
02478 [self load];
02479 }
02480
02481 - (void)viewWillMoveToSuperview:(CPView)aView
02482 {
02483 var superview = [self superview],
02484 defaultCenter = [CPNotificationCenter defaultCenter];
02485
02486 if (superview)
02487 {
02488 [defaultCenter
02489 removeObserver:self
02490 name:CPViewFrameDidChangeNotification
02491 object:superview];
02492
02493 [defaultCenter
02494 removeObserver:self
02495 name:CPViewBoundsDidChangeNotification
02496 object:superview];
02497 }
02498
02499 if (aView)
02500 {
02501 [aView setPostsFrameChangedNotifications:YES];
02502 [aView setPostsBoundsChangedNotifications:YES];
02503
02504 [defaultCenter
02505 addObserver:self
02506 selector:@selector(superviewFrameChanged:)
02507 name:CPViewFrameDidChangeNotification
02508 object:aView];
02509
02510 [defaultCenter
02511 addObserver:self
02512 selector:@selector(superviewBoundsChanged:)
02513 name:CPViewBoundsDidChangeNotification
02514 object:aView];
02515 }
02516 }
02517
02518 - (void)superviewBoundsChanged:(CPNotification)aNotification
02519 {
02520 [self setNeedsDisplay:YES];
02521 [self setNeedsLayout];
02522 }
02523
02524 - (void)superviewFrameChanged:(CPNotification)aNotification
02525 {
02526 [self tile];
02527 }
02528
02529
02530
02531
02532 - (BOOL)tracksMouseOutsideOfFrame
02533 {
02534 return YES;
02535 }
02536
02537
02538
02539
02540 - (BOOL)startTrackingAt:(CGPoint)aPoint
02541 {
02542 var row = [self rowAtPoint:aPoint];
02543
02544
02545 if (row < 0 && _allowsEmptySelection)
02546 [self selectRowIndexes:[CPIndexSet indexSet] byExtendingSelection:NO];
02547
02548 [self _noteSelectionIsChanging];
02549
02550 if ([self mouseDownFlags] & CPShiftKeyMask)
02551 _selectionAnchorRow = (ABS([_selectedRowIndexes firstIndex] - row) < ABS([_selectedRowIndexes lastIndex] - row)) ?
02552 [_selectedRowIndexes firstIndex] : [_selectedRowIndexes lastIndex];
02553 else
02554 _selectionAnchorRow = row;
02555
02556
02557
02558 _startTrackingPoint = aPoint;
02559 _startTrackingTimestamp = new Date();
02560
02561 if (_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_)
02562 _trackingPointMovedOutOfClickSlop = NO;
02563
02564
02565
02566 if (row >=0 && !(_implementedDataSourceMethods & CPTableViewDataSource_tableView_writeRowsWithIndexes_toPasteboard_))
02567 [self _updateSelectionWithMouseAtRow:row];
02568
02569 [[self window] makeFirstResponder:self];
02570 return YES;
02571 }
02572
02573
02574
02575
02576 - (void)trackMouse:(CPEvent)anEvent
02577 {
02578
02579 if (![_draggedRowIndexes count])
02580 [super trackMouse:anEvent];
02581 else
02582 [CPApp sendEvent:anEvent];
02583 }
02584
02585
02586
02587
02588 - (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
02589 {
02590 var row = [self rowAtPoint:aPoint];
02591
02592
02593
02594 if(!_isSelectingSession && _implementedDataSourceMethods & CPTableViewDataSource_tableView_writeRowsWithIndexes_toPasteboard_)
02595 {
02596 if (row >= 0 && (ABS(_startTrackingPoint.x - aPoint.x) > 3 || (_verticalMotionCanDrag && ABS(_startTrackingPoint.y - aPoint.y) > 3)) ||
02597 ([_selectedRowIndexes containsIndex:row]))
02598 {
02599 if ([_selectedRowIndexes containsIndex:row])
02600 _draggedRowIndexes = [[CPIndexSet alloc] initWithIndexSet:_selectedRowIndexes];
02601 else
02602 _draggedRowIndexes = [CPIndexSet indexSetWithIndex:row];
02603
02604
02605
02606 var pboard = [CPPasteboard pasteboardWithName:CPDragPboard];
02607
02608 if ([self canDragRowsWithIndexes:_draggedRowIndexes atPoint:aPoint] && [_dataSource tableView:self writeRowsWithIndexes:_draggedRowIndexes toPasteboard:pboard])
02609 {
02610 var currentEvent = [CPApp currentEvent],
02611 offset = CPPointMakeZero(),
02612 tableColumns = [_tableColumns objectsAtIndexes:_exposedColumns];
02613
02614
02615
02616
02617 var view = [self dragViewForRowsWithIndexes:_draggedRowIndexes
02618 tableColumns:tableColumns
02619 event:currentEvent
02620 offset:offset];
02621
02622 if (!view)
02623 {
02624 var image = [self dragImageForRowsWithIndexes:_draggedRowIndexes
02625 tableColumns:tableColumns
02626 event:currentEvent
02627 offset:offset];
02628 view = [[CPImageView alloc] initWithFrame:CPMakeRect(0, 0, [image size].width, [image size].height)];
02629 [view setImage:image];
02630 }
02631
02632 var bounds = [view bounds];
02633 var viewLocation = CPPointMake(aPoint.x - CGRectGetWidth(bounds)/2 + offset.x, aPoint.y - CGRectGetHeight(bounds)/2 + offset.y);
02634 [self dragView:view at:viewLocation offset:CPPointMakeZero() event:[CPApp currentEvent] pasteboard:pboard source:self slideBack:YES];
02635 _startTrackingPoint = nil;
02636
02637 return NO;
02638 }
02639
02640
02641 _draggedRowIndexes = [CPIndexSet indexSet];
02642 }
02643 else if (ABS(_startTrackingPoint.x - aPoint.x) < 5 && ABS(_startTrackingPoint.y - aPoint.y) < 5)
02644 return YES;
02645 }
02646
02647 _isSelectingSession = YES;
02648 if(row >= 0)
02649 [self _updateSelectionWithMouseAtRow:row];
02650
02651 if ((_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_)
02652 && !_trackingPointMovedOutOfClickSlop)
02653 {
02654 var CLICK_SPACE_DELTA = 5.0;
02655 if (ABS(aPoint.x - _startTrackingPoint.x) > CLICK_SPACE_DELTA
02656 || ABS(aPoint.y - _startTrackingPoint.y) > CLICK_SPACE_DELTA)
02657 {
02658 _trackingPointMovedOutOfClickSlop = YES;
02659 }
02660 }
02661
02662 return YES;
02663 }
02664
02668 - (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
02669 {
02670 _isSelectingSession = NO;
02671
02672 var CLICK_TIME_DELTA = 1000,
02673 columnIndex,
02674 column,
02675 rowIndex,
02676 shouldEdit = YES;
02677
02678 if(_implementedDataSourceMethods & CPTableViewDataSource_tableView_writeRowsWithIndexes_toPasteboard_)
02679 {
02680 rowIndex = [self rowAtPoint:aPoint];
02681 if (rowIndex !== -1)
02682 {
02683 if ([_draggedRowIndexes count] > 0)
02684 {
02685 _draggedRowIndexes = [CPIndexSet indexSet];
02686 return;
02687 }
02688
02689 _previouslySelectedRowIndexes = [_selectedRowIndexes copy];
02690 [self _updateSelectionWithMouseAtRow:rowIndex];
02691 }
02692 }
02693
02694 if (mouseIsUp
02695 && (_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_)
02696 && !_trackingPointMovedOutOfClickSlop
02697 && ([[CPApp currentEvent] clickCount] > 1))
02698 {
02699 columnIndex = [self columnAtPoint:lastPoint];
02700 if (columnIndex !== -1)
02701 {
02702 column = _tableColumns[columnIndex];
02703 if ([column isEditable])
02704 {
02705 rowIndex = [self rowAtPoint:aPoint];
02706 if (rowIndex !== -1)
02707 {
02708 if (_implementedDelegateMethods & CPTableViewDelegate_tableView_shouldEditTableColumn_row_)
02709 shouldEdit = [_delegate tableView:self shouldEditTableColumn:column row:rowIndex];
02710 if (shouldEdit)
02711 {
02712 _editingCellIndex = CGPointMake(columnIndex, rowIndex);
02713 [self reloadDataForRowIndexes:[CPIndexSet indexSetWithIndex:rowIndex]
02714 columnIndexes:[CPIndexSet indexSetWithIndex:columnIndex]];
02715
02716 return;
02717 }
02718 }
02719 }
02720 }
02721
02722 }
02723
02724
02725 if([[CPApp currentEvent] clickCount] === 2 && _doubleAction && _target)
02726 [self sendAction:_doubleAction to:_target];
02727 }
02728
02729
02730
02731
02732 - (CPDragOperation)draggingEntered:(id)sender
02733 {
02734 var location = [self convertPoint:[sender draggingLocation] fromView:nil],
02735 dropOperation = [self _proposedDropOperationAtPoint:location],
02736 row = [self _proposedRowAtPoint:location];
02737
02738 if(_retargetedDropRow !== nil)
02739 row = _retargetedDropRow;
02740
02741 var draggedTypes = [self registeredDraggedTypes],
02742 count = [draggedTypes count],
02743 i = 0;
02744
02745 for (; i < count; i++)
02746 {
02747 if ([[[sender draggingPasteboard] types] containsObject:[draggedTypes objectAtIndex: i]])
02748 return [self _validateDrop:sender proposedRow:row proposedDropOperation:dropOperation];
02749 }
02750
02751 return CPDragOperationNone;
02752 }
02753
02754
02755
02756
02757 - (void)draggingExited:(id)sender
02758 {
02759 [_dropOperationFeedbackView removeFromSuperview];
02760 }
02761
02762
02763
02764
02765 - (void)draggingEnded:(id)sender
02766 {
02767 [self _draggingEnded];
02768 }
02769
02770 - (void)_draggingEnded
02771 {
02772 _retargetedDropOperation = nil;
02773 _retargetedDropRow = nil;
02774 _draggedRowIndexes = [CPIndexSet indexSet];
02775 [_dropOperationFeedbackView removeFromSuperview];
02776 }
02777
02778
02779
02780 - (BOOL)wantsPeriodicDraggingUpdates
02781 {
02782 return YES;
02783 }
02784
02785
02786
02787
02788 - (CPTableViewDropOperation)_proposedDropOperationAtPoint:(CGPoint)theDragPoint
02789 {
02790 if(_retargetedDropOperation !== nil)
02791 return _retargetedDropOperation;
02792
02793 var row = [self _proposedRowAtPoint:theDragPoint],
02794 rowRect = [self rectOfRow:row];
02795
02796
02797
02798 if ([self intercellSpacing].height < 5.0)
02799 rowRect = CPRectInset(rowRect, 0.0, 5.0 - [self intercellSpacing].height);
02800
02801
02802
02803
02804 if (CGRectContainsPoint(rowRect, theDragPoint) && row < _numberOfRows)
02805 return CPTableViewDropOn;
02806
02807 return CPTableViewDropAbove;
02808 }
02809
02810
02811
02812
02813 - (CPInteger)_proposedRowAtPoint:(CGPoint)dragPoint
02814 {
02815
02816
02817 var row = FLOOR(dragPoint.y / ( _rowHeight + _intercellSpacing.height ));
02818
02819
02820 var lowerRow = row + 1,
02821 rect = [self rectOfRow:row],
02822 lowerRect = [self rectOfRow:lowerRow];
02823
02824 if (ABS(CPRectGetMinY(lowerRect) - dragPoint.y) < ABS(dragPoint.y - CPRectGetMinY(rect)))
02825 row = lowerRow;
02826
02827 if (row >= [self numberOfRows])
02828 row = [self numberOfRows];
02829
02830 return row;
02831 }
02832
02833 - (void)_validateDrop:(id)info proposedRow:(CPInteger)row proposedDropOperation:(CPTableViewDropOperation)dropOperation
02834 {
02835 if(_implementedDataSourceMethods & CPTableViewDataSource_tableView_validateDrop_proposedRow_proposedDropOperation_)
02836 return [_dataSource tableView:self validateDrop:info proposedRow:row proposedDropOperation:dropOperation];
02837
02838 return CPDragOperationNone;
02839 }
02840
02841 - (CPRect)_rectForDropHighlightViewOnRow:(int)theRowIndex
02842 {
02843 if (theRowIndex >= [self numberOfRows])
02844 theRowIndex = [self numberOfRows] - 1;
02845
02846 return [self rectOfRow:theRowIndex];
02847 }
02848
02849 - (CPRect)_rectForDropHighlightViewBetweenUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex offset:(CPPoint)theOffset
02850 {
02851 if (theLowerRowIndex > [self numberOfRows])
02852 theLowerRowIndex = [self numberOfRows];
02853
02854 return [self rectOfRow:theLowerRowIndex];
02855 }
02856
02857 - (CPDragOperation)draggingUpdated:(id)sender
02858 {
02859 var location = [self convertPoint:[sender draggingLocation] fromView:nil],
02860 dropOperation = [self _proposedDropOperationAtPoint:location],
02861 numberOfRows = [self numberOfRows];
02862
02863 var row = [self _proposedRowAtPoint:location],
02864 dragOperation = [self _validateDrop:sender proposedRow:row proposedDropOperation:dropOperation];
02865 exposedClipRect = [self exposedClipRect];
02866
02867 if(_retargetedDropRow !== nil)
02868 row = _retargetedDropRow;
02869
02870
02871 if (dropOperation === CPTableViewDropOn && row >= [self numberOfRows])
02872 row = [self numberOfRows] - 1;
02873
02874 var rect = CPRectMakeZero();
02875
02876 if (row === -1)
02877 rect = exposedClipRect;
02878
02879 else if (dropOperation === CPTableViewDropAbove)
02880 rect = [self _rectForDropHighlightViewBetweenUpperRow:row - 1 andLowerRow:row offset:location];
02881
02882 else
02883 rect = [self _rectForDropHighlightViewOnRow:row];
02884
02885 [_dropOperationFeedbackView setDropOperation:row !== -1 ? dropOperation : CPDragOperationNone];
02886 [_dropOperationFeedbackView setHidden:(dragOperation == CPDragOperationNone)];
02887 [_dropOperationFeedbackView setFrame:rect];
02888 [_dropOperationFeedbackView setCurrentRow:row];
02889 [self addSubview:_dropOperationFeedbackView];
02890
02891
02892
02893 if (row > 0 && location.y - CGRectGetMinY(exposedClipRect) < _rowHeight)
02894 [self scrollRowToVisible:row - 1];
02895 else if (row < numberOfRows && CGRectGetMaxY(exposedClipRect) - location.y < _rowHeight)
02896 [self scrollRowToVisible:row + 1];
02897
02898 return dragOperation;
02899 }
02900
02901
02902
02903
02904 - (BOOL)prepareForDragOperation:(id)sender
02905 {
02906
02907
02908 [_dropOperationFeedbackView removeFromSuperview];
02909
02910 return (_implementedDataSourceMethods & CPTableViewDataSource_tableView_validateDrop_proposedRow_proposedDropOperation_);
02911 }
02912
02913
02914
02915
02916 - (BOOL)performDragOperation:(id)sender
02917 {
02918 var location = [self convertPoint:[sender draggingLocation] fromView:nil];
02919 operation = [self _proposedDropOperationAtPoint:location],
02920 row = _retargetedDropRow;
02921
02922 if(row === nil)
02923 var row = [self _proposedRowAtPoint:location];
02924
02925 return [_dataSource tableView:self acceptDrop:sender row:row dropOperation:operation];
02926 }
02927
02928
02929
02930
02931 - (void)concludeDragOperation:(id)sender
02932 {
02933 [self reloadData];
02934 }
02935
02936
02937
02938
02939 - (void)draggedImage:(CPImage)anImage endedAt:(CGPoint)aLocation operation:(CPDragOperation)anOperation
02940 {
02941 if([_dataSource respondsToSelector:@selector(tableView:didEndDraggedImage:atPosition:operation:)])
02942 [_dataSource tableView:self didEndDraggedImage:anImage atPosition:aLocation operation:anOperation];
02943 }
02944
02945
02946
02947
02948
02949 - (void)draggedView:(CPImage)aView endedAt:(CGPoint)aLocation operation:(CPDragOperation)anOperation
02950 {
02951 [self _draggingEnded];
02952 [self draggedImage:aView endedAt:aLocation operation:anOperation];
02953 }
02954
02955 - (void)_updateSelectionWithMouseAtRow:(CPInteger)aRow
02956 {
02957
02958 if(aRow < 0)
02959 return;
02960
02961 var newSelection,
02962 shouldExtendSelection = NO;
02963
02964 if ([self mouseDownFlags] & (CPCommandKeyMask | CPControlKeyMask | CPAlternateKeyMask))
02965 {
02966 if ([_selectedRowIndexes containsIndex:aRow])
02967 {
02968 newSelection = [_selectedRowIndexes copy];
02969
02970 [newSelection removeIndex:aRow];
02971 }
02972
02973 else if (_allowsMultipleSelection)
02974 {
02975 newSelection = [_selectedRowIndexes copy];
02976
02977 [newSelection addIndex:aRow];
02978 }
02979
02980 else
02981 newSelection = [CPIndexSet indexSetWithIndex:aRow];
02982 }
02983
02984 else if (_allowsMultipleSelection)
02985 {
02986 newSelection = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(MIN(aRow, _selectionAnchorRow), ABS(aRow - _selectionAnchorRow) + 1)];
02987 shouldExtendSelection = [self mouseDownFlags] & CPShiftKeyMask &&
02988 ((_lastSelectedRow == [_selectedRowIndexes lastIndex] && aRow > _lastSelectedRow) ||
02989 (_lastSelectedRow == [_selectedRowIndexes firstIndex] && aRow < _lastSelectedRow));
02990 }
02991
02992 else if (aRow >= 0 && aRow < _numberOfRows)
02993 newSelection = [CPIndexSet indexSetWithIndex:aRow];
02994
02995 else
02996 newSelection = [CPIndexSet indexSet];
02997
02998 if ([newSelection isEqualToIndexSet:_selectedRowIndexes])
02999 return;
03000
03001 if (_implementedDelegateMethods & CPTableViewDelegate_selectionShouldChangeInTableView_ &&
03002 ![_delegate selectionShouldChangeInTableView:self])
03003 return;
03004
03005 if (_implementedDelegateMethods & CPTableViewDelegate_tableView_selectionIndexesForProposedSelection_)
03006 newSelection = [_delegate tableView:self selectionIndexesForProposedSelection:newSelection];
03007
03008 if (_implementedDelegateMethods & CPTableViewDelegate_tableView_shouldSelectRow_)
03009 {
03010 var indexArray = [];
03011
03012 [newSelection getIndexes:indexArray maxCount:-1 inIndexRange:nil];
03013
03014 var indexCount = indexArray.length;
03015
03016 while (indexCount--)
03017 {
03018 var index = indexArray[indexCount];
03019
03020 if (![_delegate tableView:self shouldSelectRow:index])
03021 [newSelection removeIndex:index];
03022 }
03023 }
03024
03025 _lastSelectedRow = ([newSelection count] > 0) ? aRow : -1;
03026
03027
03028 if (!_allowsEmptySelection && [newSelection count] === 0)
03029 return;
03030
03031 if ([newSelection isEqualToIndexSet:_selectedRowIndexes])
03032 return;
03033
03034 [self selectRowIndexes:newSelection byExtendingSelection:shouldExtendSelection];
03035 }
03036
03037 - (void)_noteSelectionIsChanging
03038 {
03039 [[CPNotificationCenter defaultCenter]
03040 postNotificationName:CPTableViewSelectionIsChangingNotification
03041 object:self
03042 userInfo:nil];
03043 }
03044
03045 - (void)_noteSelectionDidChange
03046 {
03047 [[CPNotificationCenter defaultCenter]
03048 postNotificationName:CPTableViewSelectionDidChangeNotification
03049 object:self
03050 userInfo:nil];
03051 }
03052
03053 - (BOOL)becomeFirstResponder
03054 {
03055 return YES;
03056 }
03057
03058 - (BOOL)acceptsFirstResponder
03059 {
03060 return YES;
03061 }
03062
03063 - (void)keyDown:(CPEvent)anEvent
03064 {
03065 [self interpretKeyEvents:[CPArray arrayWithObject:anEvent]];
03066 }
03067
03068 - (void)moveDown:(id)sender
03069 {
03070 if (_implementedDelegateMethods & CPTableViewDelegate_selectionShouldChangeInTableView_ &&
03071 ![_delegate selectionShouldChangeInTableView:self])
03072 return;
03073
03074 var anEvent = [CPApp currentEvent];
03075 if([[self selectedRowIndexes] count] > 0)
03076 {
03077 var extend = NO;
03078
03079 if(([anEvent modifierFlags] & CPShiftKeyMask) && _allowsMultipleSelection)
03080 extend = YES;
03081
03082 var i = [[self selectedRowIndexes] lastIndex];
03083 if(i<[self numberOfRows] - 1)
03084 i++;
03085 }
03086 else
03087 {
03088 var extend = NO;
03089
03090 if([self numberOfRows] > 0)
03091 var i = 0;
03092 }
03093
03094
03095 if(_implementedDelegateMethods & CPTableViewDelegate_tableView_shouldSelectRow_)
03096 {
03097
03098 while((![_delegate tableView:self shouldSelectRow:i]) && i<[self numberOfRows])
03099 {
03100
03101 i++;
03102 }
03103
03104
03105 if(![_delegate tableView:self shouldSelectRow:i])
03106 return;
03107 }
03108
03109 [self selectRowIndexes:[CPIndexSet indexSetWithIndex:i] byExtendingSelection:extend];
03110
03111 if(i >= 0)
03112 [self scrollRowToVisible:i];
03113 }
03114
03115 - (void)moveUp:(id)sender
03116 {
03117 if (_implementedDelegateMethods & CPTableViewDelegate_selectionShouldChangeInTableView_ &&
03118 ![_delegate selectionShouldChangeInTableView:self])
03119 return;
03120
03121 var anEvent = [CPApp currentEvent];
03122 if([[self selectedRowIndexes] count] > 0)
03123 {
03124 var extend = NO;
03125
03126 if(([anEvent modifierFlags] & CPShiftKeyMask) && _allowsMultipleSelection)
03127 extend = YES;
03128
03129 var i = [[self selectedRowIndexes] firstIndex];
03130 if(i > 0)
03131 i--;
03132 }
03133 else
03134 {
03135 var extend = NO;
03136
03137 if([self numberOfRows] > 0)
03138 var i = [self numberOfRows] - 1;
03139 }
03140
03141
03142 if(_implementedDelegateMethods & CPTableViewDelegate_tableView_shouldSelectRow_)
03143 {
03144
03145 while((![_delegate tableView:self shouldSelectRow:i]) && i > 0)
03146 {
03147
03148 i--;
03149 }
03150
03151
03152 if(![_delegate tableView:self shouldSelectRow:i])
03153 return;
03154 }
03155
03156 [self selectRowIndexes:[CPIndexSet indexSetWithIndex:i] byExtendingSelection:extend];
03157
03158 if(i >= 0)
03159 [self scrollRowToVisible:i];
03160 }
03161
03162 - (void)deleteBackward:(id)sender
03163 {
03164 if([_delegate respondsToSelector: @selector(tableViewDeleteKeyPressed:)])
03165 [_delegate tableViewDeleteKeyPressed:self];
03166 }
03167
03168 @end
03169
03170 var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
03171 CPTableViewDelegateKey = @"CPTableViewDelegateKey",
03172 CPTableViewHeaderViewKey = @"CPTableViewHeaderViewKey",
03173 CPTableViewTableColumnsKey = @"CPTableViewTableColumnsKey",
03174 CPTableViewRowHeightKey = @"CPTableViewRowHeightKey",
03175 CPTableViewIntercellSpacingKey = @"CPTableViewIntercellSpacingKey",
03176 CPTableViewMultipleSelectionKey = @"CPTableViewMultipleSelectionKey",
03177 CPTableViewEmptySelectionKey = @"CPTableViewEmptySelectionKey",
03178 CPTableViewColumnReorderingKey = @"CPTableViewColumnReorderingKey",
03179 CPTableViewColumnResizingKey = @"CPTableViewColumnResizingKey",
03180 CPTableViewColumnSelectionKey = @"CPTableViewColumnSelectionKey",
03181 CPTableViewGridColorKey = @"CPTableViewGridColorKey",
03182 CPTableViewGridStyleMaskKey = @"CPTableViewGridStyleMaskKey",
03183 CPTableViewUsesAlternatingBackgroundKey = @"CPTableViewUsesAlternatingBackgroundKey",
03184 CPTableViewAlternatingRowColorsKey = @"CPTableViewAlternatingRowColorsKey",
03185 CPTableViewHeaderViewKey = @"CPTableViewHeaderViewKey",
03186 CPTableViewCornerViewKey = @"CPTableViewCornerViewKey";
03187
03188 @implementation CPTableView (CPCoding)
03189
03190 - (id)initWithCoder:(CPCoder)aCoder
03191 {
03192 self = [super initWithCoder:aCoder];
03193
03194 if (self)
03195 {
03196
03197 _allowsColumnReordering = [aCoder decodeBoolForKey:CPTableViewColumnReorderingKey];
03198 _allowsColumnResizing = [aCoder decodeBoolForKey:CPTableViewColumnResizingKey];
03199 _allowsMultipleSelection = [aCoder decodeBoolForKey:CPTableViewMultipleSelectionKey];
03200 _allowsEmptySelection = [aCoder decodeBoolForKey:CPTableViewEmptySelectionKey];
03201 _allowsColumnSelection = [aCoder decodeBoolForKey:CPTableViewColumnSelectionKey];
03202
03203 _tableViewFlags = 0;
03204
03205
03206 _selectionHighlightStyle = CPTableViewSelectionHighlightStyleRegular;
03207
03208 _usesAlternatingRowBackgroundColors = [aCoder decodeBoolForKey:CPTableViewUsesAlternatingBackgroundKey];
03209 [self setAlternatingRowBackgroundColors:[[CPColor whiteColor], [CPColor colorWithHexString:@"e4e7ff"]]];
03210
03211 _tableColumns = [aCoder decodeObjectForKey:CPTableViewTableColumnsKey];
03212 [_tableColumns makeObjectsPerformSelector:@selector(setTableView:) withObject:self];
03213
03214 _tableColumnRanges = [];
03215 _dirtyTableColumnRangeIndex = 0;
03216 _numberOfHiddenColumns = 0;
03217
03218 _objectValues = { };
03219 _dataViewsForTableColumns = { };
03220 _dataViews= [];
03221 _numberOfRows = 0;
03222 _exposedRows = [CPIndexSet indexSet];
03223 _exposedColumns = [CPIndexSet indexSet];
03224 _cachedDataViews = { };
03225 _rowHeight = [aCoder decodeFloatForKey:CPTableViewRowHeightKey];
03226
03227 if ([aCoder containsValueForKey:CPTableViewIntercellSpacingKey])
03228 _intercellSpacing = [aCoder decodeSizeForKey:CPTableViewIntercellSpacingKey];
03229 else
03230 _intercellSpacing = _CGSizeMake(0.0, 0.0);
03231
03232 _gridColor = [aCoder decodeObjectForKey:CPTableViewGridColorKey] || [CPColor grayColor];
03233 _gridStyleMask = [aCoder decodeIntForKey:CPTableViewGridStyleMaskKey] || CPTableViewGridNone;
03234
03235 _alternatingRowBackgroundColors = [aCoder decodeObjectForKey:CPTableViewAlternatingRowColorsKey];
03236 _usesAlternatingRowBackgroundColors = [aCoder decodeObjectForKey:CPTableViewUsesAlternatingBackgroundKey]
03237
03238 _headerView = [aCoder decodeObjectForKey:CPTableViewHeaderViewKey];
03239 _cornerView = [aCoder decodeObjectForKey:CPTableViewCornerViewKey];
03240
03241 _selectedColumnIndexes = [CPIndexSet indexSet];
03242 _selectedRowIndexes = [CPIndexSet indexSet];
03243
03244 _dataSource = [aCoder decodeObjectForKey:CPTableViewDataSourceKey];
03245 _delegate = [aCoder decodeObjectForKey:CPTableViewDelegateKey];
03246
03247 _tableDrawView = [[_CPTableDrawView alloc] initWithTableView:self];
03248 [_tableDrawView setBackgroundColor:[CPColor clearColor]];
03249 [self addSubview:_tableDrawView];
03250 [self _init];
03251
03252 [self viewWillMoveToSuperview:[self superview]];
03253 }
03254
03255 return self;
03256 }
03257
03258 - (void)encodeWithCoder:(CPCoder)aCoder
03259 {
03260 [super encodeWithCoder:aCoder];
03261
03262 [aCoder encodeObject:_dataSource forKey:CPTableViewDataSourceKey];
03263 [aCoder encodeObject:_delegate forKey:CPTableViewDelegateKey];
03264
03265 [aCoder encodeFloat:_rowHeight forKey:CPTableViewRowHeightKey];
03266 [aCoder encodeSize:_intercellSpacing forKey:CPTableViewIntercellSpacingKey];
03267
03268 [aCoder encodeBool:_allowsMultipleSelection forKey:CPTableViewMultipleSelectionKey];
03269 [aCoder encodeBool:_allowsEmptySelection forKey:CPTableViewEmptySelectionKey];
03270 [aCoder encodeBool:_allowsColumnReordering forKey:CPTableViewColumnReorderingKey];
03271 [aCoder encodeBool:_allowsColumnResizing forKey:CPTableViewColumnResizingKey];
03272 [aCoder encodeBool:_allowsColumnSelection forKey:CPTableViewColumnSelectionKey];
03273
03274 [aCoder encodeObject:_tableColumns forKey:CPTableViewTableColumnsKey];
03275
03276 [aCoder encodeObject:_gridColor forKey:CPTableViewGridColorKey];
03277 [aCoder encodeInt:_gridStyleMask forKey:CPTableViewGridStyleMaskKey];
03278
03279 [aCoder encodeBool:_usesAlternatingRowBackgroundColors forKey:CPTableViewUsesAlternatingBackgroundKey];
03280 [aCoder encodeObject:_alternatingRowBackgroundColors forKey:CPTableViewAlternatingRowColorsKey]
03281
03282 [aCoder encodeObject:_cornerView forKey:CPTableViewCornerViewKey];
03283 [aCoder encodeObject:_headerView forKey:CPTableViewHeaderViewKey];
03284 }
03285
03286 @end
03287
03288 @implementation CPColor (tableview)
03289
03290 + (CPColor)selectionColor
03291 {
03292 return [CPColor colorWithHexString:@"5f83b9"];
03293 }
03294
03295 + (CPColor)selectionColorSourceView
03296 {
03297 return [CPColor colorWithPatternImage:[[CPImage alloc] initByReferencingFile:@"Resources/tableviewselection.png" size:CGSizeMake(6,22)]];
03298 }
03299
03300 @end
03301
03302 @implementation CPIndexSet (tableview)
03303
03304 - (void)removeMatches:otherSet
03305 {
03306 var firstindex = [self firstIndex];
03307 var index = MIN(firstindex,[otherSet firstIndex]);
03308 var switchFlag = (index == firstindex);
03309 while(index != CPNotFound)
03310 {
03311 var indexSet = (switchFlag) ? otherSet : self;
03312 otherIndex = [indexSet indexGreaterThanOrEqualToIndex:index];
03313 if (otherIndex == index)
03314 {
03315 [self removeIndex:index];
03316 [otherSet removeIndex:index];
03317 }
03318 index = otherIndex;
03319 switchFlag = !switchFlag;
03320 }
03321 }
03322
03323 @end
03324
03325 @implementation _dropOperationDrawingView : CPView
03326 {
03327 unsigned dropOperation @accessors;
03328 CPTableView tableView @accessors;
03329 int currentRow @accessors;
03330 }
03331
03332 - (void)drawRect:(CGRect)aRect
03333 {
03334 if(tableView._destinationDragStyle === CPTableViewDraggingDestinationFeedbackStyleNone)
03335 return;
03336
03337 var context = [[CPGraphicsContext currentContext] graphicsPort];
03338
03339 CGContextSetStrokeColor(context, [CPColor colorWithHexString:@"4886ca"]);
03340 CGContextSetLineWidth(context, 3);
03341
03342 if (currentRow === -1)
03343 {
03344 CGContextStrokeRect(context, [self bounds]);
03345 }
03346
03347 else if (dropOperation === CPTableViewDropOn)
03348 {
03349
03350 var selectedRows = [tableView selectedRowIndexes],
03351 newRect = _CGRectMake(aRect.origin.x + 2, aRect.origin.y + 2, aRect.size.width - 4, aRect.size.height - 5);
03352
03353 if([selectedRows containsIndex:currentRow])
03354 {
03355 CGContextSetLineWidth(context, 2);
03356 CGContextSetStrokeColor(context, [CPColor whiteColor]);
03357 }
03358 else
03359 {
03360 CGContextSetFillColor(context, [CPColor colorWithRed:72/255 green:134/255 blue:202/255 alpha:0.25]);
03361 CGContextFillRoundedRectangleInRect(context, newRect, 8, YES, YES, YES, YES);
03362 }
03363 CGContextStrokeRoundedRectangleInRect(context, newRect, 8, YES, YES, YES, YES);
03364
03365 }
03366 else if (dropOperation === CPTableViewDropAbove)
03367 {
03368
03369 [self setFrameOrigin:CGPointMake(_frame.origin.x, _frame.origin.y - 8)];
03370
03371 var selectedRows = [tableView selectedRowIndexes];
03372
03373 if([selectedRows containsIndex:currentRow - 1] || [selectedRows containsIndex:currentRow])
03374 {
03375 CGContextSetStrokeColor(context, [CPColor whiteColor]);
03376 CGContextSetLineWidth(context, 4);
03377
03378 CGContextStrokeEllipseInRect(context, _CGRectMake(aRect.origin.x + 4, aRect.origin.y + 4, 8, 8));
03379
03380 CGContextBeginPath(context);
03381 CGContextMoveToPoint(context, 10, aRect.origin.y + 8);
03382 CGContextAddLineToPoint(context, aRect.size.width - aRect.origin.y - 8, aRect.origin.y + 8);
03383 CGContextClosePath(context);
03384 CGContextStrokePath(context);
03385
03386 CGContextSetStrokeColor(context, [CPColor colorWithHexString:@"4886ca"]);
03387 CGContextSetLineWidth(context, 3);
03388 }
03389
03390
03391 CGContextStrokeEllipseInRect(context, _CGRectMake(aRect.origin.x + 4, aRect.origin.y + 4, 8, 8));
03392
03393 CGContextBeginPath(context);
03394 CGContextMoveToPoint(context, 10, aRect.origin.y + 8);
03395 CGContextAddLineToPoint(context, aRect.size.width - aRect.origin.y - 8, aRect.origin.y + 8);
03396 CGContextClosePath(context);
03397 CGContextStrokePath(context);
03398
03399 }
03400
03401
03402 }
03403 @end