Why can I select aliases but not symbolic links in NSOpenPanel? - cocoa

I want to create an NSOpenPanel that can select any kind of file, so I do this
NSOpenPanel* panel = [NSOpenPanel openPanel];
if([panel runModalForTypes:nil] == NSOKButton) {
// process files here
}
which lets me select all files except symbolic links.
They're simply not selectable and the obvious setResolvesAliases
does nothing.
What gives?
Update 1: I did some more testing and found that this strangeness
is present in Leopard (10.5.5) but not in Tiger (10.4.8).
Update 2: The code above can select mac aliases (persistent path
data that lives in the resource fork) but not symlinks (files created with ln -s).

I cannot reproduce this. I just tried it and it works just fine. If symlink points to a directory, it shows the directory content when I select the symlink and if the symlink points to a file, I can select it as well.
Of course if the symlink points to a directory, you can only select it if choosing directories is allowed
NSOpenPanel * panel = [NSOpenPanel openPanel];
[panel setCanChooseDirectories:YES];
if ([panel runModalForTypes:nil] == NSOKButton) {
NSLog(#"%#", [panel filenames]);
}

Your code sample worked for me, as well - I'm using 10.5.5 and XCode 3.1, if it matters.
If the alias is to a directory, I couldn't select the alias, since it resolved to the directory that it was pointing to, not the alias itself (the panel seems to resolve aliases by default). I was able to select an alias to a file, though.

Related

Letting macOS sandboxed apps write file created by my non-sandboxed app

I have a macOS/Objective-C/Cocoa application. We want to spawn external applications, like TextEdit, to edit files created by this app. I'm creating these files by copying it into my ~/Documents directory (eventually I'd like to put it elsewhere, but I'm trying to simplify) with:
NSFileManager *defaultManager = [NSFileManager defaultManager];
[defaultManager copyItemAtPath:srcPath toPath:destPath error:&err];
NSDate *sourceModified = [self lastModificationOfFile:srcPath];
NSDictionary * attr = #{ NSFileModificationDate : sourceModified,
NSFileImmutable : [NSNumber numberWithBool:NO],
NSFilePosixPermissions : [NSNumber numberWithUnsignedLong:0666],
};
[defaultManager setAttributes:attr ofItemAtPath:destPath error:nil];
When I open this file in TextEdit, the window header says "filename.txt - Locked". Editing the document gives me the "Are you sure you want to modify the document in place?" dialog. I select "Overwrite", but then attempts to save give me "The document "filename.txt" could not be saved. You don't have permission."
However, this writes a "filename.txt.sb-a69dcdc5-7V6D2g" (or similarly named) file into my Documents directory. And files created from the bash shell with "echo blablabla > filename.txt" in that same directory open just fine.
I have tried many variations on those attributes. I cannot see any difference between the files which work and those which display "... - Locked" using "ls -la# filename.txt" or "xattr", even side-by-side in the same directory.
Clearly I'm up against some sandboxing issue with the files I create, but all of my search results are about the other side of this problem.
Argh. I found this: Why does TextEdit open HTML files as locked. Apparently because of the content of my .txt file, TextEdit was interpreting it as an HTML document and treating it differently based on that. Replaced the content of the file with things that didn't look like HTML and I'm able to edit the document now.

Can qt on Mac open finder and select(highlight) some files in the opened finder window?

