Fixed: the outline view was temporarily inconsistent to outside observers while expanding a node.

In particular, a selection did change notification was sent before the rows the selection referred to had had a chance to be loaded.
This commit is contained in:
Alexander Ljungberg
2011-01-13 18:57:36 -03:00
parent 28e660c295
commit dcf440396d
2 changed files with 39 additions and 4 deletions
+9 -2
View File
@@ -333,7 +333,8 @@ CPOutlineViewDropOnItemIndex = -1;
[self _noteItemWillExpand:anItem];
// Shift selection indexes below so that the same items remain selected.
var newRowCount = [_outlineViewDataSource outlineView:self numberOfChildrenOfItem:anItem];
var newRowCount = [_outlineViewDataSource outlineView:self numberOfChildrenOfItem:anItem],
newSelection = nil;
if (newRowCount)
{
var selection = [self selectedRowIndexes],
@@ -343,13 +344,19 @@ CPOutlineViewDropOnItemIndex = -1;
{
[self _noteSelectionIsChanging];
[selection shiftIndexesStartingAtIndex:expandIndex by:newRowCount];
[self _setSelectedRowIndexes:selection];
newSelection = selection;
}
}
itemInfo.isExpanded = YES;
[self _noteItemDidExpand:anItem];
[self reloadItem:anItem reloadChildren:YES];
// Update the selection - and send the associated notification - first
// after the items have loaded so that the new selection is consistent
// with the actual rows for any observers.
if (newSelection !== nil)
[self _setSelectedRowIndexes:selection];
}
if (shouldExpandChildren)
+30 -2
View File
@@ -112,17 +112,23 @@
var preSelection = [CPIndexSet indexSet];
[preSelection addIndex:[outlineView rowForItem:".1.1"]];
[preSelection addIndex:[outlineView rowForItem:".2"]];
[preSelection addIndex:[outlineView rowForItem:".3.1"]];
[outlineView selectRowIndexes:preSelection byExtendingSelection:NO];
// Test that by the time the selection notification is sent out, rows have
// been expanded. E.g. the outline view is made consistent before notifying.
var delegate = [TestNotificationsDelegate new];
[delegate setTester:self];
[outlineView setDelegate:delegate];
[outlineView expandItem:".1.2"];
afterSelection = [outlineView selectedRowIndexes];
[self assert:2 equals:[afterSelection count] message:"selections should remain"];
[self assert:".1.1" equals:[outlineView itemAtRow:[afterSelection firstIndex]] message:".1.1 selection should remain"];
[self assert:".2" equals:[outlineView itemAtRow:[afterSelection lastIndex]] message:".2 selection should remain"];
[self assert:".3.1" equals:[outlineView itemAtRow:[afterSelection lastIndex]] message:".3.1 selection should remain"];
}
@end
@@ -167,3 +173,25 @@
}
@end
@implementation TestNotificationsDelegate : CPObject
{
id tester @accessors;
}
- (void)outlineViewSelectionDidChange:(CPNotification)aNotification
{
// Verify that the state is consistent - every selected row has been loaded.
var anOutlineView = [aNotification object],
selection = [anOutlineView selectedRowIndexes],
rows = [];
[selection getIndexes:rows maxCount:-1 inIndexRange:nil];
for (var i = 0, count = [rows count]; i < count; i++)
{
[tester assertTrue:[anOutlineView itemAtRow:rows[i]] !== nil message:"selected row " + i + " should exist"];
}
}
@end