package com.limegroup.gnutella.gui;
import java.awt.Component;
import java.awt.FileDialog;
import java.io.File;
import java.io.FilenameFilter;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
import com.limegroup.gnutella.util.CommonUtils;
/**
* This is a utility class that displays a file chooser dialog to the user,
* automatically selecting the appropriate dialog based on the operating
* system, the current theme, etc. For example, if the user is on OS X
* and is not using the default theme, this displays the standard
* <tt>MetalLookAndFeel</tt> file chooser, as that is the only one that
* will appear with themes.
*/
public final class FileChooserHandler {
/**
* Displays a directory chooser to the user and returns the selected
* <tt>File</tt>. This uses the main application frame as the parent
* component.
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a directory was not selected correctly
*/
public static File getInputDirectory() {
return getInputDirectory(GUIMediator.getAppFrame());
}
/**
* Same as <tt>getInputDirectory</tt> that takes no arguments,
* except this allows the caller to specify the parent component of
* the chooser.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputDirectory(Component parent) {
return getInputDirectory(parent,
"FILE_CHOOSER_DIRECTORY_TITLE",
CommonUtils.getCurrentDirectory());
}
/**
* Same as <tt>getInputFile</tt> that takes no arguments,
* except this allows the caller to specify the parent component of
* the chooser as well as other options.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @param directory the directory to open the dialog to
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputDirectory(Component parent,
File directory) {
return getInputDirectory(parent,
"FILE_CHOOSER_DIRECTORY_TITLE",
"FILE_CHOOSER_DIRECTORY_BUTTON_LABEL",
directory);
}
/**
* Same as <tt>getInputFile</tt> that takes no arguments,
* except this allows the caller to specify the parent component of
* the chooser as well as other options.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @param directory the directory to open the dialog to
* @param filter the <tt>FileFilter</tt> instance for customizing
* the files that are displayed -- if this is null, no filter is used
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputDirectory(Component parent,
File directory,
FileFilter filter) {
return getInputDirectory(parent,
"FILE_CHOOSER_DIRECTORY_TITLE",
"FILE_CHOOSER_DIRECTORY_BUTTON_LABEL",
directory,
filter);
}
/**
* Same as <tt>getInputFile</tt> that takes no arguments,
* except this allows the caller to specify the parent component of
* the chooser as well as other options.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @param titleKey the key for the locale-specific string to use for
* the file dialog title
* @param directory the directory to open the dialog to
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputDirectory(Component parent, String titleKey,
File directory) {
return getInputDirectory(parent,
titleKey,
"FILE_CHOOSER_DIRECTORY_BUTTON_LABEL",
directory);
}
/**
* Same as <tt>getInputFile</tt> that takes no arguments,
* except this allows the caller to specify the parent component of
* the chooser as well as other options.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @param titleKey the key for the locale-specific string to use for
* the file dialog title
* @param directory the directory to open the dialog to
* @param filter the <tt>FileFilter</tt> instance for customizing
* the files that are displayed -- if this is null, no filter is used
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputDirectory(Component parent, String titleKey,
File directory, FileFilter filter) {
return getInputDirectory(parent,
titleKey,
"FILE_CHOOSER_DIRECTORY_BUTTON_LABEL",
directory,
filter);
}
/**
* Same as <tt>getInputFile</tt> that takes no arguments,
* except this allows the caller to specify the parent component of
* the chooser as well as other options.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @param titleKey the key for the locale-specific string to use for
* the file dialog title
* @param approveKey the key for the locale-specific string to use for
* the approve button text
* @param directory the directory to open the dialog to
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputDirectory(Component parent, String titleKey,
String approveKey, File directory) {
return getInputDirectory(parent,
titleKey,
approveKey,
directory,
null);
}
/**
* Same as <tt>getInputFile</tt> that takes no arguments,
* except this allows the caller to specify the parent component of
* the chooser as well as other options.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @param titleKey the key for the locale-specific string to use for
* the file dialog title
* @param approveKey the key for the locale-specific string to use for
* the approve button text
* @param directory the directory to open the dialog to
* @param filter the <tt>FileFilter</tt> instance for customizing
* the files that are displayed -- if this is null, no filter is used
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputDirectory(Component parent, String titleKey,
String approveKey, File directory,
FileFilter filter) {
return getInput(parent,
titleKey,
approveKey,
directory,
JFileChooser.DIRECTORIES_ONLY,
JFileChooser.APPROVE_OPTION,
filter);
}
/**
* Displays a file chooser to the user and returns the selected
* <tt>File</tt>. This uses the main application frame as the parent
* component.
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputFile() {
return getInputFile(GUIMediator.getAppFrame());
}
/**
* Same as <tt>getInputFile</tt> that takes no arguments,
* except this allows the caller to specify the parent component of
* the chooser.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputFile(Component parent) {
return getInputFile(parent,
"FILE_CHOOSER_DIRECTORY_TITLE",
"FILE_CHOOSER_DIRECTORY_BUTTON_LABEL",
CommonUtils.getCurrentDirectory());
}
/**
* Same as <tt>getInputFile</tt> that takes no arguments,
* except this allows the caller to specify the parent component of
* the chooser.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @param filter the <tt>FileFilter</tt> instance for customizing
* the files that are displayed -- if this is null, no filter is used
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputFile(Component parent, FileFilter filter) {
return getInputFile(parent,
"FILE_CHOOSER_DIRECTORY_TITLE",
"FILE_CHOOSER_DIRECTORY_BUTTON_LABEL",
CommonUtils.getCurrentDirectory(),
filter);
}
/**
* Same as <tt>getInputFile</tt> that takes no arguments,
* except this allows the caller to specify the parent component of
* the chooser.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @param titleKey the key for the locale-specific string to use for
* the file dialog title
* @param directory the directory to open the dialog to
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputFile(Component parent, String titleKey,
File directory) {
return getInputFile(parent,
titleKey,
"FILE_CHOOSER_DIRECTORY_BUTTON_LABEL",
directory);
}
/**
* Same as <tt>getInputFile</tt> that takes no arguments,
* except this allows the caller to specify the parent component of
* the chooser.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @param titleKey the key for the locale-specific string to use for
* the file dialog title
* @param directory the directory to open the dialog to
* @param filter the <tt>FileFilter</tt> instance for customizing
* the files that are displayed -- if this is null, no filter is used
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputFile(Component parent, String titleKey,
File directory, FileFilter filter) {
return getInputFile(parent,
titleKey,
"FILE_CHOOSER_DIRECTORY_BUTTON_LABEL",
directory,
filter);
}
/**
* Same as <tt>getInputFile</tt> that takes no arguments,
* except this allows the caller to specify the parent component of
* the chooser.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @param titleKey the key for the locale-specific string to use for
* the file dialog title
* @param approveKey the key for the locale-specific string to use for
* the approve button text
* @param directory the directory to open the dialog to
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputFile(Component parent, String titleKey,
String approveKey, File directory) {
return getInput(parent,
titleKey,
approveKey,
directory,
JFileChooser.FILES_ONLY,
JFileChooser.APPROVE_OPTION);
}
/**
* Same as <tt>getInputFile</tt> that takes no arguments,
* except this allows the caller to specify the parent component of
* the chooser.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @param titleKey the key for the locale-specific string to use for
* the file dialog title
* @param approveKey the key for the locale-specific string to use for
* the approve button text
* @param directory the directory to open the dialog to
* @param filter the <tt>FileFilter</tt> instance for customizing
* the files that are displayed -- if this is null, no filter is used
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInputFile(Component parent, String titleKey,
String approveKey, File directory,
FileFilter filter) {
return getInput(parent,
titleKey,
approveKey,
directory,
JFileChooser.FILES_ONLY,
JFileChooser.APPROVE_OPTION,
filter);
}
/**
* The implementation that the other methods delegate to. This
* provides the caller with all available options for customizing
* the <tt>JFileChooser</tt> instance. If a <tt>FileDialog</tt>
* is displayed instead of a <tt>JFileChooser</tt> (on OS X, for
* example), most or all of these options have no effect.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @param titleKey the key for the locale-specific string to use for
* the file dialog title
* @param approveKey the key for the locale-specific string to use for
* the approve button text
* @param directory the directory to open the dialog to
* @param mode the "mode" to open the <tt>JFileChooser</tt> in from
* the <tt>JFileChooser</tt> class, such as
* <tt>JFileChooser.DIRECTORIES_ONLY</tt>
* @param option the option to look for in the return code, such as
* <tt>JFileChooser.APPROVE_OPTION</tt>
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInput(Component parent, String titleKey,
String approveKey,
File directory, int mode,
int option) {
return getInput(parent, titleKey, approveKey, directory, mode,
option, null);
}
/**
* Opens a dialog asking the user to choose a file which is is used for saving
* to.
* @param parent the parent component the dialog is centered on
* @param titleKey the key for the locale-specific string to use for
* the file dialog title
* @param suggestedFile the suggested file for saving
* @return the file or <code>null</code> when the user cancelled the dialog
*/
public static File getSaveAsFile(Component parent, String titleKey, File suggestedFile) {
return getSaveAsFile(parent, titleKey, suggestedFile, null);
}
/**
* Opens a dialog asking the user to choose a file which is is used for saving
* to.
* @param parent the parent component the dialog is centered on
* @param titleKey the key for the locale-specific string to use for
* the file dialog title
* @param suggestedFile the suggested file for saving
* @param the filter to use for what's shown.
* @return the file or <code>null</code> when the user cancelled the dialog
*/
public static File getSaveAsFile(Component parent, String titleKey,
File suggestedFile, final FileFilter filter) {
if(CommonUtils.isAnyMac()) {
FileDialog dialog = new FileDialog(GUIMediator.getAppFrame(),
GUIMediator.getStringResource(titleKey),
FileDialog.SAVE);
dialog.setDirectory(suggestedFile.getParent());
dialog.setFile(suggestedFile.getName());
if(filter != null) {
FilenameFilter f = new FilenameFilter() {
public boolean accept(File dir, String name) {
return filter.accept(new File(dir, name));
}
};
dialog.setFilenameFilter(f);
}
dialog.setVisible(true);
String dir = dialog.getDirectory();
String file = dialog.getFile();
if(dir != null && file != null) {
File f = new File(dir, file);
if(filter != null && !filter.accept(f))
return null;
else
return f;
} else {
return null;
}
} else {
JFileChooser chooser = getDirectoryChooser(titleKey, null, null, JFileChooser.FILES_ONLY, filter);
chooser.setSelectedFile(suggestedFile);
return chooser.showSaveDialog(parent) != JFileChooser.APPROVE_OPTION ?
null : chooser.getSelectedFile();
}
}
/**
* The implementation that the other methods delegate to. This
* provides the caller with all available options for customizing
* the <tt>JFileChooser</tt> instance. If a <tt>FileDialog</tt>
* is displayed instead of a <tt>JFileChooser</tt> (on OS X, for
* example), most or all of these options have no effect.
*
* @param parent the <tt>Component</tt> that should be the dialog's
* parent
* @param titleKey the key for the locale-specific string to use for
* the file dialog title
* @param approveKey the key for the locale-specific string to use for
* the approve button text
* @param directory the directory to open the dialog to
* @param mode the "mode" to open the <tt>JFileChooser</tt> in from
* the <tt>JFileChooser</tt> class, such as
* <tt>JFileChooser.DIRECTORIES_ONLY</tt>
* @param option the option to look for in the return code, such as
* <tt>JFileChooser.APPROVE_OPTION</tt>
* @param filter the <tt>FileFilter</tt> instance for customizing
* the files that are displayed -- if this is null, no filter is used
*
* @return the selected <tt>File</tt> instance, or <tt>null</tt> if
* a file was not selected correctly
*/
public static File getInput(Component parent, String titleKey,
String approveKey,
File directory, int mode,
int option,
final FileFilter filter) {
if(!CommonUtils.isAnyMac()) {
JFileChooser fileChooser =
getDirectoryChooser(titleKey, approveKey, directory, mode, filter);
try {
if(fileChooser.showOpenDialog(parent) != option)
return null;
} catch(NullPointerException npe) {
// ignore NPE. can't do anything with it ...
return null;
}
return fileChooser.getSelectedFile();
} else {
FileDialog dialog;
if(mode == JFileChooser.DIRECTORIES_ONLY)
dialog = MacUtils.getFolderDialog();
else
dialog = new FileDialog(GUIMediator.getAppFrame(), "");
dialog.setTitle(GUIMediator.getStringResource(titleKey));
if(filter != null) {
FilenameFilter f = new FilenameFilter() {
public boolean accept(File dir, String name) {
return filter.accept(new File(dir, name));
}
};
dialog.setFilenameFilter(f);
}
dialog.setVisible(true);
String dirStr = dialog.getDirectory();
String fileStr = dialog.getFile();
if((dirStr==null) || (fileStr==null))
return null;
// if the filter didn't work, pretend that the person picked
// nothing
File f = new File(dirStr, fileStr);
if(filter != null && !filter.accept(f))
return null;
return f;
}
}
/**
* Returns a new <tt>JFileChooser</tt> instance for selecting directories
* and with internationalized strings for the caption and the selection
* button.
*
* @param approveKey can be <code>null</code>
* @param directory can be <code>null</code>
* @param filter can be <code>null</code>
* @return a new <tt>JFileChooser</tt> instance for selecting directories.
*/
private static JFileChooser getDirectoryChooser(String titleKey,
String approveKey, File directory, int mode, FileFilter filter) {
JFileChooser chooser = null;
if (directory == null) {
chooser = new JFileChooser();
} else {
try {
chooser = new JFileChooser(directory);
} catch (NullPointerException e) {
// Workaround for JRE bug 4711700. A NullPointer is thrown
// sometimes on the first construction under XP look and feel,
// but construction succeeds on successive attempts.
chooser = new JFileChooser(directory);
}
}
if (filter != null) {
chooser.setFileFilter(filter);
} else {
if (mode == JFileChooser.DIRECTORIES_ONLY) {
chooser.setFileFilter(new FileFilter() {
public boolean accept(File file) {
return true;
}
public String getDescription() {
return GUIMediator.getStringResource("DIRECTORY_CHOOSER_FILE_DESCRIPTION");
}
});
}
}
chooser.setFileSelectionMode(mode);
String title = GUIMediator.getStringResource(titleKey);
chooser.setDialogTitle(title);
if (approveKey != null) {
String approveButtonText = GUIMediator.getStringResource(approveKey);
chooser.setApproveButtonText(approveButtonText);
}
return chooser;
}
}