Drag and drop from finder to WebView - cocoa

I'm using a WebView in edit mode. I have implemented this method from WebUIDelegate Procotol:
- (void)webView:(WebView *)sender willPerformDragDestinationAction:(WebDragDestinationAction)action forDraggingInfo:(id < NSDraggingInfo >)draggingInfo
and use it to catch the drops of elements on my WebView. When I detect a file being dragged from outside my app, and containing a picture, I build in this method the img DOM element and add it to my document.
This works fine, but as the method's name implies, I am only informed that the drag will happen, and I have no control over it.
As the Finder always does file drag operation, what normally happens when dropping a file on a WebView in editing mode is the webview displays the path of the file.
I end up having the file path string added to my webview, and the image too, but I would like to prevent the text from being added.
Is there any way to configure this without subclassing webview?
I tried it and while it works, it breaks plenty of other things like caret moving for the drop and such.

Answering this myself for a change!
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
if ([sender draggingSource] == nil)
{
NSPasteboard *pboard = [sender draggingPasteboard];
if ( [[pboard types] containsObject:NSFilenamesPboardType] ) {
NSURL* fileURL;
fileURL=[NSURL URLFromPasteboard: [sender draggingPasteboard]];
NSArray *dragTypes = [NSArray arrayWithObject:NSFileContentsPboardType];
[[sender draggingPasteboard] declareTypes:dragTypes owner:nil];
NSImage *content = [[NSImage alloc] initWithContentsOfURL:fileURL];
[[sender draggingPasteboard] setData:[content TIFFRepresentation] forType:NSPasteboardTypeTIFF];
}
}
return [super performDragOperation:sender];
}
Actually, what I did was indeed to subclass the WebView and intercept the performDragOperation to change the content of the dragging pasteboard, if the dragging source is outside of my app and doesn't contain already an image but only a filename.

I ran into the same issue.
What I found is that subclassing the view is the best place for this to insert the image data into the pasteboard. Here is how I am doing it for multiple files:
- (BOOL) performDragOperation:(id<NSDraggingInfo>)sender {
if ( [sender draggingSource] == nil ) {
NSPasteboard *pboard = [sender draggingPasteboard];
NSArray *classes = #[ [NSURL class] ];
NSDictionary *options = #{ NSPasteboardURLReadingFileURLsOnlyKey: [NSNumber numberWithBool:YES],
NSPasteboardURLReadingContentsConformToTypesKey: [NSImage imageTypes] };
NSArray *fileURLs = [pboard readObjectsForClasses:classes options:options];
if ( fileURLs ) {
NSMutableArray *images = [NSMutableArray arrayWithCapacity:[fileURLs count]];
for ( NSURL *fileURL in fileURLs )
[images addObject:[[NSImage alloc] initWithContentsOfURL:fileURL]];
[pboard declareTypes:[NSImage imageTypes] owner:nil];
[pboard clearContents]; [pboard writeObjects:images];
}
} return [super performDragOperation:sender];
}
What I noticed is the following sequence:
1. WebView captures drag operation.
2. Internal WebCore created document fragment
3. Node is inserted into a DOMRange
4. Editing Delegate is called
5. Lastly UI Delegate is called where it is too late to do anything
Also, I suggest setting the following via the UI Delegate:
- (NSUInteger) webView:(WebView *)webView dragDestinationActionMaskForDraggingInfo:(id <NSDraggingInfo>)draggingInfo {
return WebDragDestinationActionEdit;
}
Ok, now the ISSUE I am running into and I really hope you might have an answer for me. When I select one file no problem. When I select multiple files, I get them and add all of them into the pasteboard properly. Even when I get to (5) for the UIDelegate and inspect the draggingPasteboard for its count I get what is expected. But unfortunately the document fragment is only being created once and likewise only one node gets inserted.
Any ideas how to get multiple fragments to be created so that they can all be inserted?
Thank you in advance.

