Fwd: NSPasteboardItem kPasteboardTypeFileURLPromise
Fwd: NSPasteboardItem kPasteboardTypeFileURLPromise
- Subject: Fwd: NSPasteboardItem kPasteboardTypeFileURLPromise
- From: David Riggle <email@hidden>
- Date: Wed, 29 Feb 2012 07:20:50 -0800
I've been struggling with the new NSPasteboard APIs as well. The lack of sample code is appalling. I finally got file promises to work by incorporating some low level pasteboard manager calls. Note that NSPasteboard is not toll-free bridged with PasteboardRef, but you can go back & forth between the two worlds via the pasteboard name. Also note there is a warning on the console about no HFSPromises on the pasteboard, but the drag & drop works anyway. Hopefully all this will still work in the App Sandbox.
// ... write file URL promise to the pasteboard
ImageObjectPasteboardItem *item = [ImageObjectPasteboardItem itemWithImageObject:imageObject];
[item setDataProvider:self forTypes:[NSArray arrayWithObject:(NSString *)kPasteboardTypeFileURLPromise]];
[item setString:(NSString *)kUTTypeImage forType:(NSString *)kPasteboardTypeFilePromiseContent];
[pasteboard writeObjects:[NSArray arrayWithObject:item]];
// ... provide promised file URL
- (void)pasteboard:(NSPasteboard *)pasteboard item:(ImageObjectPasteboardItem *)item provideDataForType:(NSString *)type
{
if ([type isEqualToString:(NSString *)kPasteboardTypeFileURLPromise]) {
// get paste location from low level pasteboard
PasteboardRef pboardRef = NULL;
PasteboardCreate((__bridge CFStringRef)[pasteboard name], &pboardRef);
if (pboardRef != NULL) {
PasteboardSynchronize(pboardRef);
CFURLRef urlRef = NULL;
PasteboardCopyPasteLocation(pboardRef, &urlRef);
if (urlRef != NULL) {
// create file at drop location
NSString *folderPath = [(__bridge NSURL *)urlRef path];
ImageObject *imageObject = [item imageObject];
NSString *path = [imageObject writeToFileInFolder:folderPath];
// set UTF-8 encoded file URL for promise data
NSURL *fileURL = [NSURL fileURLWithPath:path isDirectory:NO];
[item setString:[fileURL absoluteString] forType:(NSString *)kPasteboardTypeFileURLPromise];
// clean up
CFRelease(urlRef);
}
CFRelease(pboardRef);
}
}
}
// ... read file URL promise from the pasteboard
NSArray *items = [pasteboard readObjectsForClasses:[NSArray arrayWithObject:[NSPasteboardItem class]] options:nil];
for (NSPasteboardItem *item in items) {
// we only want image files
NSString *uti = [item stringForType:(NSString *)kPasteboardTypeFilePromiseContent];
if (UTTypeConformsTo((__bridge CFStringRef)uti, kUTTypeImage)) {
// set paste location via low level pasteboard
PasteboardRef pboardRef = NULL;
PasteboardCreate((__bridge CFStringRef)[pasteboard name], &pboardRef);
if (pboardRef != NULL) {
PasteboardSynchronize(pboardRef);
PasteboardSetPasteLocation(pboardRef, (__bridge CFURLRef)[NSURL fileURLWithPath:m_addedGraphicsPath isDirectory:YES]);
// ask sender to create file at destination & return UTF-8 encoded URL
NSString *urlString = [item stringForType:(NSString *)kPasteboardTypeFileURLPromise];
if (urlString != nil) {
NSURL *fileURL = [NSURL URLWithString:urlString];
NSString *filePath = [fileURL path];
// ... do something with filePath
}
CFRelease(pboardRef);
}
}
}
On Aug 12, 2011, at 11:42 AM, Gabriele de Simone <email@hidden> wrote:
> Date: Fri, 12 Aug 2011 17:55:46 +0200
> From: Gabriele de Simone <email@hidden>
> Subject: NSPasteboardItem kPasteboardTypeFileURLPromise
> To: email@hidden
> Message-ID: <email@hidden>
> Content-Type: text/plain; charset=us-ascii
>
> Hi everyone,
>
> I am trying to implement "promise" type file drags from my app to the Finder using the new, 10.6-and-later NSPasteboardItem APIs. I found almost no information about it, and it didn't seem to make sense.
>
> It starts in the outlineView:writeItems:toPasteboard: method of my NSOutlineViewDataSource instance. In there, I allocate various NSPasteboardItems for all files being dragged.
>
> [...]
>
> NSArray * pasteboardTypes = [NSArray arrayWithObjects:
> (NSString *)kPasteboardTypeFileURLPromise,
> (NSString *)kPasteboardTypeFilePromiseContent, nil];
> NSMutableArray * pasteboardItems = [NSMutableArray array];
>
> for ( <however many files are selected> ) {
>
> NSPasteboardItem * pasteboardItem = [[[NSPasteboardItem alloc] init] autorelease];
>
> [pasteboardItem setDataProvider:provider forTypes:pasteboardTypes];
> [pasteboardItems addObject:pasteboardItem];
>
> }
>
> [pasteboard writeObjects:pasteboardItems];
>
> [...]
>
> As the drag moves away from my application and over the Desktop, the "provider" instance used above is called once for each NSPasteboardItem, to get the kPasteboardTypeFilePromiseContent. That part is (presumably) easy, and my provider is returning the UTI for the promised file, based on its contents. In the source code below, I have inserted kUTTypePNG to simplify:
>
> - (void)pasteboard:(NSPasteboard *)pasteboard item:(NSPasteboardItem *)item provideDataForType:(NSString *)type {
>
> if ( [type isEqualToString:(NSString *)kPasteboardTypeFilePromiseContent] ) {
>
> [item setPropertyList:kUTTypePNG forType:type];
>
> } else if ( [type isEqualToString:(NSString *)kPasteboardTypeFileURLPromise] ) {
>
> // What to do here?
>
> }
>
> }
>
> The Finder seems happy with my UTI, and allows the drag to continue. The problem is that if I drop the files onto the desktop, the NSPasteboardDataProvider instance is called again, this time to get the kPasteboardTypeFileURLPromise data.
>
> Intuitively, one would think that you have to:
> - Create the file that was promised, and keep the URL to that file handy.
> - Call one of the methods on NSPasteboardItem to supply the URL of the promised file.
> - Allow the Finder to copy/move the files at will.
>
> Unfortunately, there is no -[NSPasteboardItem setURL:forType:] method, no -[NSURL writeToPasteboardItem:] method, or anything else that would seem to "fit" this scenario.
>
> What am I missing?
>
> Thanks,
> Gabe
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden