I've created an app that has a NSTableView which represents a series of files. From this, I want to be able to drag a row (i.e. a filename) from my NSTableView to Finder, and the file be created in that folder. However, the bit I can't work out is that I need to modify the contents of the original file, before it gets copied to Finder.
I've added the following line so I can drag outside of my NSTableView:
[self.tableView setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];
And I can get it to copy the actual file, provided I add a current files location to the pasteboard, using:
- (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard {
[pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:nil];
NSMutableArray* dragfiles = [[NSMutableArray alloc] init];
NSString* file = [self.files objectAtIndex:row];
NSString* filepath = [[[self.pathControl URL] path] stringByAppendingPathComponent:file];
[dragfiles addObject:filepath];
[pboard setPropertyList:dragfiles forType: NSFilenamesPboardType];
[dragfiles release];
}
But, because I want to modify the contents of the file, I don't want to put filepaths onto the pasteboard. I've tried using NSFileWrapper, but Finder doesnt seem to accept this as a valid format.
I've checked Google, and I've found several suggestions that you can create a temporary file and use that filepath. But, this feels ugly.
Is it possible to send data to Finder? Is there a way to solve this?
You will most likely want to use promise files, or NSFilesPromisePboardType
rather than NSFilenamesPboardType
. (Note: the promise file methods dragPromisedFilesOfTypes:fromRect:source:slideBack:event:
and namesOfPromisedFilesDroppedAtDestination:
that that documentation talks about are the generic NSView
methods. NSTableView
defines more convenient methods that you'll use instead of the generic ones. That said, that should still provide info on how promise file drags work). NSTableView
uses tableView:namesOfPromisedFilesDroppedAtDestination:forDraggedRowsWithIndexes:
, which is where you can do the processing of your files. In your tableView:writeRowsWithIndexes:toPasteboard:
method, you'll declare NSFilesPromisePboardType
, then set an array of filename extensions for the types of files you plan to write. The following is pseudo-code that outlines how you might approach it:
- (BOOL)tableView:(NSTableView *)aTableView
writeRowsWithIndexes:(NSIndexSet *)rowIndexes
toPasteboard:(NSPasteboard *)pboard {
[pboard declareTypes:[NSArray arrayWithObjects:NSFilesPromisePboardType, nil]];
NSMutableArray *filenameExtensions = [NSMutableArray array];
NSArray *draggedFilenames = [self.files objectsAtIndexes:rowIndexes];
for (NSString *filename in draggedFilenames) {
NSString *filenameExtension = [filename pathExtension];
if (filenameExtension.length) {
[filenameExtensions addObject:filenameExtension];
}
}
[pboard setPropertyList:filenameExtensions
forType:NSFilesPromisePboardType];
return YES;
}
Then in your names-of-promisedFiles method:
- (NSArray *)tableView:(NSTableView *)aTableView
namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
forDraggedRowsWithIndexes:(NSIndexSet *)indexSet {
NSArray *draggedFilenames = [self.files objectsAtIndexes:indexSet];
for (NSString *filename in draggedFilenames) {
// do your processing of files in here
// if it may take a long time, you might need to do it on a background
// thread
NSString *fullPathToOriginal = nil;
NSString *destPath =
[[dropDestination path] stringByAppendingPathComponent:filename];
}
return draggedFilenames;
}
You should be able to calculate the original file path (not sure how you're determining it, so I left it nil
in the code above) and the destination file path (using something like in the code above).
Something to watch out for.
In NSPasteboard.h
there is a comment that says:
/* Use of pboard types should be replaced with use of UTIs.
Pboard types will be deprecated in a future release. */
And after the NSFilesPromisePboardType
definition says:
// Use (NSString *)kPasteboardTypeFileURLPromise
I just spent a few hours banging my head against a brick wall because I was passing in (NSString *)kPasteboardTypeFileURLPromise
instead of NSFilesPromisePboardType
in a few places.
It looks like they don't do quite the same thing. I couldn't work out why:
tableView:namesOfPromisedFilesDroppedAtDestination:forDraggedRowsWithIndexes
wasn't being called. When I switched back to NSFilesPromisePboardType
,
suddenly it was called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With