Fixed version for the previous replies, this code works for multiple images dragged in the web view.
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
{
if ( [sender draggingSource] == nil )
{
NSPasteboard *pboard = [sender draggingPasteboard];
NSArray *classes = #[ [NSURL class] ];
NSDictionary *options = #{ NSPasteboardURLReadingFileURLsOnlyKey: [NSNumber numberWithBool:YES],
NSPasteboardURLReadingContentsConformToTypesKey: [NSImage imageTypes] };
NSArray *fileURLs = [pboard readObjectsForClasses:classes options:options];
if(fileURLs)
{
NSArray* filenames = [pboard propertyListForType: NSFilenamesPboardType];
NSMutableString* html = [NSMutableString string];
for(NSString* filename in filenames) {
[html appendFormat: #"<img src=\"%#\"/>", [[[NSURL alloc] initFileURLWithPath: filename] absoluteString]];
}
[pboard declareTypes: [NSArray arrayWithObject: NSHTMLPboardType] owner: self];
[pboard setString: html forType: NSHTMLPboardType];
}
} return [super performDragOperation:sender];
}

Related

Limit allowed operations to only NSDragOperationCopy

I have a custom view that is a drag source. I want to limit the allowed drag operations to only a copy, and hence I return NSDragOperationCopy in my draggingSession:sourceOperationMaskForDraggingContext: method.
For some reason this has no effect.
There doesn't seem to be anything wrong with my code as returning NSDragOperationNone works as expected and blocks drags.
Below is the code from my NSView that is the dragging source. Dragging from the view to the "Trash" you'll see a NSDragOperationMove or NSDragOperationDelete even though I only want to allow the NSDragOperationCopy operation.
I've also uploaded a small demo project to demonstrate what I'm talking about: https://dl.dropbox.com/u/368222/test.zip.
- (void)mouseDown:(NSEvent *)event {
NSString *path = [[NSBundle mainBundle] resourcePath];
NSString *imagePath = [path stringByAppendingString:#"/image.png"];
NSImage *image = [[NSImage alloc] initWithContentsOfFile:imagePath];
NSArray *file = [NSArray arrayWithObject:imagePath];
NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
[pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:nil];
[pboard setPropertyList:file forType:NSFilenamesPboardType];
[self dragImage:image at:NSZeroPoint offset:NSMakeSize(0, 0) event:event pasteboard:pboard source:self slideBack:NO];
}
- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context {
return NSDragOperationCopy;
}
- (void)draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation {
NSLog(#"Dragging session ended with operation: %li", operation);
}
Anyone?
Thx!

copy and paste text + image from NSPasteboard

we are working on a C++ Qt applciation that copies selected text and/or images from external applications, modifies it and then paste it back. Since we are on Mac, we are doing this part with Objective-C.
We are having problems trying to get an image from the Pasteboard. It works fine for text, but we are not sure about how to handle images or combination of text+image.
Since we dont know what the user might select, we should be able to perform a generic retrieval of content of the pasteboard to modify it and putting it back in the pasteboard.
We've try this:
//we thought about retrieving some generic item from pasteboard, using NSPasteboardItem
NSArray *classes = [[NSArray alloc] initWithObjects:[NSPasteboardItem class], nil];
NSDictionary *options = [NSDictionary dictionary];
NSArray *auxArray = [[NSPasteboard generalPasteboard] readObjectsForClasses:classes options:options];
NSData *archived_data = [auxArray objectAtIndex:0];
Our solution for handling text was:
NSString *text = [[NSPasteoard generalPasteboard] stringForType:NSStringPboardType];
string text_str = string([text UTF8String]);
It didnt work, so, How can we get the user selection from the pasteboard?
We need to get the raw bytes or rtf content in order to modify it as we need, and then putting it back in the pasteboard and paste it back replacing the original user selection.
Thanks!
I think this function will help you
- (IBAction)paste:sender
{
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
NSArray *classArray = [NSArray arrayWithObject:[NSImage class]];
NSDictionary *options = [NSDictionary dictionary];
BOOL ok = [pasteboard canReadObjectForClasses:classArray options:options];
if (ok)
{
NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options];
NSImage *image = [objectsToPaste objectAtIndex:0];
[imageView setImage:image];
}
}

Force plaintext copy from a Cocoa WebView

I have a Cocoa Webview subclass, and I need to make all text copied from it be plaintext only. I have tried overriding -copy and -pasteboardTypesForSelection, but no luck, and debugging code seems to indicate that those methods are never called. I've also tried setting -webkit-user-modify to read-write-plaintext-only in the css (this would also work in this situation) but that seemed to have no effect.
Any ideas?
Okay this seems to work (with the subclass instance as its own editing delegate):
- (BOOL)webView:(WebView *)webView doCommandBySelector:(SEL)command
{
if (command == #selector(copy:)) {
NSString *markup = [[self selectedDOMRange] markupString];
NSData *data = [markup dataUsingEncoding: NSUTF8StringEncoding];
NSNumber *n = [NSNumber numberWithUnsignedInteger: NSUTF8StringEncoding];
NSDictionary *options = [NSDictionary dictionaryWithObject:n forKey: NSCharacterEncodingDocumentOption];
NSAttributedString *as = [[NSAttributedString alloc] initWithHTML:data options:options documentAttributes: NULL];
NSString *selectedString = [as string];
[as autorelease];
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
[pasteboard clearContents];
NSArray *objectsToCopy = [NSArray arrayWithObject: selectedString];
[pasteboard writeObjects:objectsToCopy];
return YES;
}
return NO;
}
Not sure if this is the best way.

set lastPathComponent string after save

Doc based, QTKit app. When saving, the new filename updates in the active window titleBar. I would also like to display the newly saved filename string in a textField, somewhere else on the opened doc. The code successfully saves the new doc. However the lastPathComponent string doesn't update. Please advise?
thanks,
Paul
- (void)savePanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
NSURL *outputFileURL = [(NSURL *)contextInfo autorelease];
if (returnCode == NSOKButton) {
NSString *filename = [sheet filename];
[[NSFileManager defaultManager] moveItemAtPath:[outputFileURL path] toPath:filename error:nil];
NSString *path = [filename lastPathComponent];
[textField setStringValue:[path lastPathComponent]];
[[NSWorkspace sharedWorkspace] openFile:filename];
}
else {
[[NSFileManager defaultManager] removeItemAtPath:[outputFileURL path] error:nil];
}
}
Since "filename" is apparently valid (because things are working and your window title updates), have you checked to make sure "textField" is actually connected in your XIB?

