Post

Replies

Boosts

Views

Activity

Reply to Is Code-level support still allowing cases dealing with macOS 10.9 Mavericks?
This issue has been solved. Here's the things to beware of when migrating NSStackView things to macOS 10.9: (Not talking about macOS 10.10 - 10.12 due to lack of tests.) macOS 10.9 doesn't draw shadow for opaque windows. In macOS 10.9, even if you set .isOpaque = true and the background color to NSColor.clear, it won't make clear backgrounds like what macOS 10.13 and later behaves. NSStackView in macOS 10.9 bugs, requiring every of its components to be constraint-set in order to make the entire view size looks as big as what behaves on macOS 10.13 and later. The subViews of an NSStackView might be more than the views you actually added into it. Instead of directly enumerating the .subviews of an NSStackView, you create another Swift array to track these subviews before adding them to the NSStackView instance.
Feb ’23
Reply to How to get the bundle identifier of the app bundle dragged into an NSTableView?
I solved this. Prerequisites: NSTableView instance must have its DataSource object assigned: myNSTableViewInstance.dataSource = *** The DataSource object conforms to NSTableViewDataSource protocol, having two necessary functions implemented (will discuss below). Whenever appropriate (e.g.: .windowDidLoad(), .viewDidLoad(), etc.), register the .registerForDraggedTypes for NSTableView instance. In the prerequisite 3, the registration method is: // Constructing the NSPasteboard.PasteboardType. tblClients.registerForDraggedTypes([.init(rawValue: kUTTypeFileURL as String)]) // Compatible with macOS 10.9 Mavericks. tblClients.registerForDraggedTypes([.fileURL]) // Since macOS 10.13 High Sierra. In the prerequisite 2, the registration method is: // Constructing the NSPasteboard.PasteboardType. .init(rawValue: kUTTypeApplicationBundle as String) We start implementing. Suppose that (in this case): the DataSource object is the WindowController itself. the name of the NSTableView instance is tblClients. Since the two functions mentioned above shares a lot of things, we extract them as a standalone function with lambda expressions: /// See whether the incoming NSDraggingInfo is an array of App Bundles. /// - Parameters: /// - info: the incoming NSDraggingInfo object。 /// - onError: On error perform this given lambda expression. /// - handler: When conditions are met, perform this given lambda expression to process the URL array. private func validatePasteboardForAppBundles( neta info: NSDraggingInfo, onError: @escaping () -> Void?, handler: @escaping ([URL]) -> Void? ) { 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 } handler(urls) } Finally, the two implementations. The one to check whether the dragged file object is the one we need to let the NSTableView response to: 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。 handler: { _ in } ) return result } The handling process once the mouse click releases: func tableView( _: NSTableView, acceptDrop info: NSDraggingInfo, row _: Int, dropOperation _: NSTableView.DropOperation ) -> Bool { var result = true // Outer report: Operation successful or not. validatePasteboardForAppBundles( neta: info, onError: { result = false } // NSDragOperationNone。 ) { theURLs in var dealt = false // Inner report. Will be true if at least one URL entry is processed with successful result. theURLs.forEach { url in // See whether this is an app bundle with valid bundleID: guard let bundle = Bundle(url: url), let bundleID = bundle.bundleIdentifier else { return } // Performing customized operations toward this bundleID string: self.applyNewValue(bundleID, highMitigation: true) // Mark this operation as "successful". dealt = true } // Tell the outer report that whether we did at least one successful operation. result = dealt } defer { if result { self.tblClients.reloadData() } } return result } This should work unless there are other things screwed up. $ EOF.
Feb ’23