Further improvements to tableview, and reimplemented getIndexes: for CPIndexSet to match the new architecture.

Reviewed by me.
This commit is contained in:
Francisco Ryan Tolmasky I committed 2009-06-23 10:51:16 -07:00
1 parent 998f52c4a4
commit 1fecae3dc0
5 files changed
+241 -107

No files matched your search

+35 -28
View File
@@ -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 = {};
+6 -2
View File
@@ -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
{
+119 -40
View File
@@ -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];
}
}
+56 -37
View File
@@ -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)];
}
}
+25
View File
@@ -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)];