I’d like to use the pasteboard to copy files between apps and to Finder.
What I have so far is:
For Each file As FolderItem In files
Dim pbItem As New NSPasteboardItemMBS
Dim url As String = file.URLPath
Dim name As String = file.Name
pbItem.stringForType(NSPasteboardMBS.NSURLPboardType) = url.ConvertEncoding(Encodings.UTF8)
pbItem.stringForType(NSPasteboardMBS.NSPasteboardTypeString) = name.ConvertEncoding(Encodings.UTF8)
pbItems.Append pbItem
Next file
Dim b As Boolean = pb.SetPasteboardItems(pbItems)
If b = False Then Beep
But this is giving resulting in b = false on the penultimate line.
What am I missing?
It can be done with the native Xojo clipboard class.
Public Sub folderitem(extends c as clipboard, assigns value as folderItem)
#if targetMacOS then
c.RawData( "public.file-url" ) = value.URLPath
c.rawData( "public.utf8-plain-text" ) = value.displayName
#endif
End Sub
But reading a folderitem from the clipboard requires a library because of a bug in Xojo. <https://xojo.com/issue/63416>
Public Function folderitem(extends c as clipboard) as folderItem
#if TargetMacOS then
if c.RawDataAvailable( "public.file-url" ) then
Dim fURL as string = c.rawdata( "public.file-url" )
Dim nurl as integer = NSURLWithString( NSURLClass, fURL )
return new folderItem( NSURLPath( nurl ), folderItem.pathModes.native, false )
end if
#endif
End Function
1 Like
Thanks again Sam. Yes this seems to work for individual files.
I was hoping to get something that would allow copying multiple files to the pasteboard/clipboard.
You may need to add multiple items.
So one item per NSPasteboardMBS.NSURLPboardType type.
That’s what I was trying to achieve with my code at the top of this thread. But it fails on
Dim b As Boolean = pb.SetPasteboardItems(pbItems).
Is there another way to do it?
I see, to my surprise Xojo doesn’t have a function for multiple items… Wow…
Edit: Just checked, when you copy files in the Finder, it adds multiple clipboard items, each one contains a single file. Which means none of my code handles this
This code put a bunch of files from my desktop on to the pasteboard, which I could then paste into another folder in the finder. Use the MBS equivalents.
dim paths() as string = array( "/Volumes/rowlands/Desktop/OWDocumentSender.xojo_binary_project", _
"/Volumes/rowlands/Desktop/Screen Shot 2021-08-10 at 10.55.57 AM.png", _
"/Volumes/rowlands/Desktop/Screen Shot 2021-08-07 at 8.52.40 AM.png", _
"/Volumes/rowlands/Desktop/OWFileWell.xojo_binary_project" )
// --- NSURL conforms to the NSPasteboardWriting protocol, so we only need an array of NSURLS.
Dim nurlArray as integer = NSMutableArrayWithCapacity( NSMutableArrayClass, ubound( paths ) )
For each currentPath as string in paths
NSMutableArrayAddObject( nurlArray, NSURLWithFilePath( NSURLClass, currentPath ) )
Next
// --- Once we have our NSArray of NSURLs, we then ask the NSPasteboard to write it.
Dim pb as integer = NSPasteboard_generalPasteboard( NSClassFromString( "NSPasteboard" ) )
call NSPasteboard_clearContents( pb )
if NSPasteboard_writeObjects( pb, nurlArray ) = false then
break
end if
1 Like
So, I’ve first added a new variant of SetPasteboardItems taking NSURLMBS objects:
Dim paths() As String
paths.Append "/Users/cs/Pictures/test1.jpg"
paths.Append "/Users/cs/Pictures/test2.jpg"
paths.Append "/Users/cs/Pictures/test3.jpg"
Dim n As NSPasteboardMBS = NSPasteboardMBS.generalPasteboard
Dim URLs() As NSURLMBS
For Each path As String In paths
Dim URL As NSURLMBS = NSURLMBS.fileURLWithPath(path)
URLs.Append URL
Next
Call n.clearContents
If n.SetPasteboardItems(URLs) Then
Break // okay
Else
Break // failed
End If
I will change SetPasteboardItems to take variant array, so you can pass various objects including folder items:
SetPasteboardItems(items() as Variant) as Boolean
New sample code:
Dim paths() As String
paths.Append "/Users/cs/Pictures/test1.jpg"
paths.Append "/Users/cs/Pictures/test2.png"
paths.Append "/Users/cs/Pictures/test3.jpg"
Dim n As NSPasteboardMBS = NSPasteboardMBS.generalPasteboard
Dim files() As Variant
For Each path As String In paths
files.Append new FolderItem(path, FolderItem.PathModes.Native)
Next
Call n.clearContents
If n.SetPasteboardItems(files) Then
Break // okay
Else
Break // failed
End If
Then it works fine now with newer plugins.
Thank you Sam and Christian. Its quick responses like this that make Xojo great.
2 Likes
I believe you could if you’d create a single item with name NSFilenamesPboardType
(or dyn.ah62d4rv4gu8y6y4grf0gn5xbrzw1gydcr7u1e3cytf2gn
, which is the equivalent UTI) as RawData, with the contents being a plist array with the paths, like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<string>/path/to/file1</string>
<string>/path/to/file2</string>
</array>
</plist>
I’ve just tried this:
Dim s As String = k_plist_Header
For Each file As folderitem In files
s = s + EndOfLine + "<String>" + file.NativePath + "</String>"
Next file
s = s + EndOfLine + k_plist_footer
Dim n As NSPasteboardMBS = NSPasteboardMBS.generalPasteboard
Dim i As Integer = n.declareType(NSPasteboardMBS.NSFilenamesPboardType)
n.dataForType(NSPasteboard
MBS.NSFilenamesPboardType) = s
with the result in the clipboard of:
<?xml version="1.0" Encoding="UTF-8"?>
<!DOCTYPE plist Public "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<Array>
<String>/Volumes/Extreme SSD 1TB/test - empty/2020/01/P1011755.JPG</String>
<String>/Volumes/Extreme SSD 1TB/test - empty/2020/01/01/P1011755.JPG</String>
<String>/Volumes/Extreme SSD 1TB/test - empty/2020/Q1/P1011755.JPG</String>
</Array>
</plist>
But this doesn’t seem to work when pasting back to finder or other apps. Also tried using URLPaths - but also not working.
As it is non-urgent I might just wait for Christian’s magic.
Could you wait for me to upload pr2 for the new function for you?
James, use my ShowClipboards (made with Xojo ) to see what your test program puts into the pasteboard and compare that with what the Finder does. Maybe that would help identify the problem.
Hold on - you changed the case of the tags in the XML. That can’t work (it’s never a good idea to “improve” an example before making sure that it’s working with the original).
Here is a working example:
dim s as String = "<?xml version=""1.0"" encoding=""UTF-8""?>"+EndOfLine.Unix+_
"<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">"+EndOfLine.Unix+_
"<plist version=""1.0"">"+EndOfLine.Unix+_
"<array>"+EndOfLine.Unix+_
"<string>/Library/Preferences/com.apple.dock.plist</string>"+EndOfLine.Unix+_
"</array>"+EndOfLine.Unix+_
"</plist>"
// not working:
'dim c as new Clipboard
'c.AddRawData s, "dyn.ah62d4rv4gu8y6y4grf0gn5xbrzw1gydcr7u1e3cytf2gn"
'c.Close
// working, with MBS:
Dim n As NSPasteboardMBS = NSPasteboardMBS.generalPasteboard
call n.clearContents
Dim i As Integer = n.declareType(NSPasteboardMBS.NSFilenamesPboardType)
n.dataForType(NSPasteboardMBS.NSFilenamesPboardType) = s
I agree. In this instance it was caused by copying your xml into a method in the Xojo IDE, which then automatically capitalised the text prior to me copying into constant fields. Note to self. Care when copying XML into IDE.
But yes, your new version does work. Thank you.