7124337: [macosx] FileDialog fails to select multiple files
Reviewed-by: anthony, swingler
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java Tue May 15 15:04:10 2012 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java Wed May 16 13:15:27 2012 +0400
@@ -34,6 +34,7 @@
import java.io.*;
import sun.awt.CausedFocusEvent.Cause;
+import sun.awt.AWTAccessor;
import sun.java2d.pipe.Region;
class CFileDialog implements FileDialogPeer {
@@ -53,33 +54,40 @@
title = " ";
}
- String userFileName = nativeRunFileDialog(title,
- dialogMode, navigateApps,
+ String[] userFileNames = nativeRunFileDialog(title,
+ dialogMode,
+ target.isMultipleMode(),
+ navigateApps,
target.getFilenameFilter() != null,
target.getDirectory(),
target.getFile());
- File file = null;
- if (userFileName != null) {
+ String directory = null;
+ String file = null;
+ File[] files = null;
+
+ if (userFileNames != null) {
// the dialog wasn't cancelled
- file = new File(userFileName);
+ int filesNumber = userFileNames.length;
+ files = new File[filesNumber];
+ for (int i = 0; i < filesNumber; i++) {
+ files[i] = new File(userFileNames[i]);
+ }
+
+ directory = files[0].getParent();
+ // make sure directory always ends in '/'
+ if (!directory.endsWith(File.separator)) {
+ directory = directory + File.separator;
+ }
+
+ file = files[0].getName(); // pick any file
}
- if (file != null) {
- // make sure directory always ends in '/'
- String parent = file.getParent();
- if (!parent.endsWith(File.separator)) {
- parent = parent + File.separator;
- }
-
- // store results back in component
- target.setDirectory(parent);
- target.setFile(file.getName());
- } else {
- // setting file name to null is how we tell
- // java client that user hit the cancel button
- target.setFile(null);
- }
+ // store results back in component
+ AWTAccessor.FileDialogAccessor accessor = AWTAccessor.getFileDialogAccessor();
+ accessor.setDirectory(target, directory);
+ accessor.setFile(target, file);
+ accessor.setFiles(target, files);
} finally {
// Java2 Dialog waits for hide to let show() return
target.dispose();
@@ -133,8 +141,8 @@
return ret;
}
- private native String nativeRunFileDialog(String title, int mode,
- boolean shouldNavigateApps, boolean hasFilenameFilter,
+ private native String[] nativeRunFileDialog(String title, int mode,
+ boolean multipleMode, boolean shouldNavigateApps, boolean hasFilenameFilter,
String directory, String file);
@Override
--- a/jdk/src/macosx/native/sun/awt/CFileDialog.h Tue May 15 15:04:10 2012 +0400
+++ b/jdk/src/macosx/native/sun/awt/CFileDialog.h Wed May 16 13:15:27 2012 +0400
@@ -46,11 +46,14 @@
// File dialog's mode
jint fMode;
+ // Indicates whether the user can select multiple files
+ BOOL fMultipleMode;
+
// Should we navigate into apps?
BOOL fNavigateApps;
- // panel's filename
- NSString *fReturnedFilename;
+ // Contains the absolute paths of the selected files as URLs
+ NSArray *fURLs;
}
// Allocator
@@ -60,6 +63,7 @@
directory:(NSString *)inPath
file:(NSString *)inFile
mode:(jint)inMode
+ multipleMode:(BOOL)inMultipleMode
shouldNavigate:(BOOL)inNavigateApps
withEnv:(JNIEnv*)env;
@@ -69,7 +73,7 @@
// Get dialog return value
- (BOOL) userClickedOK;
-// Filename user chose
-- (NSString *) filename;
+// Returns the absolute paths of the selected files as URLs
+- (NSArray *) URLs;
@end
--- a/jdk/src/macosx/native/sun/awt/CFileDialog.m Tue May 15 15:04:10 2012 +0400
+++ b/jdk/src/macosx/native/sun/awt/CFileDialog.m Wed May 16 13:15:27 2012 +0400
@@ -41,6 +41,7 @@
directory:(NSString *)inPath
file:(NSString *)inFile
mode:(jint)inMode
+ multipleMode:(BOOL)inMultipleMode
shouldNavigate:(BOOL)inNavigateApps
withEnv:(JNIEnv*)env;
{
@@ -54,6 +55,7 @@
fTitle = inTitle;
[fTitle retain];
fMode = inMode;
+ fMultipleMode = inMultipleMode;
fNavigateApps = inNavigateApps;
fPanelResult = NSCancelButton;
}
@@ -79,8 +81,8 @@
[fTitle release];
fTitle = nil;
- [fReturnedFilename release];
- fReturnedFilename = nil;
+ [fURLs release];
+ fURLs = nil;
[super dealloc];
}
@@ -105,7 +107,7 @@
if (fMode == java_awt_FileDialog_LOAD) {
NSOpenPanel *openPanel = (NSOpenPanel *)thePanel;
- [openPanel setAllowsMultipleSelection:NO];
+ [openPanel setAllowsMultipleSelection:fMultipleMode];
[openPanel setCanChooseFiles:YES];
[openPanel setCanChooseDirectories:NO];
[openPanel setCanCreateDirectories:YES];
@@ -114,8 +116,16 @@
[thePanel setDelegate:self];
fPanelResult = [thePanel runModalForDirectory:fDirectory file:fFile];
[thePanel setDelegate:nil];
- fReturnedFilename = [thePanel filename];
- [fReturnedFilename retain];
+
+ if ([self userClickedOK]) {
+ if (fMode == java_awt_FileDialog_LOAD) {
+ NSOpenPanel *openPanel = (NSOpenPanel *)thePanel;
+ fURLs = [openPanel URLs];
+ } else {
+ fURLs = [NSArray arrayWithObject:[thePanel URL]];
+ }
+ [fURLs retain];
+ }
}
[self disposer];
@@ -158,8 +168,8 @@
return fPanelResult == NSOKButton;
}
-- (NSString *)filename {
- return [[fReturnedFilename retain] autorelease];
+- (NSArray *)URLs {
+ return [[fURLs retain] autorelease];
}
@end
@@ -167,13 +177,14 @@
* Class: sun_lwawt_macosx_CFileDialog
* Method: nativeRunFileDialog
* Signature: (Ljava/lang/String;ILjava/io/FilenameFilter;
- * Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+ * Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;
*/
-JNIEXPORT jstring JNICALL
+JNIEXPORT jobjectArray JNICALL
Java_sun_lwawt_macosx_CFileDialog_nativeRunFileDialog
-(JNIEnv *env, jobject peer, jstring title, jint mode, jboolean navigateApps, jboolean hasFilter, jstring directory, jstring file)
+(JNIEnv *env, jobject peer, jstring title, jint mode, jboolean multipleMode,
+ jboolean navigateApps, jboolean hasFilter, jstring directory, jstring file)
{
- jstring returnValue = NULL;
+ jobjectArray returnValue = NULL;
JNF_COCOA_ENTER(env);
NSString *dialogTitle = JNFJavaToNSString(env, title);
@@ -187,6 +198,7 @@
directory:JNFJavaToNSString(env, directory)
file:JNFJavaToNSString(env, file)
mode:mode
+ multipleMode:multipleMode
shouldNavigate:navigateApps
withEnv:env];
@@ -196,8 +208,18 @@
waitUntilDone:YES];
if ([dialogDelegate userClickedOK]) {
- NSString *filename = [dialogDelegate filename];
- returnValue = JNFNSToJavaString(env, filename);
+ NSArray *urls = [dialogDelegate URLs];
+ jsize count = [urls count];
+
+ jclass stringClass = (*env)->FindClass(env, "java/lang/String");
+ returnValue = (*env)->NewObjectArray(env, count, stringClass, NULL);
+ (*env)->DeleteLocalRef(env, stringClass);
+
+ [urls enumerateObjectsUsingBlock:^(id url, NSUInteger index, BOOL *stop) {
+ jstring filename = JNFNormalizedJavaStringForPath(env, [url path]);
+ (*env)->SetObjectArrayElement(env, returnValue, index, filename);
+ (*env)->DeleteLocalRef(env, filename);
+ }];
}
[dialogDelegate release];
--- a/jdk/src/share/classes/java/awt/FileDialog.java Tue May 15 15:04:10 2012 +0400
+++ b/jdk/src/share/classes/java/awt/FileDialog.java Wed May 16 13:15:27 2012 +0400
@@ -147,8 +147,8 @@
static {
AWTAccessor.setFileDialogAccessor(
new AWTAccessor.FileDialogAccessor() {
- public void setFiles(FileDialog fileDialog, String directory, String files[]) {
- fileDialog.setFiles(directory, files);
+ public void setFiles(FileDialog fileDialog, File files[]) {
+ fileDialog.setFiles(files);
}
public void setFile(FileDialog fileDialog, String file) {
fileDialog.file = ("".equals(file)) ? null : file;
@@ -446,13 +446,9 @@
* @see #getFiles
* @since 1.7
*/
- private void setFiles(String directory, String files[]) {
+ private void setFiles(File files[]) {
synchronized (getObjectLock()) {
- int filesNumber = (files != null) ? files.length : 0;
- this.files = new File[filesNumber];
- for (int i = 0; i < filesNumber; i++) {
- this.files[i] = new File(directory, files[i]);
- }
+ this.files = files;
}
}
--- a/jdk/src/share/classes/sun/awt/AWTAccessor.java Tue May 15 15:04:10 2012 +0400
+++ b/jdk/src/share/classes/sun/awt/AWTAccessor.java Wed May 16 13:15:27 2012 +0400
@@ -34,6 +34,8 @@
import java.awt.peer.ComponentPeer;
import java.security.AccessControlContext;
+import java.io.File;
+
/**
* The AWTAccessor utility class.
* The main purpose of this class is to enable accessing
@@ -455,7 +457,7 @@
/*
* Sets the files the user selects
*/
- void setFiles(FileDialog fileDialog, String directory, String files[]);
+ void setFiles(FileDialog fileDialog, File files[]);
/*
* Sets the file the user selects
--- a/jdk/src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java Tue May 15 15:04:10 2012 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java Wed May 16 13:15:27 2012 +0400
@@ -73,7 +73,7 @@
if (filenames == null) {
accessor.setDirectory(fd, null);
accessor.setFile(fd, null);
- accessor.setFiles(fd, null, null);
+ accessor.setFiles(fd, null);
} else {
// Fix 6987233: add the trailing slash if it's absent
String with_separator = directory;
@@ -83,7 +83,13 @@
}
accessor.setDirectory(fd, with_separator);
accessor.setFile(fd, filenames[0]);
- accessor.setFiles(fd, directory, filenames);
+
+ int filesNumber = (filenames != null) ? filenames.length : 0;
+ File[] files = new File[filesNumber];
+ for (int i = 0; i < filesNumber; i++) {
+ files[i] = new File(directory, filenames[i]);
+ }
+ accessor.setFiles(fd, files);
}
}
--- a/jdk/src/solaris/classes/sun/awt/X11/XFileDialogPeer.java Tue May 15 15:04:10 2012 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XFileDialogPeer.java Wed May 16 13:15:27 2012 +0400
@@ -396,11 +396,18 @@
savedFile = file.substring(index+1);
}
+ String[] fileNames = fileList.getSelectedItems();
+ int filesNumber = (fileNames != null) ? fileNames.length : 0;
+ File[] files = new File[filesNumber];
+ for (int i = 0; i < filesNumber; i++) {
+ files[i] = new File(savedDir, fileNames[i]);
+ }
+
AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor();
fileDialogAccessor.setDirectory(target, savedDir);
fileDialogAccessor.setFile(target, savedFile);
- fileDialogAccessor.setFiles(target, savedDir, fileList.getSelectedItems());
+ fileDialogAccessor.setFiles(target, files);
}
/**
@@ -419,7 +426,7 @@
fileDialogAccessor.setDirectory(target, null);
fileDialogAccessor.setFile(target, null);
- fileDialogAccessor.setFiles(target, null, null);
+ fileDialogAccessor.setFiles(target, null);
handleQuitButton();
}
--- a/jdk/src/windows/classes/sun/awt/windows/WFileDialogPeer.java Tue May 15 15:04:10 2012 +0400
+++ b/jdk/src/windows/classes/sun/awt/windows/WFileDialogPeer.java Wed May 16 13:15:27 2012 +0400
@@ -139,13 +139,16 @@
String jDirectory = null;
String jFile = null;
- String jFiles[] = null;
+ File[] jFiles = null;
if (multiple) {
jDirectory = wFiles[0];
- jFiles = new String[wFiles.length - 1];
- System.arraycopy(wFiles, 1, jFiles, 0, jFiles.length);
- jFile = jFiles[1]; // choose any file
+ int filesNumber = wFiles.length - 1;
+ jFiles = new File[filesNumber];
+ for (int i = 0; i < filesNumber; i++) {
+ jFiles[i] = new File(jDirectory, wFiles[i + 1]);
+ }
+ jFile = wFiles[1]; // choose any file
} else {
int index = wFiles[0].lastIndexOf(java.io.File.separatorChar);
if (index == -1) {
@@ -155,7 +158,7 @@
jDirectory = wFiles[0].substring(0, index + 1);
jFile = wFiles[0].substring(index + 1);
}
- jFiles = new String[] { jFile };
+ jFiles = new File[] { new File(jDirectory, jFile) };
}
final FileDialog fileDialog = (FileDialog)target;
@@ -163,7 +166,7 @@
fileDialogAccessor.setDirectory(fileDialog, jDirectory);
fileDialogAccessor.setFile(fileDialog, jFile);
- fileDialogAccessor.setFiles(fileDialog, jDirectory, jFiles);
+ fileDialogAccessor.setFiles(fileDialog, jFiles);
WToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() {
public void run() {
@@ -178,7 +181,7 @@
final FileDialog fileDialog = (FileDialog)target;
AWTAccessor.getFileDialogAccessor().setFile(fileDialog, null);
- AWTAccessor.getFileDialogAccessor().setFiles(fileDialog, null, null);
+ AWTAccessor.getFileDialogAccessor().setFiles(fileDialog, null);
WToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() {
public void run() {