I'm at a stand still and I need guidance.
I am trying to implement drag and drop in a MAC OS X app, using NSPasteboardWriting, NSPasteboardReading, NSPasteboardItemProvider.
it's not working, but it's not crashing. It's just not working.
I have tons of code in this. It's actually very alarming just how much leg workhas to be done in order to enable drag n drop, but as far as I am able to tell... I should be getting something. a crash. a malformed object. an error message. Nope.
I've tried to make a compact copy of all of the pertinent code:
// in the NSDraggingSource which is also the NSPasteboardItemProvider:
// this is the function that ultimately handles mouseDown in a delegate:
open override func mouseDown(event : NSEvent, view: NSView, forProp: BKControlProps)->Bool{
if let aNode = forProp.representedObject as? docDataObj{
pasteboardNode = aNode
}
let pasteboardItem = NSPasteboardItem()
pasteboardItem.setDataProvider(self, forTypes: [NSPasteboard.PasteboardType(rawValue: "com.bktools.node")])
let dragImg = NSImage.init(byReferencing: Bundle.main.urlForImageResource("dragImg")!)
let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardItem)
let winLoc = event.locationInWindow
draggingItem.setDraggingFrame(CGRect(x: winLoc.x - 25, y: winLoc.y - 25, width: 50, height: 50), contents:dragImg)
view.beginDraggingSession(with: [draggingItem], event: event, source: self as! NSDraggingSource)
return true
}
// this is the pasteboardItem provider stuff:
// the delegate is a to-many delegate, so we needed a way to temporarily store the item being dragged.you can see that we set that in the mousedown
var pasteboardNode : docDataObj? = nil
func pasteboard(_ pasteboard: NSPasteboard?, item: NSPasteboardItem, provideDataForType type: NSPasteboard.PasteboardType) {
if let realItem = pasteboardNode{
pasteboard?.writeObjects([realItem])
}
}
// now on to the actual object that is transported, which is NSPasteboardReading, and Wiriting, it is also NSCoding compliant.
// note: this method makes no sense to me. we get data passed, which contains a complete copy of an object, but by the time we get it, we already have an instance of that object type.
// but it doesn't yet matter: this method is never called. haven't even come close to testing it.
required init?(pasteboardPropertyList propertyList: Any, ofType type: NSPasteboard.PasteboardType) {
super.init()
if let data = propertyList as? Data{
do {
let newObject = try NSKeyedUnarchiver.unarchivedObject(ofClass: docDataObj.self, from: data)
if let anItem = newObject{
self.name = anItem.name
self.type = anItem.type
self.channels = anItem.channels
self.children = anItem.children
}
} catch {
debugPrint("initing from property list failed trying to unarchive")
}
}
static func readableTypes(for pasteboard: NSPasteboard) -> [NSPasteboard.PasteboardType] {
return [NSPasteboard.PasteboardType(rawValue: "com.bktools.node")]
}
func pasteboardPropertyList(forType type: NSPasteboard.PasteboardType) -> Any? {
var data : Data? = nil
do {
data = try NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false)
} catch {
debugPrint("archiveFailed for drag of node in toolbox")
}
return data
}
func writableTypes(for pasteboard: NSPasteboard) -> [NSPasteboard.PasteboardType] {
return [NSPasteboard.PasteboardType(rawValue: "com.bktools.node")]
}
// now at the dragging destination:
// handling drops.
open override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation{
debugPrint("drag enter")
return [.copy, .move]
}
open override func draggingUpdated(_ sender: NSDraggingInfo) -> NSDragOperation{
debugPrint("drag updated")
return [.copy, .move]
}
open override func draggingExited(_ sender: NSDraggingInfo?){
debugPrint("drag exited")
// don't do anything... or... update the ui in some way.
}
open override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool{
debugPrint("prepare for drop")
return true
}
open override func performDragOperation(_ sender: NSDraggingInfo) -> Bool{
debugPrint("accepting drop")
let pasteBoard = sender.draggingPasteboard
// we are doing some veracity testing below here:
let types = pasteBoard.types
// types returns 'com.bktools.node' in an array.
let item = pasteBoard.canReadObject( forClasses: [docDataObj.self], options:nil)
// item returns true.
// here is the problem. when this code is executed : nodes returns as an empty array.
// the docDataObj being transported is actually archived, turned into Data, and sent to the pasteboard.
// the pastebord shows that it has 1 item... and that it is the correct type This method does not return a nil value. i returns an empty array.
// and at no point, is a docDataObj instantiated from a propertyList.
if let nodes = pasteBoard.readObjects(forClasses: [docDataObj.self], options:nil) as? [docDataObj]{
self.appData?.docData += nodes
return true
}
return true
}
open override func concludeDragOperation(_ sender: NSDraggingInfo?){
debugPrint("drop completed")
}