如何允许通过在 NSTableView 中拖动行来移动和复制?

How can I allow moving and copying by dragging rows in an NSTableView?

我有一个 NSTableView,我希望能够拖放行来移动它们,并在按住 Option 的同时拖放(根据 Apple's documentation)来复制它们。

我的视图控制器中有以下代码,它也是 table 视图的 dataSource

- (void)awakeFromNib {
    [self.tableView registerForDraggedTypes:@[kRowIndexesPasteboardType]];
}

- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pasteboard {
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
    [pasteboard declareTypes:@[kRowIndexesPasteboardType] owner:self];
    [pasteboard setData:data forType:kRowIndexesPasteboardType];
    return YES;
}

- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation {
    // Only allow dropping above/below.
    return dropOperation == NSTableViewDropAbove ? (NSDragOperationMove|NSDragOperationCopy) : NSDragOperationNone;
}

- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id <NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation {
    if (dropOperation == NSTableViewDropAbove) {
        NSPasteboard* pasteboard = [info draggingPasteboard];
        NSData* rowData = [pasteboard dataForType:kRowIndexesPasteboardType];
        NSIndexSet* rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:rowData];

        BOOL copy = ???;
        if (copy) {
            // Copy items at rowIndexes to row.
        } else {
            // Move items at rowIndexes to row.
        }
        return YES;
    }
    return NO;
}
  1. 如何让默认的拖动操作是移动,只有按住Option键时才复制?目前默认直接复制。
  2. tableView:acceptDrop:row:dropOperation: 中,如何判断操作是复制操作还是删除操作?

在 validateDrop 中:return [info draggingSourceOperationMask] & (NSDragOperationMove | NSDragOperationCopy) 或 NSDragOperationNone。

在 acceptDrop 中:检查 [info draggingSourceOperationMask] & NSDragOperationMove。

this discussion 中所述,当没有修饰键时,draggingSourceOperationMask 的值将是 NSDragOperationEvery(除非更改):

When it comes back to your table as a drop validation without any modification by the user (no option key down) then any of the original options need to be considered as being possible. Your validation should then pick the operation (out of the source allowed options) that you will do based on what makes sense for the target of the drop.

这意味着当按住 Option 键时,以下方法将 return NSDragOperationCopy,否则 NSDragOperationMove

- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation {
    // Allow moving or copying the rows.
    NSDragOperation moveOrCopy = (info.draggingSourceOperationMask == NSDragOperationCopy ? NSDragOperationCopy : NSDragOperationMove);
    // Only allow dropping above/below.
    return dropOperation == NSTableViewDropAbove ? moveOrCopy : NSDragOperationNone;
}

同样,可以以类似的方式在 tableView:acceptDrop:row:dropOperation: 中检查操作。