On Nov 28, 2012, at 18:53 , Graham Cox <[email protected]> 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 protected])

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to