2
votes

I'm fairly new to Cocoa dev, but implementing single row drag and drop within my NSTableView was fairly straightforward. However I'm now having a hard time getting it to work right when multiple rows are selected.

It seems to work without fault when all the selected rows are sequential, but it fails when, for example, you select rows 0 and 4 (where 4 is the last row) and drag them to somewhere in between (such as row 1 or 2) — by fail I mean that the wrong row is deleted and so I end up with duplicates.

Here is my acceptDrop code so far:

- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id <NSDraggingInfo>)info
        row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation
{
    NSPasteboard* pboard = [info draggingPasteboard];
    NSData* rowData = [pboard dataForType:BasicTableViewDragAndDropDataType];
    NSIndexSet* rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:rowData];
    NSInteger dragRow = [rowIndexes firstIndex];
    NSArray *tempArray = [[NSArray alloc] initWithArray:_filePaths copyItems:YES];

    int i = 0;

  if (dragRow < row) 
    {
        while (dragRow != NSNotFound) 
        {
            int putRow = row + i;
            int deleteRow = dragRow;

            if (putRow > [_filePaths count]) { putRow = [_filePaths count]; }
            if (i >= 1)
            {
                // offset fix for already deleted rows
                deleteRow = deleteRow - i;
            }

            [_filePaths insertObject:[tempArray objectAtIndex:dragRow] atIndex:putRow];
            [_filePaths removeObjectAtIndex:deleteRow];

            dragRow = [rowIndexes indexGreaterThanIndex:dragRow];

            i++;
        }

        [_imagesTableView noteNumberOfRowsChanged];
        [_imagesTableView reloadData];

    return YES;

  }

    NSLog(@"dragging up");

    while (dragRow != NSNotFound) 
    {
        int putRow = row + i;
        if (putRow > [_filePaths count]) { putRow = [_filePaths count]; }

        [_filePaths removeObjectAtIndex:dragRow];
        [_filePaths insertObject:[tempArray objectAtIndex:dragRow] atIndex:putRow];

        dragRow = [rowIndexes indexGreaterThanIndex:dragRow];

        i++;
    } 

    [_imagesTableView noteNumberOfRowsChanged];
    [_imagesTableView reloadData];

  return YES;
}    
1

1 Answers

4
votes

So after much dragging and dropping (and a few application crashes mixed in there) I started web searching again and found this class on GitHub.

I mimicked the code there and now it's working like a charm.