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

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);

Related

Get UTI of NSPasteboardTypeFileURL

NSFilenamesPboardType got deprecated on 10.14 and the suggestion is to use NSPasteboardTypeFileURL. This gives me filename as
file:///.file/id=6571367.12885025918
and NSWorkspace is unable to get UTI out of it.
How to get UTI from NSPasteboardTypeFileURL?
Old code:
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
NSDragOperation resultingDragMask = NSDragOperationNone;
NSPasteboard *pboard = [sender draggingPasteboard];
if ([[pboard types] containsObject:NSFilenamesPboardType]) {
NSArray <NSString *>*list = [pboard propertyListForType:NSFilenamesPboardType];
NSString *firstItem = [list objectAtIndexedSubscript:0];
NSError *error;
NSString *UTI = [[NSWorkspace sharedWorkspace] typeOfFile:firstItem error:&error];
if (!error) {
if ([[NSImage imageTypes] containsObject:UTI]) {
resultingDragMask = NSDragOperationCopy;
}
}
} else if ([[pboard types] containsObject:NSPasteboardTypeTIFF]) {
resultingDragMask = NSDragOperationCopy;
}
if (sourceDragMask & NSDragOperationCopy && resultingDragMask & NSDragOperationCopy) {
return NSDragOperationCopy;
}
return NSDragOperationNone;
}
With NSPasteboardTypeFileURL I get error which states file doesn't exist. Dragged from pasteboard:
Printing description of error:
Error Domain=NSCocoaErrorDomain Code=260 "The file “id=6571367.12885025918” couldn’t be opened because there is no such
file." UserInfo={NSURL=file:/.file/id=6571367.12885025918 --
file:///Users/xxx/Library/Containers/com.xxx.imageviewfix/Data/,
NSFilePath=/Users/xxx/Library/Containers/com.xxx.imageviewfix/Data/file:/.file/id=6571367.12885025918,
NSUnderlyingError=0x600000c70d80 {Error Domain=NSPOSIXErrorDomain
Code=2 "No such file or directory"}}
I am late to this question but I found this works:
NSArray<Class> *classes = #[[NSURL class]];
NSDictionary *options = #{};
NSArray<NSURL*> *files = [pboard readObjectsForClasses:classes options:options];
for (NSURL *url in files)
{
NSString *str = [url path];
// TODO: do something with str.
}
Unlike the other answer, dropping multiple files works with this approach.
Getting path of NSURL object gets the original filename. The only thing missing is the array of file paths which NSFilenamesPboardType used to give.
NSString *fileURL = [[NSURL URLFromPasteboard:pboard] path];
Updated code:
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
NSDragOperation resultingDragMask = NSDragOperationNone;
NSPasteboard *pboard = [sender draggingPasteboard];
if ([[pboard types] containsObject:NSPasteboardTypeFileURL]) {
NSString *fileURL = [[NSURL URLFromPasteboard:pboard] path];
NSError *error;
NSString *UTI = [[NSWorkspace sharedWorkspace] typeOfFile:fileURL error:&error];
if (!error) {
if ([[NSImage imageTypes] containsObject:UTI]) {
resultingDragMask = NSDragOperationCopy;
}
}
} else if ([[pboard types] containsObject:NSPasteboardTypeTIFF]) {
resultingDragMask = NSDragOperationCopy;
}
if (sourceDragMask & NSDragOperationCopy && resultingDragMask & NSDragOperationCopy) {
return NSDragOperationCopy;
}
return NSDragOperationNone;
}

NSPersistentStoreCoordinator database storage location applicationSupportFolder issue

