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 protected]> wrote:
> Date: Fri, 12 Aug 2011 17:55:46 +0200
> From: Gabriele de Simone <[email protected]>
> Subject: NSPasteboardItem kPasteboardTypeFileURLPromise
> To: [email protected]
> Message-ID: <[email protected]>
> 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 protected])
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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com
This email sent to [email protected]