6

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])


        }
    }
}
Jake3231
  • 703
  • 8
  • 22
  • 1
    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. – Willeke Jan 19 '18 at 08:24
  • 1
    Thank you@Willeke. I have updated the question. – Jake3231 Jan 19 '18 at 17:06
  • @Willeke I have updated the question to contain the code I'm using. – Jake3231 Jan 23 '18 at 01:37
  • Take a look at `NSFilePromiseProvider`, the documentation is missing but you can read about it in [AppKit Release Notes (macOS 10.12 and Earlier)](https://developer.apple.com/library/content/releasenotes/AppKit/RN-AppKitOlderNotes/), Dragging File Promise Source. – Willeke Jan 23 '18 at 10:24
  • 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. – Jake3231 Jan 23 '18 at 15:55
  • You can "create" a file by moving it from the temporary directory. – Willeke Jan 25 '18 at 16:05

1 Answers1

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).
seth
  • 1,647
  • 1
  • 12
  • 20
  • 1
    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? – Jake3231 Jan 23 '18 at 00:18
  • 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)` – seth Jan 24 '18 at 01:48
  • 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. – Jake3231 Jan 24 '18 at 03:29
  • 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.. – Jake3231 Jan 24 '18 at 03:46
  • Hi @Jake3231, did you get a solution for dragging file outside the cocoa app? If yes, can you please share the solution? – sam Jul 23 '19 at 14:53