Get NSTableView to register drop from PNG source - objective-c

Trying to get this to work, and not sure what I'm missing. The idea is to drop images on a NSTableView so that I can grab their paths and do some manipulations for them. I can get the drop to work for NSPastebouardTypeString, but I cannot for the life of me get it to register dragging PNGs from Finder into the tableview. What am I missing?
Relevent code:
- (void)awakeFromNib {
[imageTableView registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypePNG]];
}
- (NSDragOperation)tableView:(NSTableView *)aTableView validateDrop:(id < NSDraggingInfo >)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)operation {
NSLog(#"Validate Drop");
return NSDragOperationEvery;
}
- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id < NSDraggingInfo >)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation {
NSLog(#"Accept Drop");
return YES;
}

PNG files dragged from the Finder are not PNG data. They're files, which have their own pasteboard type. (Being files, you don't necessarily want them to be entirely loaded in memory in case of a drop, would you? :D)
10.4 gave you a NSArray of NSStrings as a NSFilenamesPboardType. 10.5 and later also provide you with an array of file: URLs as NSURLPboardType. Since you're using the older API, this document on 10.5- APIs applies (10.6 completely overhauls the pasteboard API to make it behave more like the iOS one).

Related

Cannot get drag and drop to work onto NSCollectionView

