diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 7862fea77..2c6c226ed 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -94,12 +94,13 @@ var DOMElementPrototype = nil, BackgroundTrivialColor = 0, BackgroundVerticalThreePartImage = 1, BackgroundHorizontalThreePartImage = 2, - BackgroundNinePartImage = 3, - - CustomDrawRectViews = {}, - CustomLayoutSubviewsViews = {}; + BackgroundNinePartImage = 3; #endif +var CPViewFlags = { }, + CPViewHasCustomDrawRect = 1 << 0, + CPViewHasCustomLayoutSubviews = 1 << 1; + /*! @ingroup appkit @class CPView @@ -184,6 +185,8 @@ var DOMElementPrototype = nil, // Key View Support CPView _nextKeyView; CPView _previousKeyView; + + unsigned _viewClassFlags; } /* @@ -209,6 +212,27 @@ var DOMElementPrototype = nil, CachedNotificationCenter = [CPNotificationCenter defaultCenter]; } +- (void)setupViewFlags +{ + var theClass = [self class], + classUID = [theClass UID]; + + if (CPViewFlags[classUID] === undefined) + { + var flags = 0; + + if ([theClass instanceMethodForSelector:@selector(drawRect:)] !== [CPView instanceMethodForSelector:@selector(drawRect:)]) + flags |= CPViewHasCustomDrawRect; + + if ([theClass instanceMethodForSelector:@selector(layoutSubviews)] !== [CPView instanceMethodForSelector:@selector(layoutSubviews)]) + flags |= CPViewHasCustomLayoutSubviews; + + CPViewFlags[classUID] = flags; + } + + _viewClassFlags = CPViewFlags[classUID]; +} + - (id)init { return [self initWithFrame:CGRectMakeZero()]; @@ -256,6 +280,8 @@ var DOMElementPrototype = nil, _theme = [CPTheme defaultTheme]; _themeState = CPThemeStateNormal; + [self setupViewFlags]; + [self _loadThemeAttributes]; } @@ -1534,16 +1560,7 @@ setBoundsOrigin: - (void)setNeedsDisplayInRect:(CPRect)aRect { #if PLATFORM(DOM) - var UID = [[self class] UID], - hasCustomDrawRect = CustomDrawRectViews[UID]; - - if (!hasCustomDrawRect && typeof hasCustomDrawRect === "undefined") - { - hasCustomDrawRect = [self methodForSelector:@selector(drawRect:)] != [CPView instanceMethodForSelector:@selector(drawRect:)]; - CustomDrawRectViews[UID] = hasCustomDrawRect; - } - - if (!hasCustomDrawRect) + if (!(_viewClassFlags & CPViewHasCustomDrawRect)) return; #endif @@ -1665,22 +1682,10 @@ setBoundsOrigin: _needsLayout = YES; #if PLATFORM(DOM) - var UID = [[self class] UID], - hasCustomLayoutSubviews = CustomLayoutSubviewsViews[UID]; - - if (hasCustomLayoutSubviews === undefined) - { - hasCustomLayoutSubviews = [self methodForSelector:@selector(layoutSubviews)] != [CPView instanceMethodForSelector:@selector(layoutSubviews)]; - CustomLayoutSubviewsViews[UID] = hasCustomLayoutSubviews; - } - - if (!hasCustomLayoutSubviews) + if (!(_viewClassFlags & CPViewHasCustomLayoutSubviews)) return; - if (_needsLayout) - { - CPDOMDisplayServerAddView(self); - } + CPDOMDisplayServerAddView(self); #endif } @@ -2320,6 +2325,8 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask", [self setBackgroundColor:[aCoder decodeObjectForKey:CPViewBackgroundColorKey]]; + [self setupViewFlags]; + _theme = [CPTheme defaultTheme]; _themeState = CPThemeState([aCoder decodeIntForKey:CPViewThemeStateKey]); _themeAttributes = {}; diff --git a/AppKit/NEWCPTableColumn.j b/AppKit/NEWCPTableColumn.j index 7a6e8b8fc..e9f0018c5 100644 --- a/AppKit/NEWCPTableColumn.j +++ b/AppKit/NEWCPTableColumn.j @@ -215,20 +215,24 @@ CPTableColumnUserResizingMask = 2; var dataView = [self dataViewForRow:aRowIndex], dataViewUID = [dataView UID]; +var x = [self tableView]._cachedDataViews[dataViewUID]; +if (x && x.length) +return x.pop(); + // if we haven't cached an archive of the data view, do it now if (!_dataViewData[dataViewUID]) _dataViewData[dataViewUID] = [CPKeyedArchiver archivedDataWithRootObject:dataView]; // unarchive the data view cache var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]]; - +newDataView.identifier = dataViewUID; return newDataView; } //Setting the Identifier /* - Sets the receiverÕs identifier to anIdentifier. + Sets the receiver identifier to anIdentifier. */ - (void)setIdentifier:(id)anIdentifier { diff --git a/AppKit/NEWCPTableView.j b/AppKit/NEWCPTableView.j index 09a3b7e3d..a26c940f9 100644 --- a/AppKit/NEWCPTableView.j +++ b/AppKit/NEWCPTableView.j @@ -59,10 +59,12 @@ CPTableViewSelectionHighlightStyleSourceList = 1; CPInteger _numberOfHiddenColumns; Object _objectValues; - CPArray _dataViews; CPRange _exposedRows; CPIndexSet _exposedColumns; + Object _dataViewsForTableColumns; + Object _cachedDataViews; + //Configuring Behavior BOOL _allowsColumnReordering; BOOL _allowsColumnResizing; @@ -103,11 +105,12 @@ CPTableViewSelectionHighlightStyleSourceList = 1; _numberOfHiddenColumns = 0; _objectValues = { }; + _dataViewsForTableColumns = { }; _dataViews= []; _numberOfRows = 0; _exposedRows = [CPIndexSet indexSet]; _exposedColumns = [CPIndexSet indexSet]; - +_cachedDataViews = { }; _intercellSpacing = _CGSizeMake(0.0, 0.0); _rowHeight = 24.0; } @@ -315,6 +318,7 @@ CPTableViewSelectionHighlightStyleSourceList = 1; - (void)addTableColumn:(CPTableColumn)aTableColumn { [_tableColumns addObject:aTableColumn]; + [aTableColumn setTableView:self]; if (_dirtyTableColumnRangeIndex < 0) _dirtyTableColumnRangeIndex = NUMBER_OF_COLUMNS() - 1; @@ -326,8 +330,15 @@ CPTableViewSelectionHighlightStyleSourceList = 1; - (void)removeTableColumn:(CPTableColumn)aTableColumn { + if ([aTableColumn tableView] !== self) + return; + var index = [_tableColumns indeOfObjectIdenticalTo:aTableColumn]; + if (index === CPNotFound) + return; + + [aTableColumn setTableView:nil]; [_tableColumns removeObjectAtIndex:index]; var tableColumnUID = [aTableColumn UID]; @@ -594,7 +605,7 @@ CPTableViewSelectionHighlightStyleSourceList = 1; if (x < range.location) high = middle - 1; - else if (x > CPMaxRange(range)) + else if (x >= CPMaxRange(range)) low = middle + 1; else @@ -625,8 +636,14 @@ CPTableViewSelectionHighlightStyleSourceList = 1; return FLOOR(y / (_rowHeight + _intercellSpacing.height)); } +- (CGRect)frameOfDataViewAtColumn:(CPInteger)aColumnIndex row:(CPInteger)aRowIndex +{ + var tableColumnRange = _tableColumns[aColumnIndex], + rectOfRow = [self rectOfRow:aRowIndex]; + + return _CGRectMake(tableColumnRange.location, _CGRectGetMinY(rectOfRow), tableColumnRange.length, _CGRectGetHeight(rectOfRow)); +} /* - * - frameOfCellAtColumn:row: * - columnAutoresizingStyle * - setColumnAutoresizingStyle: */ @@ -897,71 +914,133 @@ CPTableViewSelectionHighlightStyleSourceList = 1; // remove? return; } -console.profile("cell-load"); - // SLOWMO -/* var subviews = [self subviews], - count = [subviews count]; + if (window.console && window.console.profile) + console.profile("cell-load"); - while (count--) - [subviews[count] removeFromSuperview]; -*/ var exposedRect = [self _exposedRect], exposedRows = [CPIndexSet indexSetWithIndexesInRange:[self rowsInRect:exposedRect]], exposedColumns = [self columnIndexesInRect:exposedRect], - previouslyExposedRows = [_exposedRows copy], - previouslyExposedColumns = [_exposedColumns copy], - newlyExposedRows = [exposedRows copy], - newlyExposedColumns = [exposedColumns copy]; + obscuredRows = [_exposedRows copy], + obscuredColumns = [_exposedColumns copy]; -// console.log("exposed rows: " + exposedRows + " exposed columns: " + exposedColumns); -// console.log("but rows: " + _exposedRows + " exposed columns: " + _exposedColumns); + [obscuredRows removeIndexes:exposedRows]; + [obscuredColumns removeIndexes:exposedColumns]; + + var newlyExposedRows = [exposedRows copy], + newlyExposedColumns = [exposedColumns copy]; [newlyExposedRows removeIndexes:_exposedRows]; [newlyExposedColumns removeIndexes:_exposedColumns]; + + var previouslyExposedRows = [exposedRows copy], + previouslyExposedColumns = [exposedColumns copy]; + [previouslyExposedRows removeIndexes:newlyExposedRows]; [previouslyExposedColumns removeIndexes:newlyExposedColumns]; +// console.log("will remove:" + '\n\n' + +// previouslyExposedRows + "\n" + obscuredColumns + "\n\n" + +// obscuredRows + "\n" + previouslyExposedColumns + "\n\n" + +// obscuredRows + "\n" + obscuredColumns); + [self _unloadDataViewsInRows:previouslyExposedRows columns:obscuredColumns]; + [self _unloadDataViewsInRows:obscuredRows columns:previouslyExposedColumns]; + [self _unloadDataViewsInRows:obscuredRows columns:obscuredColumns]; + + [self _loadDataViewsInRows:previouslyExposedRows columns:newlyExposedColumns]; + [self _loadDataViewsInRows:newlyExposedRows columns:previouslyExposedColumns]; + [self _loadDataViewsInRows:newlyExposedRows columns:newlyExposedColumns]; + // console.log("newly exposed rows: " + newlyExposedRows + "\nnewly exposed columns: " + newlyExposedColumns); _exposedRows = exposedRows; _exposedColumns = exposedColumns; - [self r:previouslyExposedRows c:newlyExposedColumns]; - [self r:newlyExposedRows c:previouslyExposedColumns]; - [self r:newlyExposedRows c:newlyExposedColumns]; -console.profileEnd("cell-load"); + if (window.console && window.console.profile) + console.profileEnd("cell-load"); } -- (void)r:(CPIndexSet)rows c:(CPIndexSet)columns +- (void)_unloadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns { - var columnIndex = [columns firstIndex]; + if (![rows count] || ![columns count]) + return; - while (columnIndex !== CPNotFound) + var rowArray = [], + columnArray = []; + + [rows getIndexes:rowArray maxCount:-1 inIndexRange:nil]; + [columns getIndexes:columnArray maxCount:-1 inIndexRange:nil]; + + var columnIndex = 0, + columnsCount = columnArray.length; + + for (; columnIndex < columnsCount; ++columnIndex) { - if (!_dataViews[columnIndex]) - _dataViews[columnIndex] = []; - - var tableColumn = _tableColumns[columnIndex], - tableColumnRange = _tableColumnRanges[columnIndex]; + var column = columnArray[columnIndex], + tableColumn = _tableColumns[column], + tableColumnUID = [tableColumn UID]; - var rowIndex = [rows firstIndex] + var rowIndex = 0, + rowsCount = rowArray.length; - while (rowIndex !== CPNotFound) + for (; rowIndex < rowsCount; ++rowIndex) { - var dataView = [tableColumn _newDataViewForRow:rowIndex], - rectOfRow = [self rectOfRow:rowIndex]; + var row = rowArray[rowIndex], + dataView = _dataViewsForTableColumns[tableColumnUID][row]; + + _dataViewsForTableColumns[tableColumnUID][row] = nil; +if (!_cachedDataViews[dataView.identifier]) +_cachedDataViews[dataView.identifier] = [dataView]; +else +_cachedDataViews[dataView.identifier].push(dataView); + } + } +} + +- (void)_loadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns +{ + if (![rows count] || ![columns count]) + return; + + var rowArray = [], + rowRects = [], + columnArray = []; + + [rows getIndexes:rowArray maxCount:-1 inIndexRange:nil]; + [columns getIndexes:columnArray maxCount:-1 inIndexRange:nil]; + + var columnIndex = 0, + columnsCount = columnArray.length; + + for (; columnIndex < columnsCount; ++columnIndex) + { + var column = columnArray[columnIndex], + tableColumn = _tableColumns[column], + tableColumnUID = [tableColumn UID], + tableColumnRange = _tableColumnRanges[column]; + + if (!_dataViewsForTableColumns[tableColumnUID]) + _dataViewsForTableColumns[tableColumnUID] = []; + + var rowIndex = 0, + rowsCount = rowArray.length; + + for (; rowIndex < rowsCount; ++rowIndex) + { + var row = rowArray[rowIndex], + dataView = [tableColumn _newDataViewForRow:row], + rectOfRow = rowRects[row]; + + if (!rectOfRow) + rectOfRow = rowRects[row] = [self rectOfRow:row]; [dataView setBackgroundColor:[CPColor redColor]]; [dataView setFrame:_CGRectMake(tableColumnRange.location, _CGRectGetMinY(rectOfRow), tableColumnRange.length, _CGRectGetHeight(rectOfRow))]; - [dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:rowIndex]]; + [dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]]; - [self addSubview:dataView]; - - _dataViews[columnIndex][rowIndex] = dataView; + if ([dataView superview] !== self) + [self addSubview:dataView]; - rowIndex = [rows indexGreaterThanIndex:rowIndex]; + _dataViewsForTableColumns[tableColumnUID][row] = dataView; } - - columnIndex = [columns indexGreaterThanIndex:columnIndex]; } } diff --git a/Foundation/CPIndexSet.j b/Foundation/CPIndexSet.j index 040d32690..ab704a916 100644 --- a/Foundation/CPIndexSet.j +++ b/Foundation/CPIndexSet.j @@ -23,6 +23,9 @@ @import "CPRange.j" @import "CPObject.j" +#define _CPMaxRange(aRange) ((aRange).location + (aRange).length) +#define _CPMakeRange(aLocation, aLength) { location:(aLocation), length:aLength } +#define _CPMakeRangeCopy(aRange) { location:(aRange).location, length:(aRange).length } /*! @class CPIndexSet @@ -68,7 +71,7 @@ - (id)init { - return [self initWithIndexesInRange:CPMakeRange(0, 0)]; + return [self initWithIndexesInRange:_CPMakeRange(0, 0)]; } /*! @@ -77,7 +80,7 @@ */ - (id)initWithIndex:(CPInteger)anIndex { - return [self initWithIndexesInRange:CPMakeRange(anIndex, 1)]; + return [self initWithIndexesInRange:_CPMakeRange(anIndex, 1)]; } /*! @@ -120,7 +123,7 @@ otherRangesCount = otherRanges.length; while (otherRangesCount--) - _ranges[otherRangesCount] = CPCopyRange(otherRanges[otherRangesCount]); + _ranges[otherRangesCount] = _CPMakeRangeCopy(otherRanges[otherRangesCount]); } return self; @@ -232,7 +235,7 @@ if (FLOOR(lhsRangeIndex) === lhsRangeIndex) return YES; - var rhsRangeIndex = assumedPositionOfIndex(_ranges, CPMaxRange(aRange) - 1); + var rhsRangeIndex = assumedPositionOfIndex(_ranges, _CPMaxRange(aRange) - 1); if (FLOOR(rhsRangeIndex) === rhsRangeIndex) return YES; @@ -266,7 +269,7 @@ - (CPInteger)lastIndex { if (_count > 0) - return CPMaxRange(_ranges[_ranges.length - 1]) - 1; + return _CPMaxRange(_ranges[_ranges.length - 1]) - 1; return CPNotFound; } @@ -330,7 +333,7 @@ return anIndex; // If not, it must be the first element of this range. - return CPMaxRange(range) - 1; + return _CPMaxRange(range) - 1; } /*! @@ -360,48 +363,64 @@ @param aRangePointer the range of indices to add @return the number of elements added to the array */ -- (unsigned)getIndexes:(CPArray)anArray maxCount:(unsigned)aMaxCount inIndexRange:(CPRange)aRangePointer +- (CPInteger)getIndexes:(CPArray)anArray maxCount:(CPInteger)aMaxCount inIndexRange:(CPRange)aRange { - if (!_count || aMaxCount <= 0 || aRangePointer && !aRangePointer.length) - return 0; - - var i = SOERangeIndex(self, aRangePointer? aRangePointer.location : 0), - total = 0, - count = _ranges.length; - - for (; i < count; ++i) + if (!_count || aMaxCount === 0 || aRange && !aRange.length) { - // If aRangePointer is nil, all indexes are acceptable. - var intersection = aRangePointer ? CPIntersectionRange(_ranges[i], aRangePointer) : _ranges[i], - index = intersection.location, - maximum = CPMaxRange(intersection); + if (aRange) + aRange.length = 0; - for (; index < maximum; ++index) + return 0; + } + + var total = 0; + + if (aRange) + { + var firstIndex = aRange.location, + lastIndex = _CPMaxRange(aRange) - 1, + rangeIndex = CEIL(assumedPositionOfIndex(_ranges, firstIndex)), + lastRangeIndex = FLOOR(assumedPositionOfIndex(_ranges, lastIndex)); + } + else + { + var firstIndex = [self firstIndex], + lastIndex = [self lastIndex], + rangeIndex = 0, + lastRangeIndex = _ranges.length - 1; + } + + while (rangeIndex <= lastRangeIndex) + { + var range = _ranges[rangeIndex], + index = MAX(firstIndex, range.location), + maxRange = MIN(lastIndex + 1, _CPMaxRange(range)); + + for (; index < maxRange; ++index) { anArray[total++] = index; - if (total == aMaxCount) + if (total === aMaxCount) { - // Update aRangePointer if it exists... - if (aRangePointer) + // Update aRange if it exists... + if (aRange) { - var upper = CPMaxRange(aRangePointer); - - // Don't use CPMakeRange since the values need to persist. - aRangePointer.location = index + 1; - aRangePointer.length = upper - index - 1; + aRange.location = index + 1; + aRange.length = lastIndex + 1 - index - 1; } return aMaxCount; } } + + ++rangeIndex; } - // Update aRangePointer if it exists... - if (aRangePointer) + // Update aRange if it exists... + if (aRange) { - aRangePointer.location = CPNotFound; - aRangePointer.length = 0; + aRange.location = CPNotFound; + aRange.length = 0; } return total; @@ -456,7 +475,7 @@ */ - (void)addIndex:(CPInteger)anIndex { - [self addIndexesInRange:CPMakeRange(anIndex, 1)]; + [self addIndexesInRange:_CPMakeRange(anIndex, 1)]; } /*! @@ -532,7 +551,7 @@ for (; removal <= lastRemoval; ++removal) _count -= _ranges[removal].length; - [_ranges removeObjectsInRange:CPMakeRange(lhsRangeIndexCEIL, removalCount)]; + [_ranges removeObjectsInRange:_CPMakeRange(lhsRangeIndexCEIL, removalCount)]; } [_ranges insertObject:aRange atIndex:lhsRangeIndexCEIL]; @@ -548,7 +567,7 @@ */ - (void)removeIndex:(CPInteger)anIndex { - [self removeIndexesInRange:CPMakeRange(anIndex, 1)]; + [self removeIndexesInRange:_CPMakeRange(anIndex, 1)]; } /*! @@ -611,7 +630,7 @@ if (maxRange < existingMaxRange) { _count -= aRange.length; - [_ranges insertObject:CPMakeRange(maxRange, existingMaxRange - maxRange) atIndex:lhsRangeIndexCEIL + 1]; + [_ranges insertObject:_CPMakeRange(maxRange, existingMaxRange - maxRange) atIndex:lhsRangeIndexCEIL + 1]; return; } @@ -652,7 +671,7 @@ for (; removal <= lastRemoval; ++removal) _count -= _ranges[removal].length; - [_ranges removeObjectsInRange:CPMakeRange(lhsRangeIndexCEIL, removalCount)]; + [_ranges removeObjectsInRange:_CPMakeRange(lhsRangeIndexCEIL, removalCount)]; } } diff --git a/Tests/Foundation/CPIndexSetTest.j b/Tests/Foundation/CPIndexSetTest.j index 1d1b68fee..c659fff42 100644 --- a/Tests/Foundation/CPIndexSetTest.j +++ b/Tests/Foundation/CPIndexSetTest.j @@ -147,6 +147,31 @@ function descriptionWithoutEntity(aString) [self assert:@"[number of indexes: 1 (in 1 range), indexes: (0)]" equals:descriptionWithoutEntity(indexSet)]; } +- (void)testGetIndexes +{ + var indexSet = [CPIndexSet indexSet]; + + // Test no indexes + [self assert:descriptionWithoutEntity(indexSet) equals:@"(no indexes)"]; + + // Test adding initial range + [indexSet addIndexesInRange:CPMakeRange(0, 10)]; + + [indexSet addIndexesInRange:CPMakeRange(15, 1)]; + + [indexSet addIndexesInRange:CPMakeRange(20, 10)]; + + [indexSet addIndexesInRange:CPMakeRange(50, 10)]; + + [self assert:@"[number of indexes: 31 (in 4 ranges), indexes: (0-9 15 20-29 50-59)]" equals:descriptionWithoutEntity(indexSet)]; + + var array = []; + + [indexSet getIndexes:array maxCount:1000 inIndexRange:nil]; + + [self assert:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59] equals:array]; +} + - (void)setUp { _set = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 10)];