76: Drag between NSTableView and other applications
Problem: We have a NSTableView and want to be able to drag and drop multiple rows within the view, drag strings from the view to other applications, e.g. Safari, and drag and drop string data from other applications onto the view.
Drag and drop finder file paths onto an NSTableView
Drag and drop a Safari URL onto an NSTableView
Drag and drop a row of text from NSTableView onto a BBEdit document
Drag various rows within a NSTableView
Answer: We use Apple's
NSPasteboard Class Reference, and
Pasteboard Programming Guide and
Introduction to Drag and Drop and
tutorial on Using Drag and Drop in Tables.
Source code
// MyData.h
#import <Cocoa/Cocoa.h>
@interface MyData : NSObject {
NSString * nsStr;
}
@property (assign) NSString * nsStr;
+(id)newWithString:(NSString *)pStr;
-(id)initWithString:(NSString *)pStr;
@end
// MyData.m
#import "MyData.h"
@implementation MyData
@synthesize nsStr;
+(id)newWithString:(NSString *)pStr {
return [[self alloc]initWithString:pStr];
} // end newWithString
-(id)initWithString:(NSString *)pStr {
if ( ! (self = [super init]) ) {
NSLog(@"Error MyData initWithString");
return self;
} // end if
self.nsStr = pStr;
return self;
} // end initWithString
@end
// MyController.h
#import <Cocoa/Cocoa.h>
@interface MyController : NSObjectController {
NSMutableArray * nsAryOfDataValues;
IBOutlet NSTableView * nsTableViewObj;
NSTextFieldCell * nsTextFieldCellObj;
}
@property (assign) NSMutableArray * nsAryOfDataValues;
@property (assign) NSTextFieldCell * nsTextFieldCellObj;
@property (assign) IBOutlet NSTableView * nsTableViewObj;
@end
// MyController.m
#import "MyController.h"
#import "MyData.h"
@implementation MyController
@synthesize nsAryOfDataValues;
@synthesize nsTextFieldCellObj;
@synthesize nsTableViewObj;
#define MyPrivateTableViewDataType @"MyPrivateTableViewDataType"
- (void) awakeFromNib {
nsAryOfDataValues = [[NSMutableArray alloc]init];
[nsAryOfDataValues addObject:
[MyData newWithString:@"Fuzzy Wuzzy was a bear"]];
[nsAryOfDataValues addObject:
[MyData newWithString:@"Fuzzy Wuzzy had no hair"]];
[nsAryOfDataValues addObject:
[MyData newWithString:@"So he wasn't Fuzzy Wuzzy?"]];
// define the drag types
[self.nsTableViewObj registerForDraggedTypes:
[NSArray arrayWithObjects:MyPrivateTableViewDataType,
NSFilenamesPboardType,
@"public.utf8-plain-text",
nil] ];
// tell NSTableView we want to drag and drop accross applications
// the default has forLocal:YES
[self.nsTableViewObj setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];
} // end awakeFromNib
// these are called by the table(s)
- (int)numberOfRowsInTableView:(NSTableView *)tableView {
if (tableView == nsTableViewObj) {
return [nsAryOfDataValues count];
} // end if
return 0;
} // end numberOfRowsInTableView
- (id)tableView:(NSTableView *)tableView
objectValueForTableColumn:(NSTableColumn *)tableColumn
row:(int)row {
if (tableView == nsTableViewObj) {
MyData * zData = [nsAryOfDataValues objectAtIndex:row];
return zData.nsStr;
} // end if
return NULL;
} // end tableView:objectValueForTableColumn:tableColumn
- (void)tableView:(NSTableView *)aTableView
setObjectValue:(id)anObject
forTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex {
if (aTableView == nsTableViewObj) {
MyData * zData = [nsAryOfDataValues objectAtIndex:rowIndex];
zData.nsStr = (NSString *)anObject;
[nsAryOfDataValues replaceObjectAtIndex:rowIndex withObject:zData];
} // end if
} // end tableView:setObjectValue:forTableColumn:row:
// ===========================================
// drag operation stuff
// ===========================================
- (BOOL) tableView:(NSTableView *)pTableView
writeRowsWithIndexes:(NSIndexSet *)pIndexSetOfRows
toPasteboard:(NSPasteboard*)pboard
{
// this allows us to drag rows around within the table
// we copy the row numbers to be dragged to the pasteboard.
NSData *zNSIndexSetData = [NSKeyedArchiver archivedDataWithRootObject:pIndexSetOfRows];
[pboard declareTypes:[NSArray arrayWithObject:MyPrivateTableViewDataType] owner:self];
[pboard setData:zNSIndexSetData forType:MyPrivateTableViewDataType];
// this is to allow us to drag string data to other applications, e.g. safari, bbedit
// We don't do this if more than one row is selected
if ([pIndexSetOfRows count] > 1) {
return YES;
} // end if
NSInteger zIndex = [pIndexSetOfRows firstIndex];
MyData * zDataObj = [self.nsAryOfDataValues objectAtIndex:zIndex];
NSString *zDataString = zDataObj.nsStr;
[pboard setString:zDataString forType:@"public.utf8-plain-text"];
return YES;
}
- (NSDragOperation)tableView:(NSTableView*)pTableView
validateDrop:(id