Get the filepath when dragging a file from finder to a webview?

I am developing a flvplayer with cocoa. I want to drag a flv file from the finder and drop it to the webview window (I use it to view the flv). But I didn't have the path of this file from finder. This is my code:
_ (void)showflv(nsstring*)aa
{
..........
//Register to accept flv drag/drop
NSString *pboardType = NSCreateFileContentsPboardType(#"flv");
NSArray *dragTypes = [NSArray arrayWithObject:pboardType];
[self registerForDraggedTypes:dragTypes];
}
_ (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
NSPasteboard *pboard = [sender draggingPasteboard];
if ( [[pboard types] containsObject:NSFileContentsPboardType] ) {
}
return YES;
}
I read the document about this.I find that the function of PerformDragOperation can be written like this:
_ (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
NSPasteboard *pboard = [sender draggingPasteboard];
if ( [[pboard types] containsObject:NSFileContentsPboardType] ) {
NSFileWrapper *fileContents = [pboard readFileWrapper];
// Perform operation using the file’s contents
}
return YES;
}
I can get the filecontents of this dragging file.but how to get the path?
NSString *fileName = [fileContents filename];
I did a test, it wasn't correct.
I did a test ,but The draggedFilePaths didn't work.I found that the code:
NSPasteboard *pboard = [sender draggingPasteboard];
if ( [[pboard types] containsObject:NSFileContentsPboardType] ) {
//NSFileWrapper *fileContents = [pboard readFileWrapper];
// Perform operation using the file’s contents
nslog(#"aa");
}
when the app run ,the string "aa" didn't appear,why?
Like so:
NSArray *draggedFilePaths = [pboard propertyListForType:NSFilenamesPboardType];
NSPasteboard *pastboard = [sender draggingPasteboard];
NSURL *URL = [NSURL URLFromPasteboard:pastboard];
NSLog(#"%#", URL);

Resources