Rearrange table rows by dragging and dropping in Lion

I'm having trouble using the new Lion function to change lines in an application. I am using outlineView:pasteboardWriterForItem: to store row indices so I can access them later when I check / accept the drop. I create a new NSPasteboardItem to return and try to save the line number as follows:

 [pbItem setData: [NSKeyedArchiver archivedDataWithRootObject: [NSNumber numberWithInteger: [fTableView rowForItem: item]]] forType: TABLE_VIEW_DATA_TYPE]; 

TABLE_VIEW_DATA_TYPE is a custom string that I use to distinguish my user data in drag and drop. I do not use it outside of dragging these lines.

When I try to drag and drop, I get in the console: 'TableViewDataType' is not a valid UTI string. Cannot set data for an invalid UTI. 'TableViewDataType' is not a valid UTI string. Cannot set data for an invalid UTI.

Of course, I could use some of the built-in UTIs for cardboard, but none of them apply (and using them leads to the fact that the drag and drop accepts drags other than strings, which should not be). There is something that I am missing as a way to define a custom UTI for drag and drop only (without making it a “real” UTI, since I cannot use it outside of the internal drag and drop, so it should not be publicly available).

Thanks for any help!

+6
source share
3 answers

I had similar requirements, except that I had a mesh of objects that I wanted to rebuild by dragging the selected objects to a new location. There are several ways to do this, including creating a custom object and implementing the NSPasteboardWriting and NSPasteboardReading protocols (and NSCoding protocols if you read data like NSPasteboardReadingAsKeyedArchive ), but this seems to be superfluous for dragging objects that remain internal to the application.

What I did was related to using NSPasteboardItem as a wrapper with a custom UTI type (it already implements NSPasteboardWriting and NSPasteboardReading ). First declare a custom UTI type:

#define kUTIMyCustomType @"com.mycompany.MyApp.MyCustomType"

This must be defined in the format "com.domain.MyApp", otherwise you will get errors of the form: "XXX is not a valid UTI string. It is not possible to set data for an invalid UTI". Apple mentions this in its documentation.

Then you must register this custom UTI type in the view in which the drag will be performed. This can be done at runtime and does not require any .plist add-ons. In your init method, you can add the following:

 [self registerForDraggedTypes:[NSArray arrayWithObjects:(NSString *)kUTIMyCustomType, nil]]; 

Now make sure that a delegate is set for this view, and the delegate object implements the necessary methods of the NSDraggingSource and NSDraggingDestination . This will allow you to avoid violating the MVC design pattern by allowing the designated controller object to process the placement of data on cardboard, which is likely to include requesting model data (i.e., Indexes).

In particular, to place drag and drop indexes on objects that need to be moved when the drag starts as an NSPasteboardItem wrapper for your index data:

 - (void) draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint)screenPoint { NSPasteboard * pboard = [NSPasteboard pasteboardWithName:NSDragPboard]; [pboard clearContents]; NSMutableArray * selectedIndexes = [NSMutableArray array]; // Add NSString indexes for dragged items to pasteboard in NSPasteboardItem wrappers. for (MyModel * myModel in [self selectedObjects]) { NSPasteboardItem * pasteboardItem = [[[NSPasteboardItem alloc] init] autorelease]; [pasteboardItem setString:[NSString stringWithFormat:@"%@", [myModel index]] forType:kUTIMyCustomType]; [selectedIndexes addObject:pasteboardItem]; } [pboard writeObjects:selectedIndexes]; } 

And when the drag and drop operation is completed, read the data of the drag and drop index NSPasteboardItem :

 - (BOOL) performDragOperation:(id <NSDraggingInfo>)sender { NSPasteboard * pasteboard = [sender draggingPasteboard]; // Check for custom NSPasteboardItem which wrap our custom object indexes. NSArray * classArray = [NSArray arrayWithObject:[NSPasteboardItem class]]; NSArray * items = [pasteboard readObjectsForClasses:classArray options:[NSDictionary dictionary]]; if (items == nil) return NO; // Convert array of NSPasteboardItem with NSString index reps. to array of NSNumber indexes. NSMutableArray * indexes = [NSMutableArray array]; for (NSPasteboardItem * item in items) [indexes addObject:[NSNumber numberWithInteger:[[item stringForType:kUTIMyCustomType] integerValue]]]; // // Handle dragged indexes… // return YES; } 
+6
source

Another way you can use is simply to keep the indices of the objects you drag in the instance variable on the side. Putting everything on cardboard is not necessary if you do not accept items from another application or vice versa.

  • At awakeFromNib, register for NSStringPboardType.
  • In ... pasteboardWriterForRow, return the string [NSString].
  • In ... draggingSession: willBegin ..., set your instance variable to the indexes you want to track.
  • In validateDrop, return NSDragOperationNone if your instance variable is zero or the view does not belong to you.
  • In ... draggingSession: ended ..., zero is your instance variable.

Hope this helps ... I use the technique to represent the tables, but it should be almost identical for the outline representation.

+5
source

Instead of using vanilla NSPasteboardItem you should create a custom object that conforms to the NSPasteboardWriting protocol.

In your custom object, you can implement writableTypesForPasteboard: to return a list of user-defined UTIs that your file supports. Then you implement pasteboardPropertyListForType: to return the plist representation of your object for the corresponding custom UTI when it requests it.

You can create plist from arbitrary data using the +propertyListWithData:options:format:error: NSPropertyListSerialization .

Then you redefined tableView:pasteboardWriterForRow: in the table view data source to return an instance of your custom object.

+2
source

Source: https://habr.com/ru/post/904784/


All Articles