jdk/src/share/classes/javax/swing/JFileChooser.java
changeset 2 90ce3da70b43
child 680 eaff686e34f7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/swing/JFileChooser.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,1960 @@
+/*
+ * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javax.swing;
+
+import javax.swing.event.*;
+import javax.swing.filechooser.*;
+import javax.swing.plaf.FileChooserUI;
+
+import javax.accessibility.*;
+
+import java.io.File;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+
+import java.util.Vector;
+import java.awt.AWTEvent;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.BorderLayout;
+import java.awt.Window;
+import java.awt.Dialog;
+import java.awt.Frame;
+import java.awt.GraphicsEnvironment;
+import java.awt.HeadlessException;
+import java.awt.EventQueue;
+import java.awt.Toolkit;
+import java.awt.event.*;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeEvent;
+import java.lang.ref.WeakReference;
+
+/**
+ * <code>JFileChooser</code> provides a simple mechanism for the user to
+ * choose a file.
+ * For information about using <code>JFileChooser</code>, see
+ * <a
+ href="http://java.sun.com/docs/books/tutorial/uiswing/components/filechooser.html">How to Use File Choosers</a>,
+ * a section in <em>The Java Tutorial</em>.
+ *
+ * <p>
+ *
+ * The following code pops up a file chooser for the user's home directory that
+ * sees only .jpg and .gif images:
+ * <pre>
+ *    JFileChooser chooser = new JFileChooser();
+ *    FileNameExtensionFilter filter = new FileNameExtensionFilter(
+ *        "JPG & GIF Images", "jpg", "gif");
+ *    chooser.setFileFilter(filter);
+ *    int returnVal = chooser.showOpenDialog(parent);
+ *    if(returnVal == JFileChooser.APPROVE_OPTION) {
+ *       System.out.println("You chose to open this file: " +
+ *            chooser.getSelectedFile().getName());
+ *    }
+ * </pre>
+ * <p>
+ * <strong>Warning:</strong> Swing is not thread safe. For more
+ * information see <a
+ * href="package-summary.html#threading">Swing's Threading
+ * Policy</a>.
+ *
+ * @beaninfo
+ *   attribute: isContainer false
+ * description: A component which allows for the interactive selection of a file.
+ *
+ * @author Jeff Dinkins
+ *
+ */
+public class JFileChooser extends JComponent implements Accessible {
+
+    /**
+     * @see #getUIClassID
+     * @see #readObject
+     */
+    private static final String uiClassID = "FileChooserUI";
+
+    // ************************
+    // ***** Dialog Types *****
+    // ************************
+
+    /**
+     * Type value indicating that the <code>JFileChooser</code> supports an
+     * "Open" file operation.
+     */
+    public static final int OPEN_DIALOG = 0;
+
+    /**
+     * Type value indicating that the <code>JFileChooser</code> supports a
+     * "Save" file operation.
+     */
+    public static final int SAVE_DIALOG = 1;
+
+    /**
+     * Type value indicating that the <code>JFileChooser</code> supports a
+     * developer-specified file operation.
+     */
+    public static final int CUSTOM_DIALOG = 2;
+
+
+    // ********************************
+    // ***** Dialog Return Values *****
+    // ********************************
+
+    /**
+     * Return value if cancel is chosen.
+     */
+    public static final int CANCEL_OPTION = 1;
+
+    /**
+     * Return value if approve (yes, ok) is chosen.
+     */
+    public static final int APPROVE_OPTION = 0;
+
+    /**
+     * Return value if an error occured.
+     */
+    public static final int ERROR_OPTION = -1;
+
+
+    // **********************************
+    // ***** JFileChooser properties *****
+    // **********************************
+
+
+    /** Instruction to display only files. */
+    public static final int FILES_ONLY = 0;
+
+    /** Instruction to display only directories. */
+    public static final int DIRECTORIES_ONLY = 1;
+
+    /** Instruction to display both files and directories. */
+    public static final int FILES_AND_DIRECTORIES = 2;
+
+    /** Instruction to cancel the current selection. */
+    public static final String CANCEL_SELECTION = "CancelSelection";
+
+    /**
+     * Instruction to approve the current selection
+     * (same as pressing yes or ok).
+     */
+    public static final String APPROVE_SELECTION = "ApproveSelection";
+
+    /** Identifies change in the text on the approve (yes, ok) button. */
+    public static final String APPROVE_BUTTON_TEXT_CHANGED_PROPERTY = "ApproveButtonTextChangedProperty";
+
+    /**
+     * Identifies change in the tooltip text for the approve (yes, ok)
+     * button.
+     */
+    public static final String APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY = "ApproveButtonToolTipTextChangedProperty";
+
+    /** Identifies change in the mnemonic for the approve (yes, ok) button. */
+    public static final String APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY = "ApproveButtonMnemonicChangedProperty";
+
+    /** Instruction to display the control buttons. */
+    public static final String CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY = "ControlButtonsAreShownChangedProperty";
+
+    /** Identifies user's directory change. */
+    public static final String DIRECTORY_CHANGED_PROPERTY = "directoryChanged";
+
+    /** Identifies change in user's single-file selection. */
+    public static final String SELECTED_FILE_CHANGED_PROPERTY = "SelectedFileChangedProperty";
+
+    /** Identifies change in user's multiple-file selection. */
+    public static final String SELECTED_FILES_CHANGED_PROPERTY = "SelectedFilesChangedProperty";
+
+    /** Enables multiple-file selections. */
+    public static final String MULTI_SELECTION_ENABLED_CHANGED_PROPERTY = "MultiSelectionEnabledChangedProperty";
+
+    /**
+     * Says that a different object is being used to find available drives
+     * on the system.
+     */
+    public static final String FILE_SYSTEM_VIEW_CHANGED_PROPERTY = "FileSystemViewChanged";
+
+    /**
+     * Says that a different object is being used to retrieve file
+     * information.
+     */
+    public static final String FILE_VIEW_CHANGED_PROPERTY = "fileViewChanged";
+
+    /** Identifies a change in the display-hidden-files property. */
+    public static final String FILE_HIDING_CHANGED_PROPERTY = "FileHidingChanged";
+
+    /** User changed the kind of files to display. */
+    public static final String FILE_FILTER_CHANGED_PROPERTY = "fileFilterChanged";
+
+    /**
+     * Identifies a change in the kind of selection (single,
+     * multiple, etc.).
+     */
+    public static final String FILE_SELECTION_MODE_CHANGED_PROPERTY = "fileSelectionChanged";
+
+    /**
+     * Says that a different accessory component is in use
+     * (for example, to preview files).
+     */
+    public static final String ACCESSORY_CHANGED_PROPERTY = "AccessoryChangedProperty";
+
+    /**
+     * Identifies whether a the AcceptAllFileFilter is used or not.
+     */
+    public static final String ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY = "acceptAllFileFilterUsedChanged";
+
+    /** Identifies a change in the dialog title. */
+    public static final String DIALOG_TITLE_CHANGED_PROPERTY = "DialogTitleChangedProperty";
+
+    /**
+     * Identifies a change in the type of files displayed (files only,
+     * directories only, or both files and directories).
+     */
+    public static final String DIALOG_TYPE_CHANGED_PROPERTY = "DialogTypeChangedProperty";
+
+    /**
+     * Identifies a change in the list of predefined file filters
+     * the user can choose from.
+     */
+    public static final String CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY = "ChoosableFileFilterChangedProperty";
+
+    // ******************************
+    // ***** instance variables *****
+    // ******************************
+
+    private String dialogTitle = null;
+    private String approveButtonText = null;
+    private String approveButtonToolTipText = null;
+    private int approveButtonMnemonic = 0;
+
+    private Vector filters = new Vector(5);
+    private JDialog dialog = null;
+    private int dialogType = OPEN_DIALOG;
+    private int returnValue = ERROR_OPTION;
+    private JComponent accessory = null;
+
+    private FileView fileView = null;
+
+    // uiFileView is not serialized, as it is initialized
+    // by updateUI() after deserialization
+    private transient FileView uiFileView = null;
+
+    private boolean controlsShown = true;
+
+    private boolean useFileHiding = true;
+    private static final String SHOW_HIDDEN_PROP = "awt.file.showHiddenFiles";
+
+    // Listens to changes in the native setting for showing hidden files.
+    // The Listener is removed and the native setting is ignored if
+    // setFileHidingEnabled() is ever called.
+    private transient PropertyChangeListener showFilesListener = null;
+
+    private int fileSelectionMode = FILES_ONLY;
+
+    private boolean multiSelectionEnabled = false;
+
+    private boolean useAcceptAllFileFilter = true;
+
+    private boolean dragEnabled = false;
+
+    private FileFilter fileFilter = null;
+
+    private FileSystemView fileSystemView = null;
+
+    private File currentDirectory = null;
+    private File selectedFile = null;
+    private File[] selectedFiles;
+
+    // *************************************
+    // ***** JFileChooser Constructors *****
+    // *************************************
+
+    /**
+     * Constructs a <code>JFileChooser</code> pointing to the user's
+     * default directory. This default depends on the operating system.
+     * It is typically the "My Documents" folder on Windows, and the
+     * user's home directory on Unix.
+     */
+    public JFileChooser() {
+        this((File) null, (FileSystemView) null);
+    }
+
+    /**
+     * Constructs a <code>JFileChooser</code> using the given path.
+     * Passing in a <code>null</code>
+     * string causes the file chooser to point to the user's default directory.
+     * This default depends on the operating system. It is
+     * typically the "My Documents" folder on Windows, and the user's
+     * home directory on Unix.
+     *
+     * @param currentDirectoryPath  a <code>String</code> giving the path
+     *                          to a file or directory
+     */
+    public JFileChooser(String currentDirectoryPath) {
+        this(currentDirectoryPath, (FileSystemView) null);
+    }
+
+    /**
+     * Constructs a <code>JFileChooser</code> using the given <code>File</code>
+     * as the path. Passing in a <code>null</code> file
+     * causes the file chooser to point to the user's default directory.
+     * This default depends on the operating system. It is
+     * typically the "My Documents" folder on Windows, and the user's
+     * home directory on Unix.
+     *
+     * @param currentDirectory  a <code>File</code> object specifying
+     *                          the path to a file or directory
+     */
+    public JFileChooser(File currentDirectory) {
+        this(currentDirectory, (FileSystemView) null);
+    }
+
+    /**
+     * Constructs a <code>JFileChooser</code> using the given
+     * <code>FileSystemView</code>.
+     */
+    public JFileChooser(FileSystemView fsv) {
+        this((File) null, fsv);
+    }
+
+
+    /**
+     * Constructs a <code>JFileChooser</code> using the given current directory
+     * and <code>FileSystemView</code>.
+     */
+    public JFileChooser(File currentDirectory, FileSystemView fsv) {
+        setup(fsv);
+        setCurrentDirectory(currentDirectory);
+    }
+
+    /**
+     * Constructs a <code>JFileChooser</code> using the given current directory
+     * path and <code>FileSystemView</code>.
+     */
+    public JFileChooser(String currentDirectoryPath, FileSystemView fsv) {
+        setup(fsv);
+        if(currentDirectoryPath == null) {
+            setCurrentDirectory(null);
+        } else {
+            setCurrentDirectory(fileSystemView.createFileObject(currentDirectoryPath));
+        }
+    }
+
+    /**
+     * Performs common constructor initialization and setup.
+     */
+    protected void setup(FileSystemView view) {
+        installShowFilesListener();
+
+        if(view == null) {
+            view = FileSystemView.getFileSystemView();
+        }
+        setFileSystemView(view);
+        updateUI();
+        if(isAcceptAllFileFilterUsed()) {
+            setFileFilter(getAcceptAllFileFilter());
+        }
+        enableEvents(AWTEvent.MOUSE_EVENT_MASK);
+    }
+
+    private void installShowFilesListener() {
+        // Track native setting for showing hidden files
+        Toolkit tk = Toolkit.getDefaultToolkit();
+        Object showHiddenProperty = tk.getDesktopProperty(SHOW_HIDDEN_PROP);
+        if (showHiddenProperty instanceof Boolean) {
+            useFileHiding = !((Boolean)showHiddenProperty).booleanValue();
+            showFilesListener = new WeakPCL(this);
+            tk.addPropertyChangeListener(SHOW_HIDDEN_PROP, showFilesListener);
+        }
+    }
+
+    /**
+     * Sets the <code>dragEnabled</code> property,
+     * which must be <code>true</code> to enable
+     * automatic drag handling (the first part of drag and drop)
+     * on this component.
+     * The <code>transferHandler</code> property needs to be set
+     * to a non-<code>null</code> value for the drag to do
+     * anything.  The default value of the <code>dragEnabled</code>
+     * property
+     * is <code>false</code>.
+     *
+     * <p>
+     *
+     * When automatic drag handling is enabled,
+     * most look and feels begin a drag-and-drop operation
+     * whenever the user presses the mouse button over an item
+     * and then moves the mouse a few pixels.
+     * Setting this property to <code>true</code>
+     * can therefore have a subtle effect on
+     * how selections behave.
+     *
+     * <p>
+     *
+     * Some look and feels might not support automatic drag and drop;
+     * they will ignore this property.  You can work around such
+     * look and feels by modifying the component
+     * to directly call the <code>exportAsDrag</code> method of a
+     * <code>TransferHandler</code>.
+     *
+     * @param b the value to set the <code>dragEnabled</code> property to
+     * @exception HeadlessException if
+     *            <code>b</code> is <code>true</code> and
+     *            <code>GraphicsEnvironment.isHeadless()</code>
+     *            returns <code>true</code>
+     * @see java.awt.GraphicsEnvironment#isHeadless
+     * @see #getDragEnabled
+     * @see #setTransferHandler
+     * @see TransferHandler
+     * @since 1.4
+     *
+     * @beaninfo
+     *  description: determines whether automatic drag handling is enabled
+     *        bound: false
+     */
+    public void setDragEnabled(boolean b) {
+        if (b && GraphicsEnvironment.isHeadless()) {
+            throw new HeadlessException();
+        }
+        dragEnabled = b;
+    }
+
+    /**
+     * Gets the value of the <code>dragEnabled</code> property.
+     *
+     * @return  the value of the <code>dragEnabled</code> property
+     * @see #setDragEnabled
+     * @since 1.4
+     */
+    public boolean getDragEnabled() {
+        return dragEnabled;
+    }
+
+    // *****************************
+    // ****** File Operations ******
+    // *****************************
+
+    /**
+     * Returns the selected file. This can be set either by the
+     * programmer via <code>setSelectedFile</code> or by a user action, such as
+     * either typing the filename into the UI or selecting the
+     * file from a list in the UI.
+     *
+     * @see #setSelectedFile
+     * @return the selected file
+     */
+    public File getSelectedFile() {
+        return selectedFile;
+    }
+
+    /**
+     * Sets the selected file. If the file's parent directory is
+     * not the current directory, changes the current directory
+     * to be the file's parent directory.
+     *
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     *
+     * @see #getSelectedFile
+     *
+     * @param file the selected file
+     */
+    public void setSelectedFile(File file) {
+        File oldValue = selectedFile;
+        selectedFile = file;
+        if(selectedFile != null) {
+            if (file.isAbsolute() && !getFileSystemView().isParent(getCurrentDirectory(), selectedFile)) {
+                setCurrentDirectory(selectedFile.getParentFile());
+            }
+            if (!isMultiSelectionEnabled() || selectedFiles == null || selectedFiles.length == 1) {
+                ensureFileIsVisible(selectedFile);
+            }
+        }
+        firePropertyChange(SELECTED_FILE_CHANGED_PROPERTY, oldValue, selectedFile);
+    }
+
+    /**
+     * Returns a list of selected files if the file chooser is
+     * set to allow multiple selection.
+     */
+    public File[] getSelectedFiles() {
+        if(selectedFiles == null) {
+            return new File[0];
+        } else {
+            return (File[]) selectedFiles.clone();
+        }
+    }
+
+    /**
+     * Sets the list of selected files if the file chooser is
+     * set to allow multiple selection.
+     *
+     * @beaninfo
+     *       bound: true
+     * description: The list of selected files if the chooser is in multiple selection mode.
+     */
+    public void setSelectedFiles(File[] selectedFiles) {
+        File[] oldValue = this.selectedFiles;
+        if (selectedFiles == null || selectedFiles.length == 0) {
+            selectedFiles = null;
+            this.selectedFiles = null;
+            setSelectedFile(null);
+        } else {
+            this.selectedFiles = selectedFiles.clone();
+            setSelectedFile(this.selectedFiles[0]);
+        }
+        firePropertyChange(SELECTED_FILES_CHANGED_PROPERTY, oldValue, selectedFiles);
+    }
+
+    /**
+     * Returns the current directory.
+     *
+     * @return the current directory
+     * @see #setCurrentDirectory
+     */
+    public File getCurrentDirectory() {
+        return currentDirectory;
+    }
+
+    /**
+     * Sets the current directory. Passing in <code>null</code> sets the
+     * file chooser to point to the user's default directory.
+     * This default depends on the operating system. It is
+     * typically the "My Documents" folder on Windows, and the user's
+     * home directory on Unix.
+     *
+     * If the file passed in as <code>currentDirectory</code> is not a
+     * directory, the parent of the file will be used as the currentDirectory.
+     * If the parent is not traversable, then it will walk up the parent tree
+     * until it finds a traversable directory, or hits the root of the
+     * file system.
+     *
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     * description: The directory that the JFileChooser is showing files of.
+     *
+     * @param dir the current directory to point to
+     * @see #getCurrentDirectory
+     */
+    public void setCurrentDirectory(File dir) {
+        File oldValue = currentDirectory;
+
+        if (dir != null && !dir.exists()) {
+            dir = currentDirectory;
+        }
+        if (dir == null) {
+            dir = getFileSystemView().getDefaultDirectory();
+        }
+        if (currentDirectory != null) {
+            /* Verify the toString of object */
+            if (this.currentDirectory.equals(dir)) {
+                return;
+            }
+        }
+
+        File prev = null;
+        while (!isTraversable(dir) && prev != dir) {
+            prev = dir;
+            dir = getFileSystemView().getParentDirectory(dir);
+        }
+        currentDirectory = dir;
+
+        firePropertyChange(DIRECTORY_CHANGED_PROPERTY, oldValue, currentDirectory);
+    }
+
+    /**
+     * Changes the directory to be set to the parent of the
+     * current directory.
+     *
+     * @see #getCurrentDirectory
+     */
+    public void changeToParentDirectory() {
+        selectedFile = null;
+        File oldValue = getCurrentDirectory();
+        setCurrentDirectory(getFileSystemView().getParentDirectory(oldValue));
+    }
+
+    /**
+     * Tells the UI to rescan its files list from the current directory.
+     */
+    public void rescanCurrentDirectory() {
+        getUI().rescanCurrentDirectory(this);
+    }
+
+    /**
+     * Makes sure that the specified file is viewable, and
+     * not hidden.
+     *
+     * @param f  a File object
+     */
+    public void ensureFileIsVisible(File f) {
+        getUI().ensureFileIsVisible(this, f);
+    }
+
+    // **************************************
+    // ***** JFileChooser Dialog methods *****
+    // **************************************
+
+    /**
+     * Pops up an "Open File" file chooser dialog. Note that the
+     * text that appears in the approve button is determined by
+     * the L&F.
+     *
+     * @param    parent  the parent component of the dialog,
+     *                  can be <code>null</code>;
+     *                  see <code>showDialog</code> for details
+     * @return   the return state of the file chooser on popdown:
+     * <ul>
+     * <li>JFileChooser.CANCEL_OPTION
+     * <li>JFileChooser.APPROVE_OPTION
+     * <li>JFileChooser.ERROR_OPTION if an error occurs or the
+     *                  dialog is dismissed
+     * </ul>
+     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
+     * returns true.
+     * @see java.awt.GraphicsEnvironment#isHeadless
+     * @see #showDialog
+     */
+    public int showOpenDialog(Component parent) throws HeadlessException {
+        setDialogType(OPEN_DIALOG);
+        return showDialog(parent, null);
+    }
+
+    /**
+     * Pops up a "Save File" file chooser dialog. Note that the
+     * text that appears in the approve button is determined by
+     * the L&F.
+     *
+     * @param    parent  the parent component of the dialog,
+     *                  can be <code>null</code>;
+     *                  see <code>showDialog</code> for details
+     * @return   the return state of the file chooser on popdown:
+     * <ul>
+     * <li>JFileChooser.CANCEL_OPTION
+     * <li>JFileChooser.APPROVE_OPTION
+     * <li>JFileChooser.ERROR_OPTION if an error occurs or the
+     *                  dialog is dismissed
+     * </ul>
+     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
+     * returns true.
+     * @see java.awt.GraphicsEnvironment#isHeadless
+     * @see #showDialog
+     */
+    public int showSaveDialog(Component parent) throws HeadlessException {
+        setDialogType(SAVE_DIALOG);
+        return showDialog(parent, null);
+    }
+
+    /**
+     * Pops a custom file chooser dialog with a custom approve button.
+     * For example, the following code
+     * pops up a file chooser with a "Run Application" button
+     * (instead of the normal "Save" or "Open" button):
+     * <pre>
+     * filechooser.showDialog(parentFrame, "Run Application");
+     * </pre>
+     *
+     * Alternatively, the following code does the same thing:
+     * <pre>
+     *    JFileChooser chooser = new JFileChooser(null);
+     *    chooser.setApproveButtonText("Run Application");
+     *    chooser.showDialog(parentFrame, null);
+     * </pre>
+     *
+     * <!--PENDING(jeff) - the following method should be added to the api:
+     *      showDialog(Component parent);-->
+     * <!--PENDING(kwalrath) - should specify modality and what
+     *      "depends" means.-->
+     *
+     * <p>
+     *
+     * The <code>parent</code> argument determines two things:
+     * the frame on which the open dialog depends and
+     * the component whose position the look and feel
+     * should consider when placing the dialog.  If the parent
+     * is a <code>Frame</code> object (such as a <code>JFrame</code>)
+     * then the dialog depends on the frame and
+     * the look and feel positions the dialog
+     * relative to the frame (for example, centered over the frame).
+     * If the parent is a component, then the dialog
+     * depends on the frame containing the component,
+     * and is positioned relative to the component
+     * (for example, centered over the component).
+     * If the parent is <code>null</code>, then the dialog depends on
+     * no visible window, and it's placed in a
+     * look-and-feel-dependent position
+     * such as the center of the screen.
+     *
+     * @param   parent  the parent component of the dialog;
+     *                  can be <code>null</code>
+     * @param   approveButtonText the text of the <code>ApproveButton</code>
+     * @return  the return state of the file chooser on popdown:
+     * <ul>
+     * <li>JFileChooser.CANCEL_OPTION
+     * <li>JFileChooser.APPROVE_OPTION
+     * <li>JFileCHooser.ERROR_OPTION if an error occurs or the
+     *                  dialog is dismissed
+     * </ul>
+     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
+     * returns true.
+     * @see java.awt.GraphicsEnvironment#isHeadless
+     */
+    public int showDialog(Component parent, String approveButtonText)
+        throws HeadlessException {
+        if(approveButtonText != null) {
+            setApproveButtonText(approveButtonText);
+            setDialogType(CUSTOM_DIALOG);
+        }
+        dialog = createDialog(parent);
+        dialog.addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent e) {
+                returnValue = CANCEL_OPTION;
+            }
+        });
+        returnValue = ERROR_OPTION;
+        rescanCurrentDirectory();
+
+        dialog.show();
+        firePropertyChange("JFileChooserDialogIsClosingProperty", dialog, null);
+        dialog.dispose();
+        dialog = null;
+        return returnValue;
+    }
+
+    /**
+     * Creates and returns a new <code>JDialog</code> wrapping
+     * <code>this</code> centered on the <code>parent</code>
+     * in the <code>parent</code>'s frame.
+     * This method can be overriden to further manipulate the dialog,
+     * to disable resizing, set the location, etc. Example:
+     * <pre>
+     *     class MyFileChooser extends JFileChooser {
+     *         protected JDialog createDialog(Component parent) throws HeadlessException {
+     *             JDialog dialog = super.createDialog(parent);
+     *             dialog.setLocation(300, 200);
+     *             dialog.setResizable(false);
+     *             return dialog;
+     *         }
+     *     }
+     * </pre>
+     *
+     * @param   parent  the parent component of the dialog;
+     *                  can be <code>null</code>
+     * @return a new <code>JDialog</code> containing this instance
+     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
+     * returns true.
+     * @see java.awt.GraphicsEnvironment#isHeadless
+     * @since 1.4
+     */
+    protected JDialog createDialog(Component parent) throws HeadlessException {
+        String title = getUI().getDialogTitle(this);
+        putClientProperty(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY,
+                          title);
+
+        JDialog dialog;
+        Window window = JOptionPane.getWindowForComponent(parent);
+        if (window instanceof Frame) {
+            dialog = new JDialog((Frame)window, title, true);
+        } else {
+            dialog = new JDialog((Dialog)window, title, true);
+        }
+        dialog.setComponentOrientation(this.getComponentOrientation());
+
+        Container contentPane = dialog.getContentPane();
+        contentPane.setLayout(new BorderLayout());
+        contentPane.add(this, BorderLayout.CENTER);
+
+        if (JDialog.isDefaultLookAndFeelDecorated()) {
+            boolean supportsWindowDecorations =
+            UIManager.getLookAndFeel().getSupportsWindowDecorations();
+            if (supportsWindowDecorations) {
+                dialog.getRootPane().setWindowDecorationStyle(JRootPane.FILE_CHOOSER_DIALOG);
+            }
+        }
+        dialog.pack();
+        dialog.setLocationRelativeTo(parent);
+
+        return dialog;
+    }
+
+    // **************************
+    // ***** Dialog Options *****
+    // **************************
+
+    /**
+     * Returns the value of the <code>controlButtonsAreShown</code>
+     * property.
+     *
+     * @return   the value of the <code>controlButtonsAreShown</code>
+     *     property
+     *
+     * @see #setControlButtonsAreShown
+     * @since 1.3
+     */
+    public boolean getControlButtonsAreShown() {
+        return controlsShown;
+    }
+
+
+    /**
+     * Sets the property
+     * that indicates whether the <i>approve</i> and <i>cancel</i>
+     * buttons are shown in the file chooser.  This property
+     * is <code>true</code> by default.  Look and feels
+     * that always show these buttons will ignore the value
+     * of this property.
+     * This method fires a property-changed event,
+     * using the string value of
+     * <code>CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY</code>
+     * as the name of the property.
+     *
+     * @param b <code>false</code> if control buttons should not be
+     *    shown; otherwise, <code>true</code>
+     *
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     * description: Sets whether the approve & cancel buttons are shown.
+     *
+     * @see #getControlButtonsAreShown
+     * @see #CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY
+     * @since 1.3
+     */
+    public void setControlButtonsAreShown(boolean b) {
+        if(controlsShown == b) {
+            return;
+        }
+        boolean oldValue = controlsShown;
+        controlsShown = b;
+        firePropertyChange(CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY, oldValue, controlsShown);
+    }
+
+    /**
+     * Returns the type of this dialog.  The default is
+     * <code>JFileChooser.OPEN_DIALOG</code>.
+     *
+     * @return   the type of dialog to be displayed:
+     * <ul>
+     * <li>JFileChooser.OPEN_DIALOG
+     * <li>JFileChooser.SAVE_DIALOG
+     * <li>JFileChooser.CUSTOM_DIALOG
+     * </ul>
+     *
+     * @see #setDialogType
+     */
+    public int getDialogType() {
+        return dialogType;
+    }
+
+    /**
+     * Sets the type of this dialog. Use <code>OPEN_DIALOG</code> when you
+     * want to bring up a file chooser that the user can use to open a file.
+     * Likewise, use <code>SAVE_DIALOG</code> for letting the user choose
+     * a file for saving.
+     * Use <code>CUSTOM_DIALOG</code> when you want to use the file
+     * chooser in a context other than "Open" or "Save".
+     * For instance, you might want to bring up a file chooser that allows
+     * the user to choose a file to execute. Note that you normally would not
+     * need to set the <code>JFileChooser</code> to use
+     * <code>CUSTOM_DIALOG</code>
+     * since a call to <code>setApproveButtonText</code> does this for you.
+     * The default dialog type is <code>JFileChooser.OPEN_DIALOG</code>.
+     *
+     * @param dialogType the type of dialog to be displayed:
+     * <ul>
+     * <li>JFileChooser.OPEN_DIALOG
+     * <li>JFileChooser.SAVE_DIALOG
+     * <li>JFileChooser.CUSTOM_DIALOG
+     * </ul>
+     *
+     * @exception IllegalArgumentException if <code>dialogType</code> is
+     *                          not legal
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     * description: The type (open, save, custom) of the JFileChooser.
+     *        enum:
+     *              OPEN_DIALOG JFileChooser.OPEN_DIALOG
+     *              SAVE_DIALOG JFileChooser.SAVE_DIALOG
+     *              CUSTOM_DIALOG JFileChooser.CUSTOM_DIALOG
+     *
+     * @see #getDialogType
+     * @see #setApproveButtonText
+     */
+    // PENDING(jeff) - fire button text change property
+    public void setDialogType(int dialogType) {
+        if(this.dialogType == dialogType) {
+            return;
+        }
+        if(!(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG || dialogType == CUSTOM_DIALOG)) {
+            throw new IllegalArgumentException("Incorrect Dialog Type: " + dialogType);
+        }
+        int oldValue = this.dialogType;
+        this.dialogType = dialogType;
+        if(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG) {
+            setApproveButtonText(null);
+        }
+        firePropertyChange(DIALOG_TYPE_CHANGED_PROPERTY, oldValue, dialogType);
+    }
+
+    /**
+     * Sets the string that goes in the <code>JFileChooser</code> window's
+     * title bar.
+     *
+     * @param dialogTitle the new <code>String</code> for the title bar
+     *
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     * description: The title of the JFileChooser dialog window.
+     *
+     * @see #getDialogTitle
+     *
+     */
+    public void setDialogTitle(String dialogTitle) {
+        String oldValue = this.dialogTitle;
+        this.dialogTitle = dialogTitle;
+        if(dialog != null) {
+            dialog.setTitle(dialogTitle);
+        }
+        firePropertyChange(DIALOG_TITLE_CHANGED_PROPERTY, oldValue, dialogTitle);
+    }
+
+    /**
+     * Gets the string that goes in the <code>JFileChooser</code>'s titlebar.
+     *
+     * @see #setDialogTitle
+     */
+    public String getDialogTitle() {
+        return dialogTitle;
+    }
+
+    // ************************************
+    // ***** JFileChooser View Options *****
+    // ************************************
+
+
+
+    /**
+     * Sets the tooltip text used in the <code>ApproveButton</code>.
+     * If <code>null</code>, the UI object will determine the button's text.
+     *
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     * description: The tooltip text for the ApproveButton.
+     *
+     * @param toolTipText the tooltip text for the approve button
+     * @see #setApproveButtonText
+     * @see #setDialogType
+     * @see #showDialog
+     */
+    public void setApproveButtonToolTipText(String toolTipText) {
+        if(approveButtonToolTipText == toolTipText) {
+            return;
+        }
+        String oldValue = approveButtonToolTipText;
+        approveButtonToolTipText = toolTipText;
+        firePropertyChange(APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY, oldValue, approveButtonToolTipText);
+    }
+
+
+    /**
+     * Returns the tooltip text used in the <code>ApproveButton</code>.
+     * If <code>null</code>, the UI object will determine the button's text.
+     *
+     * @return the tooltip text used for the approve button
+     *
+     * @see #setApproveButtonText
+     * @see #setDialogType
+     * @see #showDialog
+     */
+    public String getApproveButtonToolTipText() {
+        return approveButtonToolTipText;
+    }
+
+    /**
+     * Returns the approve button's mnemonic.
+     * @return an integer value for the mnemonic key
+     *
+     * @see #setApproveButtonMnemonic
+     */
+    public int getApproveButtonMnemonic() {
+        return approveButtonMnemonic;
+    }
+
+    /**
+     * Sets the approve button's mnemonic using a numeric keycode.
+     *
+     * @param mnemonic  an integer value for the mnemonic key
+     *
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     * description: The mnemonic key accelerator for the ApproveButton.
+     *
+     * @see #getApproveButtonMnemonic
+     */
+    public void setApproveButtonMnemonic(int mnemonic) {
+        if(approveButtonMnemonic == mnemonic) {
+           return;
+        }
+        int oldValue = approveButtonMnemonic;
+        approveButtonMnemonic = mnemonic;
+        firePropertyChange(APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY, oldValue, approveButtonMnemonic);
+    }
+
+    /**
+     * Sets the approve button's mnemonic using a character.
+     * @param mnemonic  a character value for the mnemonic key
+     *
+     * @see #getApproveButtonMnemonic
+     */
+    public void setApproveButtonMnemonic(char mnemonic) {
+        int vk = (int) mnemonic;
+        if(vk >= 'a' && vk <='z') {
+            vk -= ('a' - 'A');
+        }
+        setApproveButtonMnemonic(vk);
+    }
+
+
+    /**
+     * Sets the text used in the <code>ApproveButton</code> in the
+     * <code>FileChooserUI</code>.
+     *
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     * description: The text that goes in the ApproveButton.
+     *
+     * @param approveButtonText the text used in the <code>ApproveButton</code>
+     *
+     * @see #getApproveButtonText
+     * @see #setDialogType
+     * @see #showDialog
+     */
+    // PENDING(jeff) - have ui set this on dialog type change
+    public void setApproveButtonText(String approveButtonText) {
+        if(this.approveButtonText == approveButtonText) {
+            return;
+        }
+        String oldValue = this.approveButtonText;
+        this.approveButtonText = approveButtonText;
+        firePropertyChange(APPROVE_BUTTON_TEXT_CHANGED_PROPERTY, oldValue, approveButtonText);
+    }
+
+    /**
+     * Returns the text used in the <code>ApproveButton</code> in the
+     * <code>FileChooserUI</code>.
+     * If <code>null</code>, the UI object will determine the button's text.
+     *
+     * Typically, this would be "Open" or "Save".
+     *
+     * @return the text used in the <code>ApproveButton</code>
+     *
+     * @see #setApproveButtonText
+     * @see #setDialogType
+     * @see #showDialog
+     */
+    public String getApproveButtonText() {
+        return approveButtonText;
+    }
+
+    /**
+     * Gets the list of user choosable file filters.
+     *
+     * @return a <code>FileFilter</code> array containing all the choosable
+     *         file filters
+     *
+     * @see #addChoosableFileFilter
+     * @see #removeChoosableFileFilter
+     * @see #resetChoosableFileFilters
+     */
+    public FileFilter[] getChoosableFileFilters() {
+        FileFilter[] filterArray = new FileFilter[filters.size()];
+        filters.copyInto(filterArray);
+        return filterArray;
+    }
+
+    /**
+     * Adds a filter to the list of user choosable file filters.
+     * For information on setting the file selection mode, see
+     * {@link #setFileSelectionMode setFileSelectionMode}.
+     *
+     * @param filter the <code>FileFilter</code> to add to the choosable file
+     *               filter list
+     *
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     * description: Adds a filter to the list of user choosable file filters.
+     *
+     * @see #getChoosableFileFilters
+     * @see #removeChoosableFileFilter
+     * @see #resetChoosableFileFilters
+     * @see #setFileSelectionMode
+     */
+    public void addChoosableFileFilter(FileFilter filter) {
+        if(filter != null && !filters.contains(filter)) {
+            FileFilter[] oldValue = getChoosableFileFilters();
+            filters.addElement(filter);
+            firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
+            if (fileFilter == null && filters.size() == 1) {
+                setFileFilter(filter);
+            }
+        }
+    }
+
+    /**
+     * Removes a filter from the list of user choosable file filters. Returns
+     * true if the file filter was removed.
+     *
+     * @see #addChoosableFileFilter
+     * @see #getChoosableFileFilters
+     * @see #resetChoosableFileFilters
+     */
+    public boolean removeChoosableFileFilter(FileFilter f) {
+        if(filters.contains(f)) {
+            if(getFileFilter() == f) {
+                setFileFilter(null);
+            }
+            FileFilter[] oldValue = getChoosableFileFilters();
+            filters.removeElement(f);
+            firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Resets the choosable file filter list to its starting state. Normally,
+     * this removes all added file filters while leaving the
+     * <code>AcceptAll</code> file filter.
+     *
+     * @see #addChoosableFileFilter
+     * @see #getChoosableFileFilters
+     * @see #removeChoosableFileFilter
+     */
+    public void resetChoosableFileFilters() {
+        FileFilter[] oldValue = getChoosableFileFilters();
+        setFileFilter(null);
+        filters.removeAllElements();
+        if(isAcceptAllFileFilterUsed()) {
+           addChoosableFileFilter(getAcceptAllFileFilter());
+        }
+        firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
+    }
+
+    /**
+     * Returns the <code>AcceptAll</code> file filter.
+     * For example, on Microsoft Windows this would be All Files (*.*).
+     */
+    public FileFilter getAcceptAllFileFilter() {
+        FileFilter filter = null;
+        if(getUI() != null) {
+            filter = getUI().getAcceptAllFileFilter(this);
+        }
+        return filter;
+    }
+
+   /**
+    * Returns whether the <code>AcceptAll FileFilter</code> is used.
+    * @return true if the <code>AcceptAll FileFilter</code> is used
+    * @see #setAcceptAllFileFilterUsed
+    * @since 1.3
+    */
+    public boolean isAcceptAllFileFilterUsed() {
+        return useAcceptAllFileFilter;
+    }
+
+   /**
+    * Determines whether the <code>AcceptAll FileFilter</code> is used
+    * as an available choice in the choosable filter list.
+    * If false, the <code>AcceptAll</code> file filter is removed from
+    * the list of available file filters.
+    * If true, the <code>AcceptAll</code> file filter will become the
+    * the actively used file filter.
+    *
+    * @beaninfo
+    *   preferred: true
+    *       bound: true
+    * description: Sets whether the AcceptAll FileFilter is used as an available choice in the choosable filter list.
+    *
+    * @see #isAcceptAllFileFilterUsed
+    * @see #getAcceptAllFileFilter
+    * @see #setFileFilter
+    * @since 1.3
+    */
+    public void setAcceptAllFileFilterUsed(boolean b) {
+        boolean oldValue = useAcceptAllFileFilter;
+        useAcceptAllFileFilter = b;
+        if(!b) {
+            removeChoosableFileFilter(getAcceptAllFileFilter());
+        } else {
+            removeChoosableFileFilter(getAcceptAllFileFilter());
+            addChoosableFileFilter(getAcceptAllFileFilter());
+        }
+        firePropertyChange(ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY, oldValue, useAcceptAllFileFilter);
+    }
+
+    /**
+     * Returns the accessory component.
+     *
+     * @return this JFileChooser's accessory component, or null
+     * @see #setAccessory
+     */
+    public JComponent getAccessory() {
+        return accessory;
+    }
+
+    /**
+     * Sets the accessory component. An accessory is often used to show a
+     * preview image of the selected file; however, it can be used for anything
+     * that the programmer wishes, such as extra custom file chooser controls.
+     *
+     * <p>
+     * Note: if there was a previous accessory, you should unregister
+     * any listeners that the accessory might have registered with the
+     * file chooser.
+     *
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     * description: Sets the accessory component on the JFileChooser.
+     */
+    public void setAccessory(JComponent newAccessory) {
+        JComponent oldValue = accessory;
+        accessory = newAccessory;
+        firePropertyChange(ACCESSORY_CHANGED_PROPERTY, oldValue, accessory);
+    }
+
+    /**
+     * Sets the <code>JFileChooser</code> to allow the user to just
+     * select files, just select
+     * directories, or select both files and directories.  The default is
+     * <code>JFilesChooser.FILES_ONLY</code>.
+     *
+     * @param mode the type of files to be displayed:
+     * <ul>
+     * <li>JFileChooser.FILES_ONLY
+     * <li>JFileChooser.DIRECTORIES_ONLY
+     * <li>JFileChooser.FILES_AND_DIRECTORIES
+     * </ul>
+     *
+     * @exception IllegalArgumentException  if <code>mode</code> is an
+     *                          illegal file selection mode
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     * description: Sets the types of files that the JFileChooser can choose.
+     *        enum: FILES_ONLY JFileChooser.FILES_ONLY
+     *              DIRECTORIES_ONLY JFileChooser.DIRECTORIES_ONLY
+     *              FILES_AND_DIRECTORIES JFileChooser.FILES_AND_DIRECTORIES
+     *
+     *
+     * @see #getFileSelectionMode
+     */
+    public void setFileSelectionMode(int mode) {
+        if(fileSelectionMode == mode) {
+            return;
+        }
+
+        if ((mode == FILES_ONLY) || (mode == DIRECTORIES_ONLY) || (mode == FILES_AND_DIRECTORIES)) {
+           int oldValue = fileSelectionMode;
+           fileSelectionMode = mode;
+           firePropertyChange(FILE_SELECTION_MODE_CHANGED_PROPERTY, oldValue, fileSelectionMode);
+        } else {
+           throw new IllegalArgumentException("Incorrect Mode for file selection: " + mode);
+        }
+    }
+
+    /**
+     * Returns the current file-selection mode.  The default is
+     * <code>JFilesChooser.FILES_ONLY</code>.
+     *
+     * @return the type of files to be displayed, one of the following:
+     * <ul>
+     * <li>JFileChooser.FILES_ONLY
+     * <li>JFileChooser.DIRECTORIES_ONLY
+     * <li>JFileChooser.FILES_AND_DIRECTORIES
+     * </ul>
+     * @see #setFileSelectionMode
+     */
+    public int getFileSelectionMode() {
+        return fileSelectionMode;
+    }
+
+    /**
+     * Convenience call that determines if files are selectable based on the
+     * current file selection mode.
+     *
+     * @see #setFileSelectionMode
+     * @see #getFileSelectionMode
+     */
+    public boolean isFileSelectionEnabled() {
+        return ((fileSelectionMode == FILES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES));
+    }
+
+    /**
+     * Convenience call that determines if directories are selectable based
+     * on the current file selection mode.
+     *
+     * @see #setFileSelectionMode
+     * @see #getFileSelectionMode
+     */
+    public boolean isDirectorySelectionEnabled() {
+        return ((fileSelectionMode == DIRECTORIES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES));
+    }
+
+    /**
+     * Sets the file chooser to allow multiple file selections.
+     *
+     * @param b true if multiple files may be selected
+     * @beaninfo
+     *       bound: true
+     * description: Sets multiple file selection mode.
+     *
+     * @see #isMultiSelectionEnabled
+     */
+    public void setMultiSelectionEnabled(boolean b) {
+        if(multiSelectionEnabled == b) {
+            return;
+        }
+        boolean oldValue = multiSelectionEnabled;
+        multiSelectionEnabled = b;
+        firePropertyChange(MULTI_SELECTION_ENABLED_CHANGED_PROPERTY, oldValue, multiSelectionEnabled);
+    }
+
+    /**
+     * Returns true if multiple files can be selected.
+     * @return true if multiple files can be selected
+     * @see #setMultiSelectionEnabled
+     */
+    public boolean isMultiSelectionEnabled() {
+        return multiSelectionEnabled;
+    }
+
+
+    /**
+     * Returns true if hidden files are not shown in the file chooser;
+     * otherwise, returns false.
+     *
+     * @return the status of the file hiding property
+     * @see #setFileHidingEnabled
+     */
+    public boolean isFileHidingEnabled() {
+        return useFileHiding;
+    }
+
+    /**
+     * Sets file hiding on or off. If true, hidden files are not shown
+     * in the file chooser. The job of determining which files are
+     * shown is done by the <code>FileView</code>.
+     *
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     * description: Sets file hiding on or off.
+     *
+     * @param b the boolean value that determines whether file hiding is
+     *          turned on
+     * @see #isFileHidingEnabled
+     */
+    public void setFileHidingEnabled(boolean b) {
+        // Dump showFilesListener since we'll ignore it from now on
+        if (showFilesListener != null) {
+            Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, showFilesListener);
+            showFilesListener = null;
+        }
+        boolean oldValue = useFileHiding;
+        useFileHiding = b;
+        firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, useFileHiding);
+    }
+
+    /**
+     * Sets the current file filter. The file filter is used by the
+     * file chooser to filter out files from the user's view.
+     *
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     * description: Sets the File Filter used to filter out files of type.
+     *
+     * @param filter the new current file filter to use
+     * @see #getFileFilter
+     */
+    public void setFileFilter(FileFilter filter) {
+        FileFilter oldValue = fileFilter;
+        fileFilter = filter;
+        if (filter != null) {
+            if (isMultiSelectionEnabled() && selectedFiles != null && selectedFiles.length > 0) {
+                Vector fList = new Vector();
+                boolean failed = false;
+                for (int i = 0; i < selectedFiles.length; i++) {
+                    if (filter.accept(selectedFiles[i])) {
+                        fList.add(selectedFiles[i]);
+                    } else {
+                        failed = true;
+                    }
+                }
+                if (failed) {
+                    setSelectedFiles((fList.size() == 0) ? null : (File[])fList.toArray(new File[fList.size()]));
+                }
+            } else if (selectedFile != null && !filter.accept(selectedFile)) {
+                setSelectedFile(null);
+            }
+        }
+        firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, oldValue, fileFilter);
+    }
+
+
+    /**
+     * Returns the currently selected file filter.
+     *
+     * @return the current file filter
+     * @see #setFileFilter
+     * @see #addChoosableFileFilter
+     */
+    public FileFilter getFileFilter() {
+        return fileFilter;
+    }
+
+    /**
+     * Sets the file view to used to retrieve UI information, such as
+     * the icon that represents a file or the type description of a file.
+     *
+     * @beaninfo
+     *   preferred: true
+     *       bound: true
+     * description: Sets the File View used to get file type information.
+     *
+     * @see #getFileView
+     */
+    public void setFileView(FileView fileView) {
+        FileView oldValue = this.fileView;
+        this.fileView = fileView;
+        firePropertyChange(FILE_VIEW_CHANGED_PROPERTY, oldValue, fileView);
+    }
+
+    /**
+     * Returns the current file view.
+     *
+     * @see #setFileView
+     */
+    public FileView getFileView() {
+        return fileView;
+    }
+
+    // ******************************
+    // *****FileView delegation *****
+    // ******************************
+
+    // NOTE: all of the following methods attempt to delegate
+    // first to the client set fileView, and if <code>null</code> is returned
+    // (or there is now client defined fileView) then calls the
+    // UI's default fileView.
+
+    /**
+     * Returns the filename.
+     * @param f the <code>File</code>
+     * @return the <code>String</code> containing the filename for
+     *          <code>f</code>
+     * @see FileView#getName
+     */
+    public String getName(File f) {
+        String filename = null;
+        if(f != null) {
+            if(getFileView() != null) {
+                filename = getFileView().getName(f);
+            }
+            if(filename == null && uiFileView != null) {
+                filename = uiFileView.getName(f);
+            }
+        }
+        return filename;
+    }
+
+    /**
+     * Returns the file description.
+     * @param f the <code>File</code>
+     * @return the <code>String</code> containing the file description for
+     *          <code>f</code>
+     * @see FileView#getDescription
+     */
+    public String getDescription(File f) {
+        String description = null;
+        if(f != null) {
+            if(getFileView() != null) {
+                description = getFileView().getDescription(f);
+            }
+            if(description == null && uiFileView != null) {
+                description = uiFileView.getDescription(f);
+            }
+        }
+        return description;
+    }
+
+    /**
+     * Returns the file type.
+     * @param f the <code>File</code>
+     * @return the <code>String</code> containing the file type description for
+     *          <code>f</code>
+     * @see FileView#getTypeDescription
+     */
+    public String getTypeDescription(File f) {
+        String typeDescription = null;
+        if(f != null) {
+            if(getFileView() != null) {
+                typeDescription = getFileView().getTypeDescription(f);
+            }
+            if(typeDescription == null && uiFileView != null) {
+                typeDescription = uiFileView.getTypeDescription(f);
+            }
+        }
+        return typeDescription;
+    }
+
+    /**
+     * Returns the icon for this file or type of file, depending
+     * on the system.
+     * @param f the <code>File</code>
+     * @return the <code>Icon</code> for this file, or type of file
+     * @see FileView#getIcon
+     */
+    public Icon getIcon(File f) {
+        Icon icon = null;
+        if (f != null) {
+            if(getFileView() != null) {
+                icon = getFileView().getIcon(f);
+            }
+            if(icon == null && uiFileView != null) {
+                icon = uiFileView.getIcon(f);
+            }
+        }
+        return icon;
+    }
+
+    /**
+     * Returns true if the file (directory) can be visited.
+     * Returns false if the directory cannot be traversed.
+     * @param f the <code>File</code>
+     * @return true if the file/directory can be traversed, otherwise false
+     * @see FileView#isTraversable
+     */
+    public boolean isTraversable(File f) {
+        Boolean traversable = null;
+        if (f != null) {
+            if (getFileView() != null) {
+                traversable = getFileView().isTraversable(f);
+            }
+            if (traversable == null && uiFileView != null) {
+                traversable = uiFileView.isTraversable(f);
+            }
+            if (traversable == null) {
+                traversable = getFileSystemView().isTraversable(f);
+            }
+        }
+        return (traversable != null && traversable.booleanValue());
+    }
+
+    /**
+     * Returns true if the file should be displayed.
+     * @param f the <code>File</code>
+     * @return true if the file should be displayed, otherwise false
+     * @see FileFilter#accept
+     */
+    public boolean accept(File f) {
+        boolean shown = true;
+        if(f != null && fileFilter != null) {
+            shown = fileFilter.accept(f);
+        }
+        return shown;
+    }
+
+    /**
+     * Sets the file system view that the <code>JFileChooser</code> uses for
+     * accessing and creating file system resources, such as finding
+     * the floppy drive and getting a list of root drives.
+     * @param fsv  the new <code>FileSystemView</code>
+     *
+     * @beaninfo
+     *      expert: true
+     *       bound: true
+     * description: Sets the FileSytemView used to get filesystem information.
+     *
+     * @see FileSystemView
+     */
+    public void setFileSystemView(FileSystemView fsv) {
+        FileSystemView oldValue = fileSystemView;
+        fileSystemView = fsv;
+        firePropertyChange(FILE_SYSTEM_VIEW_CHANGED_PROPERTY, oldValue, fileSystemView);
+    }
+
+    /**
+     * Returns the file system view.
+     * @return the <code>FileSystemView</code> object
+     * @see #setFileSystemView
+     */
+    public FileSystemView getFileSystemView() {
+        return fileSystemView;
+    }
+
+    // **************************
+    // ***** Event Handling *****
+    // **************************
+
+    /**
+     * Called by the UI when the user hits the Approve button
+     * (labeled "Open" or "Save", by default). This can also be
+     * called by the programmer.
+     * This method causes an action event to fire
+     * with the command string equal to
+     * <code>APPROVE_SELECTION</code>.
+     *
+     * @see #APPROVE_SELECTION
+     */
+    public void approveSelection() {
+        returnValue = APPROVE_OPTION;
+        if(dialog != null) {
+            dialog.setVisible(false);
+        }
+        fireActionPerformed(APPROVE_SELECTION);
+    }
+
+    /**
+     * Called by the UI when the user chooses the Cancel button.
+     * This can also be called by the programmer.
+     * This method causes an action event to fire
+     * with the command string equal to
+     * <code>CANCEL_SELECTION</code>.
+     *
+     * @see #CANCEL_SELECTION
+     */
+    public void cancelSelection() {
+        returnValue = CANCEL_OPTION;
+        if(dialog != null) {
+            dialog.setVisible(false);
+        }
+        fireActionPerformed(CANCEL_SELECTION);
+    }
+
+    /**
+     * Adds an <code>ActionListener</code> to the file chooser.
+     *
+     * @param l  the listener to be added
+     *
+     * @see #approveSelection
+     * @see #cancelSelection
+     */
+    public void addActionListener(ActionListener l) {
+        listenerList.add(ActionListener.class, l);
+    }
+
+    /**
+     * Removes an <code>ActionListener</code> from the file chooser.
+     *
+     * @param l  the listener to be removed
+     *
+     * @see #addActionListener
+     */
+    public void removeActionListener(ActionListener l) {
+        listenerList.remove(ActionListener.class, l);
+    }
+
+    /**
+     * Returns an array of all the action listeners
+     * registered on this file chooser.
+     *
+     * @return all of this file chooser's <code>ActionListener</code>s
+     *         or an empty
+     *         array if no action listeners are currently registered
+     *
+     * @see #addActionListener
+     * @see #removeActionListener
+     *
+     * @since 1.4
+     */
+    public ActionListener[] getActionListeners() {
+        return (ActionListener[])listenerList.getListeners(
+                ActionListener.class);
+    }
+
+    /**
+     * Notifies all listeners that have registered interest for
+     * notification on this event type. The event instance
+     * is lazily created using the <code>command</code> parameter.
+     *
+     * @see EventListenerList
+     */
+    protected void fireActionPerformed(String command) {
+        // Guaranteed to return a non-null array
+        Object[] listeners = listenerList.getListenerList();
+        long mostRecentEventTime = EventQueue.getMostRecentEventTime();
+        int modifiers = 0;
+        AWTEvent currentEvent = EventQueue.getCurrentEvent();
+        if (currentEvent instanceof InputEvent) {
+            modifiers = ((InputEvent)currentEvent).getModifiers();
+        } else if (currentEvent instanceof ActionEvent) {
+            modifiers = ((ActionEvent)currentEvent).getModifiers();
+        }
+        ActionEvent e = null;
+        // Process the listeners last to first, notifying
+        // those that are interested in this event
+        for (int i = listeners.length-2; i>=0; i-=2) {
+            if (listeners[i]==ActionListener.class) {
+                // Lazily create the event:
+                if (e == null) {
+                    e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
+                                        command, mostRecentEventTime,
+                                        modifiers);
+                }
+                ((ActionListener)listeners[i+1]).actionPerformed(e);
+            }
+        }
+    }
+
+    private static class WeakPCL implements PropertyChangeListener {
+        WeakReference<JFileChooser> jfcRef;
+
+        public WeakPCL(JFileChooser jfc) {
+            jfcRef = new WeakReference(jfc);
+        }
+        public void propertyChange(PropertyChangeEvent ev) {
+            assert ev.getPropertyName().equals(SHOW_HIDDEN_PROP);
+            JFileChooser jfc = jfcRef.get();
+            if (jfc == null) {
+                // Our JFileChooser is no longer around, so we no longer need to
+                // listen for PropertyChangeEvents.
+                Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, this);
+            }
+            else {
+                boolean oldValue = jfc.useFileHiding;
+                jfc.useFileHiding = !((Boolean)ev.getNewValue()).booleanValue();
+                jfc.firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, jfc.useFileHiding);
+            }
+        }
+    }
+
+    // *********************************
+    // ***** Pluggable L&F methods *****
+    // *********************************
+
+    /**
+     * Resets the UI property to a value from the current look and feel.
+     *
+     * @see JComponent#updateUI
+     */
+    public void updateUI() {
+        if (isAcceptAllFileFilterUsed()) {
+            removeChoosableFileFilter(getAcceptAllFileFilter());
+        }
+        FileChooserUI ui = ((FileChooserUI)UIManager.getUI(this));
+        if (fileSystemView == null) {
+            // We were probably deserialized
+            setFileSystemView(FileSystemView.getFileSystemView());
+        }
+        setUI(ui);
+
+        uiFileView = getUI().getFileView(this);
+        if(isAcceptAllFileFilterUsed()) {
+            addChoosableFileFilter(getAcceptAllFileFilter());
+        }
+    }
+
+    /**
+     * Returns a string that specifies the name of the L&F class
+     * that renders this component.
+     *
+     * @return the string "FileChooserUI"
+     * @see JComponent#getUIClassID
+     * @see UIDefaults#getUI
+     * @beaninfo
+     *        expert: true
+     *   description: A string that specifies the name of the L&F class.
+     */
+    public String getUIClassID() {
+        return uiClassID;
+    }
+
+    /**
+     * Gets the UI object which implements the L&F for this component.
+     *
+     * @return the FileChooserUI object that implements the FileChooserUI L&F
+     */
+    public FileChooserUI getUI() {
+        return (FileChooserUI) ui;
+    }
+
+    /**
+     * See <code>readObject</code> and <code>writeObject</code> in
+     * <code>JComponent</code> for more
+     * information about serialization in Swing.
+     */
+    private void readObject(java.io.ObjectInputStream in)
+            throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        installShowFilesListener();
+    }
+
+    /**
+     * See <code>readObject</code> and <code>writeObject</code> in
+     * <code>JComponent</code> for more
+     * information about serialization in Swing.
+     */
+    private void writeObject(ObjectOutputStream s) throws IOException {
+        FileSystemView fsv = null;
+
+        if (isAcceptAllFileFilterUsed()) {
+            //The AcceptAllFileFilter is UI specific, it will be reset by
+            //updateUI() after deserialization
+            removeChoosableFileFilter(getAcceptAllFileFilter());
+        }
+        if (fileSystemView.equals(FileSystemView.getFileSystemView())) {
+            //The default FileSystemView is platform specific, it will be
+            //reset by updateUI() after deserialization
+            fsv = fileSystemView;
+            fileSystemView = null;
+        }
+        s.defaultWriteObject();
+        if (fsv != null) {
+            fileSystemView = fsv;
+        }
+        if (isAcceptAllFileFilterUsed()) {
+            addChoosableFileFilter(getAcceptAllFileFilter());
+        }
+        if (getUIClassID().equals(uiClassID)) {
+            byte count = JComponent.getWriteObjCounter(this);
+            JComponent.setWriteObjCounter(this, --count);
+            if (count == 0 && ui != null) {
+                ui.installUI(this);
+            }
+        }
+    }
+
+
+    /**
+     * Returns a string representation of this <code>JFileChooser</code>.
+     * This method
+     * is intended to be used only for debugging purposes, and the
+     * content and format of the returned string may vary between
+     * implementations. The returned string may be empty but may not
+     * be <code>null</code>.
+     *
+     * @return  a string representation of this <code>JFileChooser</code>
+     */
+    protected String paramString() {
+        String approveButtonTextString = (approveButtonText != null ?
+                                          approveButtonText: "");
+        String dialogTitleString = (dialogTitle != null ?
+                                    dialogTitle: "");
+        String dialogTypeString;
+        if (dialogType == OPEN_DIALOG) {
+            dialogTypeString = "OPEN_DIALOG";
+        } else if (dialogType == SAVE_DIALOG) {
+            dialogTypeString = "SAVE_DIALOG";
+        } else if (dialogType == CUSTOM_DIALOG) {
+            dialogTypeString = "CUSTOM_DIALOG";
+        } else dialogTypeString = "";
+        String returnValueString;
+        if (returnValue == CANCEL_OPTION) {
+            returnValueString = "CANCEL_OPTION";
+        } else if (returnValue == APPROVE_OPTION) {
+            returnValueString = "APPROVE_OPTION";
+        } else if (returnValue == ERROR_OPTION) {
+            returnValueString = "ERROR_OPTION";
+        } else returnValueString = "";
+        String useFileHidingString = (useFileHiding ?
+                                    "true" : "false");
+        String fileSelectionModeString;
+        if (fileSelectionMode == FILES_ONLY) {
+            fileSelectionModeString = "FILES_ONLY";
+        } else if (fileSelectionMode == DIRECTORIES_ONLY) {
+            fileSelectionModeString = "DIRECTORIES_ONLY";
+        } else if (fileSelectionMode == FILES_AND_DIRECTORIES) {
+            fileSelectionModeString = "FILES_AND_DIRECTORIES";
+        } else fileSelectionModeString = "";
+        String currentDirectoryString = (currentDirectory != null ?
+                                         currentDirectory.toString() : "");
+        String selectedFileString = (selectedFile != null ?
+                                     selectedFile.toString() : "");
+
+        return super.paramString() +
+        ",approveButtonText=" + approveButtonTextString +
+        ",currentDirectory=" + currentDirectoryString +
+        ",dialogTitle=" + dialogTitleString +
+        ",dialogType=" + dialogTypeString +
+        ",fileSelectionMode=" + fileSelectionModeString +
+        ",returnValue=" + returnValueString +
+        ",selectedFile=" + selectedFileString +
+        ",useFileHiding=" + useFileHidingString;
+    }
+
+/////////////////
+// Accessibility support
+////////////////
+
+    protected AccessibleContext accessibleContext = null;
+
+    /**
+     * Gets the AccessibleContext associated with this JFileChooser.
+     * For file choosers, the AccessibleContext takes the form of an
+     * AccessibleJFileChooser.
+     * A new AccessibleJFileChooser instance is created if necessary.
+     *
+     * @return an AccessibleJFileChooser that serves as the
+     *         AccessibleContext of this JFileChooser
+     */
+    public AccessibleContext getAccessibleContext() {
+        if (accessibleContext == null) {
+            accessibleContext = new AccessibleJFileChooser();
+        }
+        return accessibleContext;
+    }
+
+    /**
+     * This class implements accessibility support for the
+     * <code>JFileChooser</code> class.  It provides an implementation of the
+     * Java Accessibility API appropriate to file chooser user-interface
+     * elements.
+     */
+    protected class AccessibleJFileChooser extends AccessibleJComponent {
+
+        /**
+         * Gets the role of this object.
+         *
+         * @return an instance of AccessibleRole describing the role of the
+         * object
+         * @see AccessibleRole
+         */
+        public AccessibleRole getAccessibleRole() {
+            return AccessibleRole.FILE_CHOOSER;
+        }
+
+    } // inner class AccessibleJFileChooser
+
+}