How to Allow Users To Drag Files Out of Cocoa App
Asked Answered
N

1

7

I am working on a macOS application that involves creating a folder in a temporary directory.

How can I allow users to drag a folder icon off of the Cocoa app and onto their desktop (or into Finder and other apps) so that dropping it will actually paste the folder created by the app?

I have so far been able to write the finished folder that I want to save to a temporary directory. How do I place a folder icon on the application that can be dragged into the Finder? Thanks!

The complete code I'm currently using is this:

    class draggableFolder: NSImageView {
    override func mouseDown(with theEvent: NSEvent) {
        let pasteboardItem = NSPasteboardItem()
       // pasteboardItem.availableType(from: [NSPasteboard.PasteboardType.fileURL])
        pasteboardItem.setDataProvider(self, forTypes: [kUTTypeURL as NSPasteboard.PasteboardType])
        let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardItem)
        draggingItem.setDraggingFrame(self.bounds, contents:self.image)

        beginDraggingSession(with: [draggingItem], event: theEvent, source: self as NSDraggingSource)
    }


}

extension draggableFolder: NSDraggingSource {
    func draggingSession(_ session: NSDraggingSession, sourceOperationMaskFor context: NSDraggingContext) -> NSDragOperation {
        return NSDragOperation.generic
    }
}

extension draggableFolder: NSPasteboardItemDataProvider {
    func pasteboard(_ pasteboard: NSPasteboard?, item: NSPasteboardItem, provideDataForType type:
        NSPasteboard.PasteboardType) {
        print("dataprovider")
        if let pasteboard = pasteboard, type.rawValue == String(describing: kUTTypeURL) {
           let folder = currentIconsetURL
            print("dataprovider2")
            print(NSURL.init(fileURLWithPath: currentIconsetURL))
            pasteboard.clearContents()
            pasteboard.declareTypes([NSPasteboard.PasteboardType.fileNameType(forPathExtension: "appiconset")], owner: nil)
            pasteboard.writeObjects([(URL.init(fileURLWithPath: currentIconsetURL).absoluteURL as NSURL) as NSPasteboardWriting])


        }
    }
}
Neale answered 19/1, 2018 at 2:1 Comment(6)
What is the question, how to start a drag, how to create a folder or something else? Tell us what you've done so far.Lillie
Thank you@Willeke. I have updated the question.Neale
@Lillie I have updated the question to contain the code I'm using.Neale
Take a look at NSFilePromiseProvider, the documentation is missing but you can read about it in AppKit Release Notes (macOS 10.12 and Earlier), Dragging File Promise Source.Lillie
Thanks @willeke. I've read that NSFilePromiseProvider is used when you need to create a file that doesn't exist on the filesystem. Is that correct? I the I want to appear in Finer already exists in my app's temporary directory, and I want the user to be able to move it elsewhere.Neale
You can "create" a file by moving it from the temporary directory.Lillie
E
4

Sadly, the drag and drop guide Apple has is based entirely on the old deprecated API: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/DragandDrop/DragandDrop.html

The rough outline for what you're asking, using the modern API is:

  • You need something (ex, your view) to implement the NSDraggingSource protocol to return that it supports the Copy operation only (draggingSession(_:sourceOperationMaskFor:)).
  • From within mouseDown (with a tracking loop) or mouseDragged, once the user's drag has moved a certain distance from its original location (3 or 4 points is all), then you should start a dragging session (NSView beginDraggingSession)
  • The session should contain one NSDraggingItem where you pass in the URL for the folder (as an NSURL, not a Swift URL, because only the former conforms to NSPasteboardWriter).
Eternize answered 19/1, 2018 at 17:30 Comment(5)
Thank you @seth. I'm running into the issue where the dragged file just writes the folder's path to a clipping file. The issue seems to be in the file type. I'm using kUTTypeFolder currently. Is this correct?Neale
Where are you using that UTI? In the most basic form, you'd literally just hand over the URL and nothing else: let draggingItem = NSDraggingItem(pasteboardWriter: fileURL as NSURL); ...; beginDraggingSession(with: [draggingItem], event: currentEvent, source: self)Eternize
If I use the code in the above comment, I cannot run seem to specify the data provider. How would I do this? I suspect this is the issue because when I attempt to drag the folder onto the desktop a grey prohibitory sign appears on the folder image.Neale
Just as an update, I nearly got everything working. The only issue is that when I drag the file to the desktop, the file isn't written to the location..Neale
Hi @Jake3231, did you get a solution for dragging file outside the cocoa app? If yes, can you please share the solution?Diplomate

© 2022 - 2024 — McMap. All rights reserved.