Reputation: 43
I want to write some fileURL's to general pasteboard using [pasteboard writeObjects:pasteboardArray];
where pasteboard
is an object of general pasteboard and pasteboardArray
is a NSArray of NSURL's. It writes urls on pasteboard like
file://localhost/Usr/
file://localhost/Vol/
...and so on
I want to write these URL's as following
Usr
Vol
..and so on
i.e only the name of file/Directory as the system does on copying any file/Directory.
Upvotes: 3
Views: 2801
Reputation: 90531
For each item on the pasteboard, there can be multiple types of data. When you write an NSURL
to the pasteboard, it puts types such as public.file-url
(the URL as UTF-8 text), NSFilenamesPboardType
(an array of file path strings, serialized to an XML property list), "Apple URL pasteboard type" (an array of file URL strings, serialized to an XML property list), and public.utf8-plain-text
(the URL as UTF-8 text).
When you copy a file in the Finder, it puts many of those same types, although it seems to convert the URLs to file reference URLs first. In addition, it puts the file's icon as an ICNS and a TIFF image. However, the public.utf8-plain-text
type has just the file's name, not its URL. That string is also present with type public.utf16-plain-text
.
So, presumably, the Finder is not simply using -writeObjects:
to populate the pasteboard. It may be using the older approach of -declareTypes:owner:
and/or -addTypes:owner:
followed by -set...:forType:
(e.g. -setString:forType:
). Or it may be constructing instances of NSPasteboardItem
with the desired types and data using its -set...:forType:
methods and then writing those items to the pasteboard.
For your needs it would probably be sufficient to do:
[pasteboard writeObjects:arrayOfURLs];
NSMutableString* names = [NSMutableString string];
for (NSURL* url in arrayOfURLs)
{
NSString* name;
if ([url getResourceValue:&name forKey:NSURLLocalizedNameKey error:NULL])
{
if (names.length)
[names appendString:@"\r"];
[names appendString:name];
}
}
if (names.length)
{
[pasteboard addTypes:@[(__bridge NSString*)kUTTypeUTF8PlainText] owner:nil];
[pasteboard setString:names forType:(__bridge NSString*)kUTTypeUTF8PlainText];
}
Note: when you write multiple URLs to the pasteboard, there are multiple items, each with multiple types. However, certain types are for the collection as a whole and those only go on the first item. The plain string types and NSFilenamesPboardType
are like this. The above code puts the plain string on the first item, and includes display names for all of the URLs separated by a carriage return (which is what the Finder does).
All of the above said, it's not clear if you wanted the pasteboard to contain just the display names for the URLs and not the URLs themselves in any representation. In that case, just create an array of string from the display names of the URLs and pass that array to -writeObjects:
and you're done.
Update:
I've found a way to more closely match what the Finder does while taking a bit of a shortcut:
NSMutableArray* arrayOfPaths = [arrayOfURLs valueForKey:@"path"];
[pasteboard setPropertyList:arrayOfPaths forType:NSFilenamesPboardType];
NSMutableString* names = [NSMutableString string];
BOOL first = YES;
for (NSURL* url in arrayOfURLs)
{
NSString* name;
if (![url getResourceValue:&name forKey:NSURLLocalizedNameKey error:NULL])
name = @"";
if (first)
first = NO;
else
[names appendString:@"\r"];
[names appendString:name];
}
if (names.length)
{
[pasteboard addTypes:@[(__bridge NSString*)kUTTypeUTF8PlainText] owner:nil];
[pasteboard setString:names forType:(__bridge NSString*)kUTTypeUTF8PlainText];
}
When you set the data for type NSFilenamesPboardType
, Cocoa automatically sets up multiple items, one for each element in the array. The second and subsequent ones each have just the single type public.file-url
. The first item has that type plus most of the others that the Finder puts on the pasteboard, other than the image types. Then, it's just a matter of setting the string value on the first item.
It's important to include the NSFilenamesPboardType
type because that's how multiple files were represented on the pasteboard before support for multiple pasteboard items was added. Some apps may still depend on that.
Also, if you provide the string data for each item separately (as done in your own answer), then an app which asks for the string from the pasteboard as a whole (i.e. [pasteboard stringForType:NSStringPboardType]
) gets them concatenated with newlines. That's slightly different from what the app would get when files are copied from the Finder, where the strings are concatenated with carriage returns. Some apps may not cope well with the difference.
Upvotes: 3
Reputation: 167
NSMutableArray *archive=[NSMutableArray array];
for (int i = 0; i < [pasteboardArray count]; i++) {
NSPasteboardItem *item = [[NSPasteboardItem alloc] init];
NSURL *url = [pasteboardArray objectAtIndex:i];
if (url != nil) {
[item setString:[url lastPathComponent] forType:(__bridge NSString*)kUTTypeUTF8PlainText];
NSString *str = [NSString stringWithFormat:@"%@",url];
[item setData:[str dataUsingEncoding:NSUTF8StringEncoding] forType:(__bridge NSString*)kUTTypeFileURL];
}
[archive addObject:item];
}
[pasteboard writeObjects:archive];
This worked for me, where pasteboard
is an object of general pasteboard and pasteboardArray
is a NSArray of NSURL's. Any better solutions are welcome...
Upvotes: 1