Question

I've subclassed NSCollectionView and I'm trying to receive dragged files from the Finder. I'm receiving draggingEntered: and returning an appropriate value, but I'm never receiving prepareForDragOperation: (nor any of the methods after that in the process). Is there something obvious I'm missing here?

Code:

- (void)awakeFromNib
{
    [self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
}

- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
    NSLog(@"entered"); //Happens
    NSPasteboard *pboard;
    NSDragOperation sourceDragMask;

    sourceDragMask = [sender draggingSourceOperationMask];
    pboard = [sender draggingPasteboard];

    if ([[pboard types] containsObject:NSFilenamesPboardType])
    {
        NSLog(@"copy"); //Happens
        return NSDragOperationCopy;
    }

    return NSDragOperationNone;
}

- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{
    NSLog(@"prepare"); //Never happens
    return YES;
}
Was it helpful?

Solution

This is pretty late, but I found the problem:

NSCollectionView silently provides an incompatible implementation of:

-(NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender

...and Apple hasn't documented this. If you simply implement that method to re-invoke the draggingEntered method, everything works fine, e.g.:

-(NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender
{
    return [self draggingEntered:sender];
}

(I came to SO hoping to find an explanation of what "magic" this custom implementation provides, since that too is ... undocumented (thanks, Apple!). I'm guessing it does something clever with managing an insertion-point within the CollectionView?).

UPDATE: it seems the special magic is inside the NSCollectionView's delegate object. For some reason, Xcode4 was claiming there was no delegate for me, but assigning it built and ran OK. Check out all the custom / semi-documented drag/drop methods there.

(or just do as I describe above and override the custom behaviour, and implement something that works and you can understand)

OTHER TIPS

You might want to try these delegate methods from the NSCollectionViewDelegate Protocol

- (NSDragOperation)collectionView:(NSCollectionView *)collectionView validateDrop:(id <NSDraggingInfo> )draggingInfo proposedIndex:(NSInteger *)proposedDropIndex dropOperation:(NSCollectionViewDropOperation *)proposedDropOperation;
- (BOOL)collectionView:(NSCollectionView *)collectionView acceptDrop:(id <NSDraggingInfo> )draggingInfo index:(NSInteger)index dropOperation:(NSCollectionViewDropOperation)dropOperation;

- (BOOL)collectionView:(NSCollectionView *)collectionView canDragItemsAtIndexes:(NSIndexSet *)indexes withEvent:(NSEvent *)event;
- (NSImage *)collectionView:(NSCollectionView *)collectionView draggingImageForItemsAtIndexes:(NSIndexSet *)indexes withEvent:(NSEvent *)event offset:(NSPointPointer)dragImageOffset;
- (NSArray *)collectionView:(NSCollectionView *)collectionView namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropURL forDraggedItemsAtIndexes:(NSIndexSet *)indexes;
- (BOOL)collectionView:(NSCollectionView *)collectionView writeItemsAtIndexes:(NSIndexSet *)indexes toPasteboard:(NSPasteboard *)pasteboard;

The first two methods in particular.

I went through this a while ago. It seemed counterintuitive to me, but the only way I could get it to work was to set up the associated scroll view as the drop target.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top