views:

722

answers:

1

Hi,

I have to NSTableViews in my application both display the data which is being stored as "CoreData". The TableViews are pretty basic, as the whole programm is.

The right TableView shows a list of checklists, the left shows the contents of this checklist. Now I want to allow a user to drag an item which is inside a checklist to another checklist.

I found several tutorials and sample code on the web, but they are way to overwhelming for my understanding of Cocoa. It would be great if someone could mention a webpage or tutorial or the like with short and easy to understand instructions.

Thanks a lot

EDIT: Although it should be obvious, my application is written in Cocoa and runs on the Mac.

+5  A: 

I've got a little demo on how to use NSOutlineView with drag and drop on my downloads page: http://davedelong.com/downloads It should be pretty applicable to NSTableView, since NSOutlineView is a subclass of NSTableView.

Here is a 5 minute distillation of what I've learned after about a month of reading documentation. There are three "basic" NSTableView delegate methods used when dragging and dropping stuff from NSTableViews. They are:

  1. - (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id <NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation;

  2. - (NSDragOperation)tableView:(NSTableView *)aTableView validateDrop:(id < NSDraggingInfo >)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)operation;

  3. - (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard;

The first one, tableView:acceptDrop:row:dropOperation: is used when someone has dragged something ONTO your NSTableView. It's pretty straight-forward. All the information about the drop (including what's being dropped) is found in [info draggingPasteboard]. Return YES if the drop was successful, and NO otherwise.

tableView:validateDrop:proposedRow:proposedDropOperation: is used when someone WANTS to drop something onto your NSTableView. The originator of the drop, at this point, is unimportant. All that matters is that they're hovering over you, and you have to say what they can do. If, for example, they're hovering over a certain row (the 'proposedRow'), and you don't want to allow stuff to be dropped on that row, then return NSDragOperationNone. Or maybe you want to copy what's in the information (return NSDragOperationCopy). There's a whole bunch of different kinds of operations you can signify. Use the one that is appropriate for your needs. (These return values will adjust the cursor accordingly. So if you return NSDragOperationCopy, then the cursor will get the little green + circle.)

The final method, tableView:writeRowsWithIndexes:toPasteboard: is called when the user has selected some rows in your NSTableView and has begun to drag them. You now have to provide the dragging pasteboard with the information that corresponds to those rows, so it can be dropped elsewhere. Here's a simplified example of how I've used this method to provide NSManagedObjects to the pasteboard:

- (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard {
  [pboard declareTypes:[NSArray arrayWithObject:kMyCustomDragType] owner:self];
  //get an array of URIs for the selected objects
  NSMutableArray * rows = [NSMutableArray array];
  NSArray * selectedObjects = [arrayOfManagedObjects objectsAtIndexes:rowIndexes];
  for (NSManagedObject * o in selectedObjects) {
    [rows addObject:[[o objectID] URIRepresentation]];
  }
  NSData * encodedIDs = [NSKeyedArchiver archivedDataWithRootObject:rows];
  [pboard setData:encodedIDs forType:kMyCustomDragType];
  return YES;
}

The idea behind this is that I'm encoding the URIRepresentation of each selected NSManagedObject's objectID and putting that on the pasteboard. I'm putting this data on the draggingPasteboard under the type "kMyCustomDragType" (an NSString), which means that only objects that have indicated that they accept drops of type kMyCustomDragType will be able to receive this drop. I finally return YES to indicate that I have successfully written data to the pasteboard. (Return NO if there was a failure)

If you can get this to work, then you've probably got 90% of all your drag and drop functionality that you'll need. The other 10% would come from stranger requirements. As always, the documentation will be your best friend.

Dave DeLong
Thank you David for this *very* good help. That has helped me a lot. *thumbs up*
So you should probably mark the question as answered :)
Mike Abdullah