A DESCRIPTION OF THE REQUEST :
Creating a JFileChooser to display any directory on OSX won't work if the Java application is running in a sandbox environment.
In the Console log I get this crash report:
JavaAppLauncher(31676) deny file-read-data /Users/johndoe
Process: JavaAppLauncher [31676]
Path: /Users/johndoe/Documents/Projects/SwingTest.app/Contents/MacOS/JavaAppLauncher
Load Address: 0x1071b2000
Identifier: JavaAppLauncher
Version: ??? (???)
Code Type: X86-64 (Native)
Parent Process: launchd [122]
Date/Time: 2012-05-30 13:31:23.304 +0100
OS Version: Mac OS X 10.7.4 (11E53)
Report Version: 7
Backtrace:
0 libsystem_kernel.dylib 0x00007fff88af8afa __open_nocancel + 10
1 libsystem_c.dylib 0x00007fff867e3033 __opendir2$INODE64 + 51
2 libjava.dylib 0x000000010804e736 Java_java_io_UnixFileSystem_list + 175
3 0x0000000108095f90
4 0x000000010808a333
5 0x000000010808a333
6 0x000000010808a333
7 0x000000010808a333
8 0x000000010808a333
9 0x00000001080844f7
10 libjvm.dylib 0x00000001077355ff JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*) + 557
11 libjvm.dylib 0x0000000107735adc JavaCalls::call_virtual(JavaValue*, KlassHandle, Symbol*, Symbol*, JavaCallArguments*, Thread*) + 256
12 libjvm.dylib 0x0000000107735c16 JavaCalls::call_virtual(JavaValue*, Handle, KlassHandle, Symbol*, Symbol*, Thread*) + 74
13 libjvm.dylib 0x000000010776881c _ZL12thread_entryP10JavaThreadP6Thread + 169
14 libjvm.dylib 0x0000000107920388 JavaThread::thread_main_inner() + 134
15 libjvm.dylib 0x0000000107921827 JavaThread::run() + 369
16 libjvm.dylib 0x000000010785e95d _ZL10java_startP6Thread + 173
17 libsystem_c.dylib 0x00007fff867d68bf _pthread_start + 335
18 libsystem_c.dylib 0x00007fff867d9b75 thread_start + 13
Binary Images:
0x1074b1000 - 0x107b24ff7 +libjvm.dylib (??? - ???) <A37ACC18-F389-38E0-AE02-5DDC4DE9AAD7> /Users/johndoe/Documents/Projects/SwingTest.app/Contents/PlugIns/jdk1.7.0.jdk/Contents/Home/jre/lib/server/libjvm.dylib
0x108042000 - 0x108063fef +libjava.dylib (??? - ???) <4BC578CB-D29C-36CD-851F-9D01A43BDF2F> /Users/johndoe/Documents/Projects/SwingTest.app/Contents/PlugIns/jdk1.7.0.jdk/Contents/Home/jre/lib/libjava.dylib
0x7fff86788000 - 0x7fff86865fef libsystem_c.dylib (763.13.0 - compatibility 1.0.0) <41B43515-2806-3FBC-ACF1-A16F35B7E290> /usr/lib/system/libsystem_c.dylib
0x7fff88ae2000 - 0x7fff88b02fff libsystem_kernel.dylib (1699.26.8 - compatibility 1.0.0) <1DDC0B0F-DB2A-34D6-895D-E5B2B5618946> /usr/lib/system/libsystem_kernel.dylib
JUSTIFICATION :
The enhancement is required because it is impossible on the Mac platform to have an application running in the sandbox environment that allows the user to select a directory with an open dialog.
This is because of the following bugs:
- FileDialog RFE not implemented after more than two years: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6927978
- apple.awt.fileDialogForDirectories not honoured (closed as duplicate of the RFE)
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7161437
- this bug.
Before the sandbox requirements the only way to do it was to use the JFileChooser but since now it's no longer an option, we're left without any solution.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would expect to be able to see the files in the folder that the JFileChooser is showing.
ACTUAL -
I see nothing.
---------- BEGIN SOURCE ----------
import javax.swing.JFrame;
import java.io.File;
import javax.swing.JFileChooser;
public class SwingTest extends JFrame {
public String selectFolder() {
JFileChooser chooser = new JFileChooser(System.getProperty("user.home"));
chooser.showOpenDialog(this);
return chooser.getSelectedFile().getAbsolutePath();
}
public static void main(String[] args) {
SwingTest fdt = new SwingTest();
File dir = new File(System.getProperty("user.home"));
String selectedFolder = fdt.selectFolder();
System.out.println("The selected file was: " + selectedFolder);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
There is no workaround when using the JFileChooser. The only way to open a directory would be to use a FileDialog and apply the following patch which will make the FileDialog honour the apple.awt.fileDialogForDirectories property:
diff -r 6432464ffec2 src/macosx/classes/sun/lwawt/macosx/CFileDialog.java
--- a/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java Sat May 26 08:01:40 2012 -0700
+++ b/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java Tue May 29 17:56:51 2012 +0100
@@ -49,20 +49,28 @@ class CFileDialog implements FileDialogP
navigateApps = true;
String title = target.getTitle();
if (title == null) {
title = " ";
}
+ String chooseDirectoriesValue = System.getProperty("apple.awt.fileDialogForDirectories");
+ boolean chooseDirectories = false;
+ if(chooseDirectoriesValue != null &&
+ chooseDirectoriesValue.equalsIgnoreCase("true")) {
+ chooseDirectories = true;
+ }
+
String[] userFileNames = nativeRunFileDialog(title,
dialogMode,
target.isMultipleMode(),
navigateApps,
+ chooseDirectories,
target.getFilenameFilter() != null,
target.getDirectory(),
target.getFile());
String directory = null;
String file = null;
File[] files = null;
@@ -137,18 +145,18 @@ class CFileDialog implements FileDialogP
File directoryObj = new File(fileObj.getParent());
String nameOnly = fileObj.getName();
ret = ff.accept(directoryObj, nameOnly);
}
return ret;
}
private native String[] nativeRunFileDialog(String title, int mode,
- boolean multipleMode, boolean shouldNavigateApps, boolean hasFilenameFilter,
- String directory, String file);
+ boolean multipleMode, boolean shouldNavigateApps, boolean canChooseDirectories,
+ boolean hasFilenameFilter, String directory, String file);
@Override
public void setDirectory(String dir) {
}
@Override
public void setFile(String file) {
}
diff -r 6432464ffec2 src/macosx/native/sun/awt/CFileDialog.h
--- a/src/macosx/native/sun/awt/CFileDialog.h Sat May 26 08:01:40 2012 -0700
+++ b/src/macosx/native/sun/awt/CFileDialog.h Tue May 29 17:56:51 2012 +0100
@@ -47,16 +47,19 @@
jint fMode;
// Indicates whether the user can select multiple files
BOOL fMultipleMode;
// Should we navigate into apps?
BOOL fNavigateApps;
+ // Can the dialog choose directories ?
+ BOOL fChooseDirectories;
+
// Contains the absolute paths of the selected files as URLs
NSArray *fURLs;
}
// Allocator
- (id) initWithFilter:(jboolean)inHasFilter
fileDialog:(jobject)inDialog
title:(NSString *)inTitle
diff -r 6432464ffec2 src/macosx/native/sun/awt/CFileDialog.m
--- a/src/macosx/native/sun/awt/CFileDialog.m Sat May 26 08:01:40 2012 -0700
+++ b/src/macosx/native/sun/awt/CFileDialog.m Tue May 29 17:56:51 2012 +0100
@@ -38,30 +38,32 @@
- (id)initWithFilter:(jboolean)inHasFilter
fileDialog:(jobject)inDialog
title:(NSString *)inTitle
directory:(NSString *)inPath
file:(NSString *)inFile
mode:(jint)inMode
multipleMode:(BOOL)inMultipleMode
shouldNavigate:(BOOL)inNavigateApps
+canChooseDirectories:(BOOL)inChooseDirectories
withEnv:(JNIEnv*)env;
{
if (self == [super init]) {
fHasFileFilter = inHasFilter;
fFileDialog = JNFNewGlobalRef(env, inDialog);
fDirectory = inPath;
[fDirectory retain];
fFile = inFile;
[fFile retain];
fTitle = inTitle;
[fTitle retain];
fMode = inMode;
fMultipleMode = inMultipleMode;
fNavigateApps = inNavigateApps;
+ fChooseDirectories = inChooseDirectories;
fPanelResult = NSCancelButton;
}
return self;
}
-(void) disposer {
if (fFileDialog != NULL) {
@@ -104,17 +106,17 @@
if (fNavigateApps) {
[thePanel setTreatsFilePackagesAsDirectories:YES];
}
if (fMode == java_awt_FileDialog_LOAD) {
NSOpenPanel *openPanel = (NSOpenPanel *)thePanel;
[openPanel setAllowsMultipleSelection:fMultipleMode];
[openPanel setCanChooseFiles:YES];
- [openPanel setCanChooseDirectories:NO];
+ [openPanel setCanChooseDirectories:fChooseDirectories];
[openPanel setCanCreateDirectories:YES];
}
[thePanel setDelegate:self];
fPanelResult = [thePanel runModalForDirectory:fDirectory file:fFile];
[thePanel setDelegate:nil];
if ([self userClickedOK]) {
@@ -177,17 +179,17 @@
* Class: sun_lwawt_macosx_CFileDialog
* Method: nativeRunFileDialog
* Signature: (Ljava/lang/String;ILjava/io/FilenameFilter;
* Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL
Java_sun_lwawt_macosx_CFileDialog_nativeRunFileDialog
(JNIEnv *env, jobject peer, jstring title, jint mode, jboolean multipleMode,
- jboolean navigateApps, jboolean hasFilter, jstring directory, jstring file)
+ jboolean navigateApps, jboolean chooseDirectories, jboolean hasFilter, jstring directory, jstring file)
{
jobjectArray returnValue = NULL;
JNF_COCOA_ENTER(env);
NSString *dialogTitle = JNFJavaToNSString(env, title);
if ([dialogTitle length] == 0) {
dialogTitle = @" ";
}
@@ -195,16 +197,17 @@ JNF_COCOA_ENTER(env);
CFileDialog *dialogDelegate = [[CFileDialog alloc] initWithFilter:hasFilter
fileDialog:peer
title:dialogTitle
directory:JNFJavaToNSString(env, directory)
file:JNFJavaToNSString(env, file)
mode:mode
multipleMode:multipleMode
shouldNavigate:navigateApps
+ canChooseDirectories:chooseDirectories
withEnv:env];
[JNFRunLoop performOnMainThread:@selector(safeSaveOrLoad)
on:dialogDelegate
withObject:nil
waitUntilDone:YES];
if ([dialogDelegate userClickedOK]) {