[Swift][Cocoa] Drag&Drop したファイルのファイルパスを NSTextFeild に表示する


## 概要
Window 内に Finder 経由でファイルを Drag&Drop したら、ファイルパスを改行で区切って NSTextFeild に表示する。
[ブログ](http://www.macneko.com/entry/drag-and-drop-cocoa-sample)にあげたものと同じもの。

## 使い方
1. 起動する  
![drag-and-drop-cocoa-sample-1.png](https://qiita-image-store.s3.amazonaws.com/0/81221/33eecdd6-7c71-b362-055e-937089a1cd19.png "drag-and-drop-cocoa-sample-1.png")
　  
　  
2. Drag&Drop  
![drag-and-drop-cocoa-sample-2.png](https://qiita-image-store.s3.amazonaws.com/0/81221/e03e6c31-f9ce-b1aa-561e-10edbddcd82a.png "drag-and-drop-cocoa-sample-2.png")  
　
3. 表示される  
![drag-and-drop-cocoa-sample-3.png](https://qiita-image-store.s3.amazonaws.com/0/81221/7963d314-2602-bf2e-c216-684a934eb32e.png "drag-and-drop-cocoa-sample-3.png")





## 実装方法

1. NSView を継承した FileDragDropView クラスを作成して、そこに一連の処理を書く  
2. Storyboard の NSViewController に NSView を配置して、クラスを FileDragDropView にする
3. ビルドしたら完成

## ソースコード
FileDragDropView クラスだけ抽出。

```swift:FileDragDropView
import Cocoa

class FileDragDropView: NSView {

    var acceptableTypes: Set<String> {
        return [NSURLPboardType]
    }
    var nonURLTypes: Set<String>  {
        return [String(kUTTypeText)]
    }
    let filteringOptions = [NSPasteboardURLReadingContentsConformToTypesKey:["public.text"]]
    var label: NSTextField?

    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
    }

    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        setup()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        label = NSTextField(frame: NSRect(x: 20, y: 20, width: self.frame.width - 40, height: 40))
        label?.stringValue = ""
        label?.textColor = NSColor.black
        self.addSubview(label!)
    }
    
    func setup() {
        self.register(forDraggedTypes: Array(acceptableTypes))
    }
    
    func shouldAllowDrag(_ draggingInfo: NSDraggingInfo) -> Bool {
        var canAccept = false
        let pasteBoard = draggingInfo.draggingPasteboard()
        if pasteBoard.canReadObject(forClasses: [NSURL.self], options: filteringOptions) {
            canAccept = true
        } else if let types = pasteBoard.types, nonURLTypes.intersection(types).count > 0 {
            canAccept = true
        }
        return canAccept
    }
    
    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
        let allow = shouldAllowDrag(sender)
        return allow ? .copy : NSDragOperation()
    }
    
    override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
        let allow = shouldAllowDrag(sender)
        return allow
    }
    
    override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
        let pasteBoard = sender.draggingPasteboard() as NSPasteboard
        if let urls = pasteBoard.readObjects(forClasses: [NSURL.self], options: filteringOptions) as? [URL], urls.count > 0 {
            label?.stringValue = ""
            let files = pasteBoard.propertyList(forType: NSFilenamesPboardType) as! [String]
            for file in files {
                label?.stringValue += file + "\n"
            }
            return true
        }
        else if let types = pasteBoard.types, types.contains(NSFilenamesPboardType) {
            label?.stringValue = ""
            let files = pasteBoard.propertyList(forType: NSFilenamesPboardType) as! [String]
            for file in files {
                label?.stringValue += file + "\n"
            }
            return true
        }
        return false
    }
}
```

## 更新履歴
2017/4/27 テキスト形式のファイルのみ Drag&Drop できるようにフィルタリング処理を追加
2017/4/26 初版

## 参考
[[macOS] [Swift3.0] Drag & Dropでファイルパスを取得](http://qiita.com/Akira_Kido_N/items/9fbda65a7efe218d9e12)
[Drag and Drop Tutorial for macOS](https://www.raywenderlich.com/136272/drag-and-drop-tutorial-for-macos)