From 04f1889923f62605580a1e1be88f42e2f0b2cb50 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Fri, 24 Feb 2023 19:16:59 +0800 Subject: [PATCH] ClientListMgr // Allow dragging app bundles to the window. --- .../WindowControllers/CtlClientListMgr.swift | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/Source/Modules/WindowControllers/CtlClientListMgr.swift b/Source/Modules/WindowControllers/CtlClientListMgr.swift index 7d0a7a15..325cb987 100644 --- a/Source/Modules/WindowControllers/CtlClientListMgr.swift +++ b/Source/Modules/WindowControllers/CtlClientListMgr.swift @@ -32,6 +32,7 @@ class CtlClientListMgr: NSWindowController, NSTableViewDelegate, NSTableViewData window?.setPosition(vertical: .center, horizontal: .right, padding: 20) localize() tblClients.delegate = self + tblClients.registerForDraggedTypes([.init(rawValue: kUTTypeFileURL as String)]) tblClients.allowsMultipleSelection = true tblClients.dataSource = self tblClients.action = #selector(onItemClicked(_:)) @@ -225,6 +226,60 @@ extension CtlClientListMgr { return Self.clientsList[row] } + /// 檢查傳入的 NSDraggingInfo 當中的 URL 對應的物件是否是 App Bundle。 + /// - Parameters: + /// - info: 傳入的 NSDraggingInfo 物件。 + /// - onError: 當不滿足判定條件時,執行給定的 lambda expression。 + /// - handler: 當滿足判定條件時,讓傳入的 lambda expression 處理已經整理出來的 URL 陣列。 + private func validatePasteboardForAppBundles( + neta info: NSDraggingInfo, onError: @escaping () -> Void?, handler: (([URL]) -> Void)? = nil + ) { + let board = info.draggingPasteboard + let type = NSPasteboard.PasteboardType(rawValue: kUTTypeApplicationBundle as String) + let options: [NSPasteboard.ReadingOptionKey: Any] = [ + .urlReadingFileURLsOnly: true, + .urlReadingContentsConformToTypes: [type], + ] + guard let urls = board.readObjects(forClasses: [NSURL.self], options: options) as? [URL], !urls.isEmpty else { + onError() + return + } + if let handler = handler { + handler(urls) + } + } + + func tableView( + _: NSTableView, validateDrop info: NSDraggingInfo, proposedRow _: Int, + proposedDropOperation _: NSTableView.DropOperation + ) -> NSDragOperation { + var result = NSDragOperation.copy + validatePasteboardForAppBundles( + neta: info, onError: { result = .init(rawValue: 0) } // 對應 NSDragOperationNone。 + ) + return result + } + + func tableView( + _: NSTableView, acceptDrop info: NSDraggingInfo, + row _: Int, dropOperation _: NSTableView.DropOperation + ) -> Bool { + var result = true + validatePasteboardForAppBundles( + neta: info, onError: { result = false } // 對應 NSDragOperationNone。 + ) { theURLs in + var dealt = false + theURLs.forEach { url in + guard let bundle = Bundle(url: url), let bundleID = bundle.bundleIdentifier else { return } + self.applyNewValue(bundleID, highMitigation: true) + dealt = true + } + result = dealt + } + defer { if result { tblClients.reloadData() } } + return result + } + private func localize() { guard let window = window else { return } window.title = NSLocalizedString("Client Manager", comment: "")