On mac, my application creates some files in a folder for user, then I need to reveal the files to user. I can open the folder with finder by QDesktopServices::openUrl, but I can not select(highlight) the files just created in the opened finder window.
I have tried the follow code:
QStringList scriptArgs;
scriptArgs << QLatin1String("-e")
<< QString::fromLatin1("tell application \"Finder\" to select POSIX file \"%1\"")
.arg(filePath);
QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs);
scriptArgs.clear();
scriptArgs << QLatin1String("-e")
<< QLatin1String("tell application \"Finder\" to activate");
QProcess::execute("/usr/bin/osascript", scriptArgs);`
... but only one file can be selected.
Someone help me? Thank you!
I have completed it with:
NSMutableArray *fileURLs = [NSMutableArray arrayWithCapacity:fileList.size()];
for(int i=0; i<fileList.size(); i++)
{
[fileURLs addObject:[NSURL fileURLWithPath:[NSString stringWithCString:fileList.at(i).toUtf8().data() encoding:4] isDirectory:false]];
}
[[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:fileURLs];
You can tell Finder to select multiple items by passing select a list of objects, for example
tell application "Finder" to select {POSIX file "/Applications/Calendar.app", POSIX file "/Applications/Contacts.app"}
(You can play around with that kind of scripts using /Applications/Utilities/Script Editor.app.)

Move Files In Cocoa

I want to move a file from a folder to another folder
I used
[[NSFileManager defaultManager]moveItemAtPath:#"Folder/Filename.fileExtension" toPath:#"FolderToMoveTheFile" error:nil];
Is there something else to type in error: ?
Why it isn't move my file?
You would get the error by doing this:
NSError* error;
if (![[NSFileManager defaultManager]moveItemAtPath:#"Folder/Filename.fileExtension" toPath:#"FolderToMoveTheFile" error:&error])
{
// handle error, typically using the NSError object pointed to by the error variable
// In an app, you might want to pass it to a -presentError:... method of a convenient responder
// This is good enough for debugging:
NSLog(#"failed to move file: %#", error);
}
The second path that goes after toPath: must be the path including the file name at the destination. It is not correct to just specify the path to the directory into which you want to move the file.
Also, you should typically use absolute paths, not relative paths. You can use relative paths but that then depends on the current working directory for the process. That's arbitrary for apps launched from the Finder or Dock. It's really only meaningful for command-line tools launched from a shell (e.g. a Terminal window) where the user might be expected to cd to a directory and then provide relative paths as command-line arguments.

Enumerating over a directory gives me an error when I try to follow aliases

I want my users to be able to drop a folder into my OSX app. I then look at all the files in the directory and its subdirectories. That works fine but not when there is an alias in the directory. The alias is resolved correctly (Thanks to Matt Gallagher, shame on you Apple) but the enumerator does not allow me to do enumerate the target directory (it just returns no elements and the error below). Here is some sample code:
-(void)enumDirAtPath:(NSString*)path {
NSString* file_enum = nil;
NSDirectoryEnumerator* enumerator = [[NSFileManager defaultManager] enumeratorAtPath:path];
while (file_enum = [enumerator nextObject])
{
NSString* file = [[NSString stringWithFormat:#"%#/%#",path,file_enum] stringByResolvingSymlinksAndAliases];
BOOL isDirectory = NO;
[[NSFileManager defaultManager] fileExistsAtPath:file isDirectory: &isDirectory];
if (!isDirectory) {
NSLog(#"Adding file: %#",file);
} else {
NSLog(#"Found dir: %#",file);
[self enumDirAtPath: file];
}
}
}
the same code with enumeratorAtURL:includingPropertiesForKeys:options:errorHandler: gives me this error:
error: Error Domain=NSCocoaErrorDomain Code=257 "The file “Musik”
couldn’t be opened because you don’t have permission to view it."
UserInfo=0x1094cf670
{NSURL=file://localhost/Users/david/Desktop/Musik,
NSFilePath=/Users/david/Desktop/Musik, NSUnderlyingError=0x1094d43f0
"The operation couldn’t be completed. Operation not permitted"}
Even If I just dispatch_async the recursive call it won't let me do it. Is there any way I can just iterate over a directory and get all the content?
Note: I am fully aware that this could result in infinite loops. This code is just to illustrate the problem.
I‘m pretty damn sure the answer is right there in the error message:
The file “Musik” couldn’t be opened because you don’t have permission to view it.
Reveal the destination of the alias in the Finder application and check its permission via “Get Info” or ls -l# in the Terminal — I’d bet that your user account david is not being granted one of the following permissions:
read
execute
list
The last one will typically not be visible on the command line except in combination with an explicit deny-access-control-entry.

Cocoa - Open File Package in Finder

I am trying to open the Finder in a certain package.
I got this file, Example.backup, which is just a folder with an extension. In the finder, you can right click it (Show Package Contents) and I will be presented with the files. (there is no Contents folder).
I've tried opening it with NSWorkspace's methods but none open the finder at that directory, they either select the file or open it with the associated program.
Is there a way to do this in AppleScript maybe? Or Cocoa?
Thanks
Since no one answered yet, there might not be a one line solution.
All I could think of was a workaround: call /usr/bin/open with the -R option, which will reveal the given file in Finder. Since you want to show the contents of the package, you will have to reveal any file that is inside (not the package itself).
Downsides: won't work on empty package (but then you could just reveal the package), also the Finder window will show a selection on the last item.
NSString *pathToBundle = #"/tmp/test.app";
NSFileManager *fm = [[[NSFileManager alloc] init] autorelease];
// get the last file/directory in the package
// TODO: error handling / empty package
NSString *lastItemInBundle = [[fm contentsOfDirectoryAtPath:pathToBundle error:NULL] lastObject];
// reveal this file in Finder, by using /usr/bin/open
// see -R option in the manpage
NSTask *open = [[[NSTask alloc] init] autorelease];
[open setLaunchPath:#"/usr/bin/open"];
[open setCurrentDirectoryPath:pathToBundle];
[open setArguments:[NSArray arrayWithObjects:#"-R", lastItemInBundle, nil]];
[open launch];

Resources