One of the responsibilities of any object implementing the <draggingDestination>
protocol is to maintain an array of data-types which informs others what sort of data will trigger the methods you mention in your question. To allow your subclass to deal with drags from Finder or the desktop, I've found you need to register for three pasteboard types.
/* Sorry, not using Swift yet */
// MyNSTextField.m
- (void)awakeFromNib {
[self registerForDraggedTypes:@[NSPasteboardTypeString,
NSURLPboardType,
NSFilenamesPboardType]];
}
At least on OS X 10.9, this is sufficient to fire your draggingEntered
method. If all you want on the pasteboard is the filename, rather than the full URL or path, you need to (i) extract the name, (ii) clear the pasteboard and (iii) add just the name back onto the pasteboard:
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
NSDragOperation operation = NSDragOperationNone;
NSPasteboard *pBoard = [sender draggingPasteboard];
NSArray *array = [pBoard readObjectsForClasses:@[[NSURL class], [NSString class]]
options:nil];
if ([array count] > 0) {
NSString *filename;
if ([[array firstObject] isKindOfClass:[NSURL class]]) {
// Possibly a file dragged from Finder
NSURL *url = [array firstObject];
filename = [[url pathComponents] lastObject];
} else if ([[array firstObject] isKindOfClass:[NSString class]]) {
// Possibly a file dragged from the desktop
NSString *path = [array firstObject];
BOOL isPath = [[NSFileManager defaultManager] fileExistsAtPath:path];
if (isPath) {
filename = [path lastPathComponent];
}
}
if (filename) {
[pBoard clearContents];
[pBoard setData:[filename dataUsingEncoding:NSUTF8StringEncoding]
forType:NSPasteboardTypeString];
operation = NSDragOperationGeneric;
}
}
return operation;
}
On occasion the drag into the text field will happen so quickly that the above method is not triggered, in which case you're back to the same problem. One way around this is to implement the following text field delegate method:
// From NSTextFieldDelegate Protocol
- (void)textDidChange:(NSNotification *)notification
In this method you can compare the contents of your text field, with the contents of the pasteboard, if you're field now contains a valid system path and this path matches the contents of the pasteboard, you know you need to adjust the string in the text field. Fortunately, this seems to happen so quickly that it looks just like a normal paste operation.