Help With Intra-Application Drag and Drop -- Cocoa - objective-c

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?

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

PXListView drag and drop is not doing working

i have created the NSViewController for managing the PXListView....delegate is connect with File owner...
here everything is working as per the expectation..except drag and drop...
while dragging it is not entering into the dragging delegate function...and it is not showing the + symbol while dragging(i.e dragging symbol)... and dragging cells relocates to its original position
#import "PXListView.h"
#interface ListViewController : NSViewController <PXListViewDelegate>
{
IBOutlet PXListView *listView;
NSMutableArray *_listItems;
int count;
}
- (void)addCell;
#end
- (BOOL)listView:(PXListView*)aListView writeCellsWithIndexes:(NSIndexSet*)rowIndexes toPasteboard:(NSPasteboard*)dragPasteboard
{
// +++ Actually drag the items, not just dummy data.
[dragPasteboard declareTypes: [NSArray arrayWithObjects: NSStringPboardType, nil] owner: self];
[dragPasteboard setString: #"Just Testing" forType: NSStringPboardType];
return YES;
}
- (NSDragOperation)listView:(PXListView*)aListView validateDrop:(id <NSDraggingInfo>)info proposedCell:(NSUInteger)row
proposedDropHighlight:(PXListViewDropHighlight)dropHighlight;
{
return NSDragOperationCopy;
}
- (BOOL)listView:(PXListView*)aListView acceptDrop:(id <NSDraggingInfo>)info row: (NSUInteger)row dropHighlight:(PXListViewDropHighlight)dropHighlight
{
NSLog(#"Accept Drop");
ListViewThumbnailObject *temp = [_listItems objectAtIndex: [listView selectedCell]];
[_listItems removeObjectAtIndex: [listView selectedCell]];
[_listItems insertObject: temp atIndex: row];
[listView reloadData];
return YES;
}
it is not entering into the drag related delegate methods..
in the "nib" file delegate is wired with file owner...
can anyone please suggest me how to solve this problem?
Thanks,
Muthu
To be able to accept drops, you will likely need to assure you register the list view for all dragged types you plan on accepting. Try adding this in the awakeFromNib method in your list view controller class:
- (void)awakeFromNib {
[listView registerForDraggedTypes:[NSArray
arrayWithObjects:NSStringPboardType, nil]];
}
See Drag and Drop Programming Topics: Receiving Drag Operations for more info.
Note that I used NSStringPboardType in the array here because that's the type you declared for writing in the listView:writeCellsWithIndexes:toPasteboard: method. The exact array of types you use will depend on the types you want to support, and the type of drag operations you want to support (for example, do you just want to implement drag and drop to allow reordering of items in a single list view, or do you want to allow dragging items from the Finder, or to the Finder, or between different views in your own application). If you describe the type of drag operations you hope to support I can provide more details on how you might want to implement them.

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.

Can NSTableView handle normal drag-and-drop methods?

I'd like to use NSTableView without the NSTableViewDataSource Methods but just like a normal view. draggingEntered: and draggingExited: are being called but when I return NSDragOperationCopy, I don't see the green plus mouse pointer and performDragOperation: doesn't get called.
I subclassed the NSTableView with these methods:
- (void)awakeFromNib
{
[self registerForDraggedTypes: [NSArray arrayWithObject: NSFilenamesPboardType]];
}
- (NSDragOperation)draggingEntered: (id < NSDraggingInfo >)sender
{
NSLog(#"draggingEntered"); //Gets called
return NSDragOperationCopy;
}
- (void)draggingExited: (id < NSDraggingInfo >)sender
{
NSLog(#"draggingExited"); //Gets called
}
- (BOOL)performDragOperation: (id < NSDraggingInfo >)sender
{
NSLog(#"performDragOperation"); //Doesn't get called
return YES;
}
The documentation says it conforms to the NSDraggingDestination and NSDraggingSource protocol, so yes it should hand normal drag-and-drop.
You might try using -registerForDraggedTypes: method from nsview.

Drag-drop from NSTableView to NSImageView

I need to drag a row from NSTableView containing an image path and drop it over NSImageView, and the image of the dragged row should appear in the imageview. Help appreciated
Thanks a lot. It really worked. I registered NSImageView and NSTableView for NSStringPboardType and NSFilenamesPboardType. Then in TableView delegate I used
the following code.
- (BOOL)tableView:(NSTableView *)tv writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard*)pboard
{
NSString *string = [filePath objectAtIndex:[rowIndexes firstIndex]];
[pboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self];
[pboard setString:string forType:NSStringPboardType];
return YES;
}
And in NSImageView NSDragging Destination informal protocol, used following code.
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
NSString *str = [[sender draggingPasteboard] stringForType:NSStringPboardType];
myImage = [[NSImage alloc] initWithContentsOfFile:str];
[self setImage:myImage];
[self setNeedsDisplay: YES];
return NSDragOperationCopy;
}
cheers :)
First, in your table data source, implement the necessary methods for table row dragging. You'll put data representing the row onto the drag pasteboard in one or more data types. One type you'll use for this is NSFilenamesPboardType, which takes an array of pathnames.
Then, make a subclass of NSImageView that can handle NSFilenamesPboardType in drops. (You'll need to implement methods from the NSDraggingDestination informal protocol.) Then make your image view an instance of this subclass, instead of NSImageView, and register that view for NSFilenamesPboardType.