Search code examples
swiftcocoanspasteboard

Swift. How to allow dragging an URL from the browser to a NSView


I have an NSView that accepts dropped files and store their fileURLs but I'd like it to accept HTTP URLs dragged from an Internet Browser as well. I mean, the same behavior as dragging it to Finder to create a .webloc file but inside my app. What's the proper PasteboardType to use? I've tried .fileContents, .urL, .fileURL, .html, .string… to no avail.

EDIT: This is the relevant code as requested:

    required init?(coder: NSCoder) {

    super.init(coder: coder)

    wantsLayer = true
    layer?.backgroundColor = NSColor.clear.cgColor

    registerForDraggedTypes([NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType"), .URL, .string, .html])
}

override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {

    showFrame(true)

    return .copy
}

override func draggingExited(_ sender: NSDraggingInfo?) {

    showFrame(false)
}

override func draggingEnded(_ sender: NSDraggingInfo) {

    showFrame(false)
}

override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {

    if let board = sender.draggingPasteboard.propertyList(forType: NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType")) as? NSArray
    {
        print("FILE: \(board)")
        return true
    } else if let board = sender.draggingPasteboard.propertyList(forType: .URL) as? NSArray {
        print("URL: \(board)")
        return true
    } else if let board = sender.draggingPasteboard.propertyList(forType: .string) as? NSArray {
        print("STRING: \(board)")
        return true
    } else if let board = sender.draggingPasteboard.propertyList(forType: .html) as? NSArray {
        print("HTML: \(board)")
        return true
    }

    return false
}

EDIT AGAIN:

I've found what is the problem. It turns out that I have a tableview inside this NSView and it is registered for .string dragged types too (to be able to reorder the cells). It seems the table "swallows" the URL type but let the filenames pass through. I'll have to handle this issue but this is another question.


Solution

  • The data on the pasteboard is not a property list and URL is not a property list compatible class. Use readObjects(forClasses:options:) instead of propertyList(forType:).

    if let board = sender.draggingPasteboard().readObjects(forClasses: [NSURL.self]) {
        print("URL: \(board)")
        return true
    }