Right now my App is placing the database in the ~/Library folder but I would like it to place it in a more organized manner ~/Library/App Name but I can not figure out how to do that with this block of code.
(NSPersistentStoreCoordinator *) persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSFileManager *fileManager;
NSString *applicationSupportFolder = nil;
NSString *dataFilePath;
NSURL *url;
NSError *error;
fileManager = [NSFileManager defaultManager];
applicationSupportFolder = [self applicationSupportFolder];
if ( ![fileManager fileExistsAtPath:applicationSupportFolder isDirectory:NULL] ) {
[fileManager createDirectoryAtPath:applicationSupportFolder attributes:nil];
}
dataFilePath = [applicationSupportFolder stringByAppendingPathComponent: #"sample.dat"];
if( NO == [[ NSFileManager defaultManager ] fileExistsAtPath: dataFilePath ] )
{
[[ NSFileManager defaultManager ] copyPath: [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: #"sample.dat"]
toPath: dataFilePath handler: NULL ];
}
url = [NSURL fileURLWithPath:dataFilePath];
if( url )
{
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error]){
[[NSApplication sharedApplication] presentError:error];
}
}
return persistentStoreCoordinator;
}
This code works it just places the database in a pretty terrible location IMO. I am new to Obj-C and just inherited this code set from a another developer.
UPDATE:
Adding the final working code below.
(NSPersistentStoreCoordinator *) persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSFileManager *fileManager;
NSString *applicationSupportFolder = nil;
NSString *dataFilePath;
NSURL *url;
NSError *error;
fileManager = [NSFileManager defaultManager];
applicationSupportFolder = [self applicationSupportFolder];
NSString *aappSupportFolder = [applicationSupportFolder stringByAppendingPathComponent: #"APP"];
if ( ![fileManager fileExistsAtPath:aappSupportFolder isDirectory:NULL] ) {
[fileManager createDirectoryAtPath:aappSupportFolder attributes:nil];
}
dataFilePath = [aappSupportFolder stringByAppendingPathComponent: #"sample.dat"];
if( NO == [[ NSFileManager defaultManager ] fileExistsAtPath: dataFilePath ] )
{
[[ NSFileManager defaultManager ] copyPath: [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: #"sample.dat"]
toPath: dataFilePath handler: NULL ];
}
url = [NSURL fileURLWithPath:dataFilePath];
if( url )
{
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error]){
[[NSApplication sharedApplication] presentError:error];
}
}
return persistentStoreCoordinator;
}
Well it is very simple just you have to create folder name APP inside library folder of your machine and then you have to move your app inside the same path . Please try below:-
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *pathString= [paths objectAtIndex:0];
NSError *err=nil;
//below is your application previous path which we will move to new path
NSString *dataFilePath = [pathString stringByAppendingPathComponent: #"sample.dat"];
NSString *applicationSupportFolder = [pathString stringByAppendingPathComponent: #"App"];
//Here we have created directory folder as App inside Library below
if ( ![fileManager fileExistsAtPath:applicationSupportFolder isDirectory:NULL] ) {
[fileManager createDirectoryAtPath:applicationSupportFolder attributes:nil];
}
if ([fm moveItemAtPath:dataFilePath toPath:applicationSupportFolder error:&err])
{
NSLog(#"success");
}
else
{
NSLog(#"%#",[err localizedDescription]);
}

Using multiple imagepickers on one view

I have a working imagepicker that upon button click and hold gesture, allows the user to upload an image to the disk, and the user can change the image using the same gesture. The only issue is, however, I need this to be done twice on the same view (i.e. I have two imageviews, two buttons to change each of the imageviews, etc.), and I am stumped on how to get the second one to work. This is essentially what the view looks like:
Here is my current code:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
//
// Saving into Documents folder
//
NSString* path = [NSHomeDirectory() stringByAppendingString:#"/Documents/first.png"];
BOOL ok = [[NSFileManager defaultManager] createFileAtPath:path
contents:nil attributes:nil];
if (!ok) {
NSLog(#"Error creating file %#", path);
} else {
NSFileHandle* myFileHandle = [NSFileHandle fileHandleForWritingAtPath:path];
[myFileHandle writeData:UIImagePNGRepresentation(info [UIImagePickerControllerOriginalImage])];
[myFileHandle closeFile];
}
//
// Loading from documents
//
NSFileHandle* myFileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
UIImage* loadedImage = [UIImage imageWithData:[myFileHandle readDataToEndOfFile]];
self.chosenImage = loadedImage;
[self.imageView setImage:self.chosenImage];
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void) imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)onLongTile:(UILongPressGestureRecognizer *)gesture
{
switch ([gesture state]) {
case UIGestureRecognizerStateBegan:{
NSString *actionSheetTitle = #"Photo Options"; //Action Sheet Title
NSString *type = #"Upload Photo";
NSString *cancelTitle = #"Cancel";
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:actionSheetTitle
delegate:self
cancelButtonTitle:cancelTitle
destructiveButtonTitle:nil
otherButtonTitles:type, nil];
[actionSheet showInView:self.view]; }
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
NSString *buttonTitle = [actionSheet buttonTitleAtIndex:buttonIndex];
if ([buttonTitle isEqualToString:#"Photo"]) {
self.imagePicker = [[UIImagePickerController alloc] init];
self.imagePicker.delegate = self;
[self.imagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
[self presentViewController:self.imagePicker animated:YES completion:nil];
}
}
Updated code with tags:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
if (self.imageViewOne.tag == 100)
{
//
// Saving into Documents folder
//
NSString* path = [NSHomeDirectory() stringByAppendingString:#"/Documents/one.png"];
BOOL ok = [[NSFileManager defaultManager] createFileAtPath:path
contents:nil attributes:nil];
if (!ok) {
NSLog(#"Error creating file %#", path);
} else {
NSFileHandle* myFileHandle = [NSFileHandle fileHandleForWritingAtPath:path];
[myFileHandle writeData:UIImagePNGRepresentation(info [UIImagePickerControllerOriginalImage])];
[myFileHandle closeFile];
}
//
// Loading from documents
//
NSFileHandle* myFileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
UIImage* loadedImage = [UIImage imageWithData:[myFileHandle readDataToEndOfFile]];
self.chosenImageOne = loadedImage;
[self.imageViewOne setImage:self.chosenImageOne];
[self dismissViewControllerAnimated:YES completion:nil];
}
if (self.imageViewTwo.tag == 200)
{
//
// Saving into Documents folder
//
NSString* path = [NSHomeDirectory() stringByAppendingString:#"/Documents/two.png"];
BOOL ok = [[NSFileManager defaultManager] createFileAtPath:path
contents:nil attributes:nil];
if (!ok) {
NSLog(#"Error creating file %#", path);
} else {
NSFileHandle* myFileHandle = [NSFileHandle fileHandleForWritingAtPath:path];
[myFileHandle writeData:UIImagePNGRepresentation(info [UIImagePickerControllerOriginalImage])];
[myFileHandle closeFile];
}
//
// Loading from documents
//
NSFileHandle* myFileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
UIImage* loadedImage = [UIImage imageWithData:[myFileHandle readDataToEndOfFile]];
self.chosenImageTwo = loadedImage;
[self.imageViewTwo setImage:self.chosenImageTwo];
[self dismissViewControllerAnimated:YES completion:nil];
}
}
From what I understood of the question, set tags to your UIImageView and change is accordingly. something like:
[self.imageViewOne setTag:100];
[self.imageViewTne setTag:200];
And then in your delegates you can check the tag value and do the needful:
if ( imageView.tag == 100)
{
// Code for first imageView
}

Drag and drop from finder to WebView

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];
}

Default Save location of document in Cocoa document based application

I have created a Cocoa document based picture drawing application. I want that the default location of a new document created using my app in Save/Save As dialog should be in ~/Pictures/MyAppName/ directory.
How can I achieve this?
I tried more or less what Ole suggested below, but it doesn't work. Here is my implementation of prepareSavePanel. What am I doing wrong?
- (BOOL)prepareSavePanel:(NSSavePanel *)savePanel
{
if ([self fileURL] == nil) {
//new, not saved yet
[savePanel setExtensionHidden:NO];
//set default save location
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSPicturesDirectory, NSUserDomainMask, YES);
if ([paths count] > 0) {
NSString *userPicturesPath = [paths objectAtIndex:0];
NSString *myDirPath = [userPicturesPath stringByAppendingPathComponent:#"MyAppName"];
//create directory is it doesn't already exist
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDir;
BOOL useMyAppDir = NO;
if([fileManager fileExistsAtPath:myDirPath isDirectory:&isDir]){
if (isDir) {
useMyAppDir = YES;
}
} else {
//create the directory
if([fileManager createDirectoryAtPath:myDirPath withIntermediateDirectories:YES attributes:nil error:nil]){
useMyAppDir = YES;
}
}
if (useMyAppDir) {
NSURL * myAppDirectoryURL = [NSURL URLWithString:myDirPath];
[savePanel setDirectoryURL:myAppDirectoryURL];
}
}
} else {
[savePanel setExtensionHidden:[self fileNameExtensionWasHiddenInLastRunSavePanel]];
}
return YES;
}
In your NSDocument subclass, override -prepareSavePanel:
- (BOOL) prepareSavePanel:(NSSavePanel *)savePanel
{
// Set default folder if no default preference is present
NSDictionary *userDefaults = [[NSUserDefaults standardUserDefaults] persistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];
if ([userDefaults objectForKey:#"NSNavLastRootDirectory"] == nil) {
NSArray *picturesFolderURLs = [[NSFileManager defaultManager] URLsForDirectory:NSPicturesDirectory inDomains:NSUserDomainMask];
if ([picturesFolderURLs count] > 0) {
NSURL *picturesFolderURL = [[picturesFolderURLs objectAtIndex:0] URLByAppendingPathComponent:#"MyAppName"];
[savePanel setDirectoryURL:picturesFolderURL];
}
}
return YES;
}

Resources