Search code examples
objective-cdrag-and-dropnsoutlineviewnspasteboard

NSOutlineView drag promises with directories


How does one implement an NSOutlineViewDataSource to allow dragging directories that do not exist in the file system at the time of dragging to the Finder? I have searched and searched and read a ton of the documentation, but have had great difficulty finding anything of value that works. I use a custom data source that manages a file system-like tree, and all the items are instances of a class that keeps track of its path. I would like to be able to drag files and directories out of the outline view into the Finder.

I have:

- (BOOL)outlineView:(NSOutlineView *)outlineView 
         writeItems:(NSArray *)items 
       toPasteboard:(NSPasteboard *)pasteboard 
{
    NSMutableArray *types = [NSMutableArray array];
    for (JOItemInfo *itemInfo in items) {
        NSString *extension = itemInfo.name.pathExtension;
        if (extension.length > 0) [types addObject:extension];
    }

    [pasteboard declareTypes:@[(__bridge_transfer NSString *)kPasteboardTypeFileURLPromise] 
                       owner:self];
    [pasteboard setPropertyList:types 
                        forType:(__bridge_transfer NSString *)kPasteboardTypeFileURLPromise];
    DDLogInfo(@"Wrote types %@ to pasteboard %@ for key %@", 
               types, 
               pasteboard, 
               (__bridge_transfer NSString *)kPasteboardTypeFileURLPromise);
    return YES;
}

and an implementation of -outlineView:namesOfPromisedFilesDroppedAtDestination:forDraggedItems: that writes the items inside of the given path. This works in that I can drag items out to the Finder, but when I let go nothing else happens, and the -...namesOfPromisedFilesDropped... method isn't even called. Also,

[self.outlineView setDraggingDestinationFeedbackStyle:NSTableViewDraggingDestinationFeedbackStyleRegular];
[self.outlineView setDraggingSourceOperationMask:NSDragOperationNone forLocal:YES];
[self.outlineView setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];

is in my -awakeFromNib. The if (extension.length > 0) ... was based on an example I found somewhere, but it was dated, and the documentation says to return an extension, so I think that is appropriate. Personally, I find the documentation for this whole area very lacking, especially in regard to an NSOutlineView. Thanks!


Solution

  • I changed (__bridge_transfer NSString *)kPasteboardTypeFileURLPromise to NSFilesPromisePboardType, and I can now drag files (with an extension at least) and they can be dropped successfully in the Finder. (I had used the former b/c the documentation for the latter recommended that, but they do not have the same effect.)

    Also, I tried removing the conditional and allowing it to add an empty string for an empty extension, which worked like a charm. I can now drag out of the outline view into the Finder.