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]