There is probably a simple mistake that I'm making, but I simply cannot get dropping of files onto an NSCollectionView to work even in the most basic way.
In a test project, I have an NSCollectionView on a window, and the view controller is both its delegate and data source. I want to be able to drag files from the Finder onto this collection view.
From reading the docs, all I should have to do is:
Register for dragged type(s):
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"Registering dragged types for collection view: %#", self.collectionView);
[self.collectionView registerForDraggedTypes:#[NSFilenamesPboardType]];
[self.collectionView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES];
[self.collectionView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:NO];
}
And then implement these two methods:
-(NSDragOperation)collectionView:(NSCollectionView *)collectionView validateDrop:(id<NSDraggingInfo>)draggingInfo proposedIndex:(NSInteger *)proposedDropIndex dropOperation:(NSCollectionViewDropOperation *)proposedDropOperation {
NSLog(#"Validate drop: %#", draggingInfo);
return NSDragOperationMove;
}
-(BOOL)collectionView:(NSCollectionView *)collectionView acceptDrop:(id<NSDraggingInfo>)draggingInfo index:(NSInteger)index dropOperation:(NSCollectionViewDropOperation)dropOperation {
NSLog(#"Accept drop: %#", draggingInfo);
return YES;
}
But none of the two methods is ever called, when I try to drag an item onto the collection view, which makes me think that the registerForDraggedTypes: call is not working as expected.
What can be the issue here? What else do I have to look into?
From OS X 10.11 the NSCollectionViewDelegate methods take an index path instead of an index. For instance in
-(NSDragOperation)collectionView:(NSCollectionView *)collectionView validateDrop:(id<NSDraggingInfo>)draggingInfo proposedIndex:(NSInteger *)proposedDropIndex dropOperation:(NSCollectionViewDropOperation *)proposedDropOperation
the proposedIndex: parameter is replaced by proposedIndexPath:
- (NSDragOperation)collectionView:(NSCollectionView *)collectionView validateDrop:(id <NSDraggingInfo>)draggingInfo proposedIndexPath:(NSIndexPath * __nonnull * __nonnull)proposedDropIndexPath dropOperation:(NSCollectionViewDropOperation *)proposedDropOperation

Drag and Drop methods for NSOutlineView are not getting called

I'm trying to enable drag&drop for NSOutlineView in my OSX app. The only thing I need to be able to drop is png image from the Finder.
I have myOutlineView and a controller which is a data source and a delegate of my outline view.
In my outline view controller I have these three methods:
-(BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard
-(NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id < NSDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
-(BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id < NSDraggingInfo >)info item:(id)item childIndex:(NSInteger)index{
none of them is being called...my nib is setup properly...my outline view is getting filled and all of the functionality is working except the drag&drop feature...
Any kind of help is highly appreciated!
Just fixed it I placed
[[self currentOutlineView] registerForDraggedTypes:[NSArray arrayWithObjects:(NSString*)kUTTypeFileURL,kPrivateDragUTI,nil]];
to the wrong spot, so my outline view couldn't register the draggable types appropriately. I placed it to
-(void) awakeFromNib
in my outline view controller and everything is working now! :)

Drag&Drop is not enabled for a NSOutlineView although I've implemented delegate methods

I'm not able to enable drag and drop for a NSOutlineView. I've implemented the related method of the NSOutlineView Delegate.
But it seems that when I click an item, I can't even dragging it (I don't see animation).
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id < NSDraggingInfo >)info item:(id)item childIndex:(NSInteger)index
{
return YES;
}
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id < NSDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
{
return NSDragOperationMove; //not sure about this one.
}
thanks
UPDATE:
I'm implementing forOSX >= 10.5
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard
{
NSString *pasteBoardType = [self pasteboardTypeForTableView:outlineView];
[pboard declareTypes:[NSArray arrayWithObject:pasteBoardType] owner:self];
NSData *rowData = [NSKeyedArchiver archivedDataWithRootObject:items];
[pboard setData:rowData forType:pasteBoardType];
return YES;
}
The methods you implemented are just for the destination of the drag. You still need to implement the dragging source methods. For whatever reason Apple's NSOutlineViewDataSource Protocol documentation is missing these methods but you have two options:
If you are building 10.7+ use Xcode's Open Quickly command to look in NSOutlineView.h and find the relevant methods. Also check out the DragNDropOutlineView sample app.
If you are supporting previous OS's then use NSTableView's delegate methods. See NSTableViewDataSource Protocol Reference. Remember that NSOutlineView is a subclass of NSTableView and can use the table view methods.
At a minimum you will probably want to implement outlineView:writeItems:toPasteboard:
/* Dragging Source Support - Optional for single-image dragging. This method is called after
it has been determined that a drag should begin, but before the drag has been started. To
refuse the drag, return NO. To start a drag, return YES and place the drag data onto the
pasteboard (data, owner, etc...). The drag image and other drag related information will
be set up and provided by the outline view once this call returns with YES. The items array
is the list of items that will be participating in the drag.
*/
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pasteboard;
Update:
If the item can be dragged but won't drop on anything then most likely outlineView:validateDrop:proposedItem:proposedChildIndex: is not being called. This would mean you haven't registered the pasteboard type which you do with registerForDraggedTypes:. You would do this somewhere in the view controller, probably in awakeFromNib.
[outlineView registerForDraggedTypes:[NSArray arrayWithObject:#"myPasteBoardType"]];
To move the item (and all its children) modify your model in outlineView:acceptDrop:item:childIndex:. Then send reloadData to the outlineView.
To make your outline view a dragging source, you must implement:
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pasteboard;
This should address what you described, but you've got a lot more work to do beyond this.

Cocoa WebView Drag-Drop

In my Application i have one NSOutlineView having list of somefiles and one WebView,
User allows to drag any item from the Outline view to WebView, and on that , i am suppose to handle the database transaction,
In the Outline view , i have implemented following methods,
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard{
[self log:#"write Items”];
// Some other code to prepare the Write Item,
}
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id < NSDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(NSInteger)index{
}
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id < NSDraggingInfo >)info item:(id)item childIndex:(NSInteger)index{
}
On the WebView side, i have implemented following, methods,
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
NSPasteboard *pboard;
NSDragOperation sourceDragMask;
[self log:#"Inside draggingEntered”];
return NSDragOperationEvery;
}
- (BOOL)prepareForDragOperation:(id < NSDraggingInfo >)sender{
}
- (BOOL)performDragOperation:(id < NSDraggingInfo >)sender{
}
Now when i drag an element from outline view to WebView, i could see, writeItem of Outline view is getting called,
and in the Webview, DragEnter is getting called from where, i am not returning drag operation NONE, but returning NSDragoperationEvery,
The problem is that, i am not getting method, prepareForDragOperation and PerformDragOperation,
Can anyone help me please,
Kind Regards
Rohan
Hi guys
Thanks for Looking over it,
It got resolved by overriding
- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender{
[self log:#"Inside Dragging updated"];
return NSDragOperationEvery;
}
Though in the document it was mentioned as an option and if its not implemented, it will take the return values from dragEnter Method,
perhaps for My own data type, it would have got NONE form WebView method and working once i overwrite it.
Kind Regard
Rohan

Help With Intra-Application Drag and Drop -- Cocoa

Okay, I've got a custom class called "Task", which represents a task to be done. I've got an NSMatrix which acts as a calendar. I want the user to be able to drag an icon from an nscollectionview (I've had no trouble setting up the nscollectionview) onto a cell in the nsmatrix, thereby assigning that task to that day. I just can't seem to get the nsmatrix to respond to the drag or the drop at all.
I've implemented the method:
- (BOOL)collectionView:(NSCollectionView *)cv writeItemsAtIndexes:(NSIndexSet *)indexes toPasteboard:(NSPasteboard *)pasteboard
{
[pasteboard declareTypes:[NSArray arrayWithObject:TASK_UTI] owner:self];
NSUInteger index=[indexes firstIndex];
Task* task=[[cv content] objectAtIndex:index];
NSData* taskData=[NSKeyedArchiver archivedDataWithRootObject:task];
[taskData retain];
BOOL success=[pasteboard setData:taskData forType:TASK_UTI];
return success;
}
in my nscollectionview delegate as shown above.
I've sent [self registerForDraggedTypes:[NSArray arrayWithObjects:TASK_UTI, nil]] in my NSMatrix subclass (called "Calendar").
I've implemented the methods:
- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender
- (BOOL)prepareForDragOperation:(id < NSDraggingInfo >)sender
- (BOOL)performDragOperation:(id < NSDraggingInfo >)sender
in my Calendar (NSMatrix subclass) class.
Some debugging shows that the NSMatrix/Calendar object is not even running the dragging methods above. What gives?
Did you define your Calendar class to implement dragging destination protocol?
First off, you should use your own domain name, not “com.yourcompany”, in the UTI.
Second, did you export the UTI in your Info.plist?