On 2007-02-04 09:19:24 -0800 Guenther Noack
<[EMAIL PROTECTED]> wrote:
Hi!
Playing around with outline drag&drop, I found some other
selection-related issues in NSOutlineView:
- Inconsistency
The NSOutlineView method -noteNumberOfRowsChanged forgets about the
case where only one item is allowed to be selected. This leads to
inconsistencies within NSTableView which result in wrongly selected
rows in outline views. It can be fixed by adding this code snippet
before the -setFrame call:
if ([_selectedRows count] == 0) {
_selectedRow = -1;
} else {
_selectedRow = [_selectedRows lastIndex];
}
I really don't think that -noteNumberOfRowsChanged makes any sense for
NSOutlineView
because its a public method, and can be called seperate from
-reloadData
at the beginning it goes
_numberOfRows = [_items count];
If -reloadData is not called... this doesn't go to the delegate to get
the new number of rows
well it really cant in any good way which would be more optimal than
reloadData,
and I couldn't get this to do anything on a mac
- More inconsistency
The -reloadData method in NSTableView calls -noteNumberOfRowsChanged,
too. As the -noteNumberOfRowsChanged method restores the selected row
index set _selectedRows (and hopefully the _selectedRow index, too,
soon)
from the _selectedItems instance variable, NSOutlineView's -reloadData
has to assign a suitable value to that as well.
To fix the bug, insert this at the beginning of -reloadData (before
_items is set to nil):
// We save the selection
[_selectedItems removeAllObjects];
int row = [_selectedRows firstIndex];
while (row != NSNotFound)
{
if ([self itemAtRow: row])
{
[_selectedItems addObject: [self itemAtRow: row]];
}
row = [_selectedRows indexGreaterThanIndex: row];
}
This stuff doesn't seem to make sense to me, if the selected objects
changes row indexes
the selected row shouldn't jump around to the new row index where the
selected object
now is...
attached is a patch which gets rid of _selectedItems,
and implements a private method to maintain the selected row index
not the selected objects.
BTW: The whole issue also applies to the -reloadItem:reloadChildren:
method. There's even a FIXME describing the problem.
<NSOutlineView.diff>
Index: NSOutlineView.m
===================================================================
--- NSOutlineView.m (revision 24467)
+++ NSOutlineView.m (working copy)
@@ -111,6 +111,7 @@
- (void) _openItem: (id)item;
- (void) _closeItem: (id)item;
- (void) _removeChildren: (id)startitem;
+- (void) _maintainSelection;
@end
@implementation NSOutlineView
@@ -150,7 +151,6 @@
64);
_items = [[NSMutableArray alloc] init];
_expandedItems = [[NSMutableArray alloc] init];
- _selectedItems = [[NSMutableArray alloc] init];
_levelOfItems = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks,
64);
@@ -161,7 +161,6 @@
{
RELEASE(_items);
RELEASE(_expandedItems);
- RELEASE(_selectedItems);
NSFreeMapTable(_itemDict);
NSFreeMapTable(_levelOfItems);
@@ -227,7 +226,6 @@
if ([self isExpandable: item] && [self isItemExpanded: item] && canCollapse)
{
NSMutableDictionary *infoDict = [NSMutableDictionary dictionary];
- unsigned int row;
[infoDict setObject: item forKey: @"NSObject"];
@@ -237,18 +235,6 @@
object: self
userInfo: infoDict];
- // We save the selection
- [_selectedItems removeAllObjects];
- row = [_selectedRows firstIndex];
- while (row != NSNotFound)
- {
- if ([self itemAtRow: row])
- {
- [_selectedItems addObject: [self itemAtRow: row]];
- }
- row = [_selectedRows indexGreaterThanIndex: row];
- }
-
// collapse...
[self _closeItem: item];
@@ -279,7 +265,7 @@
}
}
}
- [self noteNumberOfRowsChanged];
+ [self _maintainSelection];
// Should only mark the rect below the closed item for redraw
[self setNeedsDisplay: YES];
}
@@ -316,7 +302,6 @@
if (![self isItemExpanded: item] && canExpand)
{
NSMutableDictionary *infoDict = [NSMutableDictionary dictionary];
- unsigned int row;
[infoDict setObject: item forKey: @"NSObject"];
@@ -326,18 +311,6 @@
object: self
userInfo: infoDict];
- // We save the selection
- [_selectedItems removeAllObjects];
- row = [_selectedRows firstIndex];
- while (row != NSNotFound)
- {
- if ([self itemAtRow: row])
- {
- [_selectedItems addObject: [self itemAtRow: row]];
- }
- row = [_selectedRows indexGreaterThanIndex: row];
- }
-
// insert the root element, if necessary otherwise insert the
// actual object.
[self _openItem: item];
@@ -371,7 +344,7 @@
}
}
- [self noteNumberOfRowsChanged];
+ [self _maintainSelection];
// Should only mark the rect below the expanded item for redraw
[self setNeedsDisplay: YES];
}
@@ -510,7 +483,7 @@
if (expanded)
{
[self _openItem: dsobj];
- [self noteNumberOfRowsChanged];
+ [self _maintainSelection];
}
}
[self setNeedsDisplay: YES];
@@ -619,48 +592,12 @@
/**
- * We override the super class's method.
+ * We override the super class's method to do nothing.
+ * This method doesn't make sense for outline views.
*/
- (void) noteNumberOfRowsChanged
{
- _numberOfRows = [_items count];
- if (!_selectingColumns)
- {
- int i, count, row;
-
- /* We restore the selection */
- [_selectedRows removeAllIndexes];
- count = [_selectedItems count];
-
- for (i = 0; i < count; i++)
- {
- row = [self rowForItem: [_selectedItems objectAtIndex: i]];
-
- if (row >= 0 && row < _numberOfRows)
- {
- [_selectedRows addIndex: row];
- }
- }
- }
-
- [self setFrame: NSMakeRect (_frame.origin.x,
- _frame.origin.y,
- _frame.size.width,
- (_numberOfRows * _rowHeight) + 1)];
-
- /* If we are shorter in height than the enclosing clipview, we
- should redraw us now. */
- if (_super_view != nil)
- {
- NSRect superviewBounds; // Get this *after* [self setFrame:]
- superviewBounds = [_super_view bounds];
- if ((superviewBounds.origin.x <= _frame.origin.x)
- && (NSMaxY (superviewBounds) >= NSMaxY (_frame)))
- {
- [self setNeedsDisplay: YES];
- }
- }
}
/**
@@ -723,6 +660,7 @@
atLevel: -1];
[self _openItem: nil];
[super reloadData];
+ [self _maintainSelection];
}
/**
@@ -782,7 +720,6 @@
64);
_items = [[NSMutableArray alloc] init];
_expandedItems = [[NSMutableArray alloc] init];
- _selectedItems = [[NSMutableArray alloc] init];
_levelOfItems = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks,
64);
@@ -816,7 +753,6 @@
64);
_items = [[NSMutableArray alloc] init];
_expandedItems = [[NSMutableArray alloc] init];
- _selectedItems = [[NSMutableArray alloc] init];
_levelOfItems = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks,
64);
@@ -1898,9 +1834,41 @@
NSMapRemove(_itemDict, child);
[_items removeObject: child];
[_expandedItems removeObject: child];
- [_selectedItems removeObject: child];
}
[anarray removeAllObjects];
}
+- (void) _maintainSelection
+{
+ int row = [_selectedRows lastIndex];
+ _numberOfRows = [_items count];
+
+ if ((row != NSNotFound) && (row >= _numberOfRows))
+ {
+ [_selectedRows removeIndexesInRange:
+ NSMakeRange(_numberOfRows,
+ row + 1 - _numberOfRows)];
+ if (_selectedRow >= _numberOfRows)
+ {
+ [self _postSelectionIsChangingNotification];
+ row = [_selectedRows lastIndex];
+
+ if (row != NSNotFound)
+ {
+ _selectedRow = row;
+ }
+ else
+ {
+ int lastRow = _numberOfRows - 1;
+
+ if (lastRow > -1)
+ [_selectedRows addIndex:lastRow];
+
+ _selectedRow = lastRow;
+ }
+ [self _postSelectionDidChangeNotification];
+ }
+ }
+}
+
@end
_______________________________________________
Gnustep-dev mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/gnustep-dev