Re: Reordering a table insanity
Re: Reordering a table insanity
- Subject: Re: Reordering a table insanity
- From: Quincey Morris <email@hidden>
- Date: Wed, 28 Nov 2012 22:44:51 -0800
On Nov 28, 2012, at 18:53 , Graham Cox <email@hidden> wrote:
> But suppose the two index sets are "absolute" in that there is not yet any adjustment to either of them. Then the indexes they refer to are absolutely referring to the table rows - there is a 1:1 correspondence between the order of indexes in the two sets representing source and dest rows, in absolute terms, before and after the move. Thus, by swapping the tables on undo, the move is reversed. The destination index set can be thought of as a list of where I want each index in the source set to end up, so if these two sets are flipped having made the change, the source list is now where the items got moved to, and the dest list is where they originally came from, with a 1:1 correspondence.
The problem is that the destination can't in general be represented by an index set, because to preserve what what originally done you need a set that (a) might have duplicate indexes and (b) might have indexes out of order. I can't prove that there's no mechanism for representing all the necessary information in an index set, but I believe it's so.
However, I found a fairly easy solution, which I implemented in TableViewPlayground. To simplify things, I added to the window a text field for the index of the row you want to move the selection *before*, a button to move the selection to that row, and a button to reverse the move:
> - (IBAction) btnMoveSelection:(id)sender {
> NSInteger targetIndex = [_txtFldTargetRow integerValue];
> NSIndexSet* indexes = [_tableViewMain selectedRowIndexes];
> NSUInteger indexCount = indexes.count;
> if (!indexCount)
> return;
>
> _fromArray = [[NSMutableArray alloc] init];
> _toArray = [[NSMutableArray alloc] init];
>
> for (NSUInteger index = 0; index < indexCount; index++)
> {
> [_fromArray addObject: [NSNumber numberWithUnsignedInteger: 0]];
> [_toArray addObject: [NSNumber numberWithUnsignedInteger: 0]];
> }
>
> NSUInteger arrayIndex = 0;
> NSUInteger fromIndex = [indexes indexLessThanIndex:targetIndex];
> NSUInteger toIndex = targetIndex;
>
> while( fromIndex != NSNotFound )
> {
> [_fromArray replaceObjectAtIndex: arrayIndex withObject: [NSNumber numberWithUnsignedInteger: fromIndex]];
> [_toArray replaceObjectAtIndex: indexCount - arrayIndex - 1 withObject: [NSNumber numberWithUnsignedInteger: --toIndex]];
> arrayIndex++;
> fromIndex = [indexes indexLessThanIndex:fromIndex];
> }
>
> fromIndex = [indexes indexGreaterThanOrEqualToIndex:targetIndex];
> toIndex = targetIndex;
>
> while( fromIndex != NSNotFound )
> {
> [_fromArray replaceObjectAtIndex: arrayIndex withObject: [NSNumber numberWithUnsignedInteger: fromIndex]];
> [_toArray replaceObjectAtIndex: indexCount - arrayIndex - 1 withObject: [NSNumber numberWithUnsignedInteger: toIndex++]];
> arrayIndex++;
> fromIndex = [indexes indexGreaterThanIndex:fromIndex];
> }
>
> [self moveFromArray: _fromArray toArray: _toArray];
> }
>
> - (IBAction) btnUndoMoveSelection:(id)sender
> {
> [self moveFromArray: _toArray toArray: _fromArray];
> }
>
> - (void) moveFromArray: (NSArray*) fromArray toArray: (NSArray*) toArray {
> NSUInteger indexCount = fromArray.count;
> for (NSUInteger index = 0; index < indexCount; index++)
> {
> NSUInteger fromIndex = [[fromArray objectAtIndex: index] unsignedIntegerValue];
> NSUInteger toIndex = [[toArray objectAtIndex: indexCount - index - 1] unsignedIntegerValue];
> [_tableViewMain moveRowAtIndex:fromIndex toIndex:toIndex];
> }
> }
The general approach is to use the original two-loop algorithm -- slightly simplified from your code -- to generate a series of desired moves, which are captured as pairs of indexes (in a pair of parallel arrays).
Then the captured arrays are "played" forward to complete the original move (or to later redo, unimplemented here), and backward to undo. I didn't test a lot of different selections, but things seemed to work fine. (I just noticed I forgot the begin/endUpdates.)
There are a couple of things to notice here:
-- Indexes are placed in the "to" array downwards from the end, so that during undo the moves are replayed in the opposite order.
-- This code seems to work just fine if the target row is one of the selected rows. Originally I thought it would need to be adjusted to a non-selected row, but this doesn't seem to be necessary.
-- In retrospect, my NSMutableArray code is unnecessarily clunky. IAC it looks like the code would be simpler if it used 2 malloc'ed C arrays of NSUInteger instead of 2 Cocoa arrays of NSNumber.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden