# HG changeset patch # User dcherepanov # Date 1337159727 -14400 # Node ID 07d5ca30e79e2bbfaf78aeddf1ea1aa11c8205e2 # Parent 6fddf8394164833b883982ee080582e07ec39d80 7124337: [macosx] FileDialog fails to select multiple files Reviewed-by: anthony, swingler diff -r 6fddf8394164 -r 07d5ca30e79e jdk/src/macosx/classes/sun/lwawt/macosx/CFileDialog.java --- 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 diff -r 6fddf8394164 -r 07d5ca30e79e jdk/src/macosx/native/sun/awt/CFileDialog.h --- 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 diff -r 6fddf8394164 -r 07d5ca30e79e jdk/src/macosx/native/sun/awt/CFileDialog.m --- 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]; diff -r 6fddf8394164 -r 07d5ca30e79e jdk/src/share/classes/java/awt/FileDialog.java --- 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; } } diff -r 6fddf8394164 -r 07d5ca30e79e jdk/src/share/classes/sun/awt/AWTAccessor.java --- 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 diff -r 6fddf8394164 -r 07d5ca30e79e jdk/src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java --- 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); } } diff -r 6fddf8394164 -r 07d5ca30e79e jdk/src/solaris/classes/sun/awt/X11/XFileDialogPeer.java --- 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(); } diff -r 6fddf8394164 -r 07d5ca30e79e jdk/src/windows/classes/sun/awt/windows/WFileDialogPeer.java --- 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() {