1 /*
   2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.swing;
  27 
  28 import javax.swing.event.*;
  29 import javax.swing.filechooser.*;
  30 import javax.swing.plaf.FileChooserUI;
  31 
  32 import javax.accessibility.*;
  33 
  34 import java.io.File;
  35 import java.io.ObjectOutputStream;
  36 import java.io.IOException;
  37 
  38 import java.util.Vector;
  39 import java.awt.AWTEvent;
  40 import java.awt.Component;
  41 import java.awt.Container;
  42 import java.awt.BorderLayout;
  43 import java.awt.Window;
  44 import java.awt.Dialog;
  45 import java.awt.Frame;
  46 import java.awt.GraphicsEnvironment;
  47 import java.awt.HeadlessException;
  48 import java.awt.EventQueue;
  49 import java.awt.Toolkit;
  50 import java.awt.event.*;
  51 import java.beans.PropertyChangeListener;
  52 import java.beans.PropertyChangeEvent;
  53 import java.io.InvalidObjectException;
  54 import java.io.ObjectInputStream;
  55 import java.lang.ref.WeakReference;
  56 
  57 /**
  58  * <code>JFileChooser</code> provides a simple mechanism for the user to
  59  * choose a file.
  60  * For information about using <code>JFileChooser</code>, see
  61  * <a
  62  href="http://docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html">How to Use File Choosers</a>,
  63  * a section in <em>The Java Tutorial</em>.
  64  *
  65  * <p>
  66  *
  67  * The following code pops up a file chooser for the user's home directory that
  68  * sees only .jpg and .gif images:
  69  * <pre>
  70  *    JFileChooser chooser = new JFileChooser();
  71  *    FileNameExtensionFilter filter = new FileNameExtensionFilter(
  72  *        "JPG &amp; GIF Images", "jpg", "gif");
  73  *    chooser.setFileFilter(filter);
  74  *    int returnVal = chooser.showOpenDialog(parent);
  75  *    if(returnVal == JFileChooser.APPROVE_OPTION) {
  76  *       System.out.println("You chose to open this file: " +
  77  *            chooser.getSelectedFile().getName());
  78  *    }
  79  * </pre>
  80  * <p>
  81  * <strong>Warning:</strong> Swing is not thread safe. For more
  82  * information see <a
  83  * href="package-summary.html#threading">Swing's Threading
  84  * Policy</a>.
  85  *
  86  * @beaninfo
  87  *   attribute: isContainer false
  88  * description: A component which allows for the interactive selection of a file.
  89  *
  90  * @author Jeff Dinkins
  91  * @since 1.2
  92  */
  93 @SuppressWarnings("serial") // Superclass is not serializable across versions
  94 public class JFileChooser extends JComponent implements Accessible {
  95 
  96     /**
  97      * @see #getUIClassID
  98      * @see #readObject
  99      */
 100     private static final String uiClassID = "FileChooserUI";
 101 
 102     // ************************
 103     // ***** Dialog Types *****
 104     // ************************
 105 
 106     /**
 107      * Type value indicating that the <code>JFileChooser</code> supports an
 108      * "Open" file operation.
 109      */
 110     public static final int OPEN_DIALOG = 0;
 111 
 112     /**
 113      * Type value indicating that the <code>JFileChooser</code> supports a
 114      * "Save" file operation.
 115      */
 116     public static final int SAVE_DIALOG = 1;
 117 
 118     /**
 119      * Type value indicating that the <code>JFileChooser</code> supports a
 120      * developer-specified file operation.
 121      */
 122     public static final int CUSTOM_DIALOG = 2;
 123 
 124 
 125     // ********************************
 126     // ***** Dialog Return Values *****
 127     // ********************************
 128 
 129     /**
 130      * Return value if cancel is chosen.
 131      */
 132     public static final int CANCEL_OPTION = 1;
 133 
 134     /**
 135      * Return value if approve (yes, ok) is chosen.
 136      */
 137     public static final int APPROVE_OPTION = 0;
 138 
 139     /**
 140      * Return value if an error occurred.
 141      */
 142     public static final int ERROR_OPTION = -1;
 143 
 144 
 145     // **********************************
 146     // ***** JFileChooser properties *****
 147     // **********************************
 148 
 149 
 150     /** Instruction to display only files. */
 151     public static final int FILES_ONLY = 0;
 152 
 153     /** Instruction to display only directories. */
 154     public static final int DIRECTORIES_ONLY = 1;
 155 
 156     /** Instruction to display both files and directories. */
 157     public static final int FILES_AND_DIRECTORIES = 2;
 158 
 159     /** Instruction to cancel the current selection. */
 160     public static final String CANCEL_SELECTION = "CancelSelection";
 161 
 162     /**
 163      * Instruction to approve the current selection
 164      * (same as pressing yes or ok).
 165      */
 166     public static final String APPROVE_SELECTION = "ApproveSelection";
 167 
 168     /** Identifies change in the text on the approve (yes, ok) button. */
 169     public static final String APPROVE_BUTTON_TEXT_CHANGED_PROPERTY = "ApproveButtonTextChangedProperty";
 170 
 171     /**
 172      * Identifies change in the tooltip text for the approve (yes, ok)
 173      * button.
 174      */
 175     public static final String APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY = "ApproveButtonToolTipTextChangedProperty";
 176 
 177     /** Identifies change in the mnemonic for the approve (yes, ok) button. */
 178     public static final String APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY = "ApproveButtonMnemonicChangedProperty";
 179 
 180     /** Instruction to display the control buttons. */
 181     public static final String CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY = "ControlButtonsAreShownChangedProperty";
 182 
 183     /** Identifies user's directory change. */
 184     public static final String DIRECTORY_CHANGED_PROPERTY = "directoryChanged";
 185 
 186     /** Identifies change in user's single-file selection. */
 187     public static final String SELECTED_FILE_CHANGED_PROPERTY = "SelectedFileChangedProperty";
 188 
 189     /** Identifies change in user's multiple-file selection. */
 190     public static final String SELECTED_FILES_CHANGED_PROPERTY = "SelectedFilesChangedProperty";
 191 
 192     /** Enables multiple-file selections. */
 193     public static final String MULTI_SELECTION_ENABLED_CHANGED_PROPERTY = "MultiSelectionEnabledChangedProperty";
 194 
 195     /**
 196      * Says that a different object is being used to find available drives
 197      * on the system.
 198      */
 199     public static final String FILE_SYSTEM_VIEW_CHANGED_PROPERTY = "FileSystemViewChanged";
 200 
 201     /**
 202      * Says that a different object is being used to retrieve file
 203      * information.
 204      */
 205     public static final String FILE_VIEW_CHANGED_PROPERTY = "fileViewChanged";
 206 
 207     /** Identifies a change in the display-hidden-files property. */
 208     public static final String FILE_HIDING_CHANGED_PROPERTY = "FileHidingChanged";
 209 
 210     /** User changed the kind of files to display. */
 211     public static final String FILE_FILTER_CHANGED_PROPERTY = "fileFilterChanged";
 212 
 213     /**
 214      * Identifies a change in the kind of selection (single,
 215      * multiple, etc.).
 216      */
 217     public static final String FILE_SELECTION_MODE_CHANGED_PROPERTY = "fileSelectionChanged";
 218 
 219     /**
 220      * Says that a different accessory component is in use
 221      * (for example, to preview files).
 222      */
 223     public static final String ACCESSORY_CHANGED_PROPERTY = "AccessoryChangedProperty";
 224 
 225     /**
 226      * Identifies whether a the AcceptAllFileFilter is used or not.
 227      */
 228     public static final String ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY = "acceptAllFileFilterUsedChanged";
 229 
 230     /** Identifies a change in the dialog title. */
 231     public static final String DIALOG_TITLE_CHANGED_PROPERTY = "DialogTitleChangedProperty";
 232 
 233     /**
 234      * Identifies a change in the type of files displayed (files only,
 235      * directories only, or both files and directories).
 236      */
 237     public static final String DIALOG_TYPE_CHANGED_PROPERTY = "DialogTypeChangedProperty";
 238 
 239     /**
 240      * Identifies a change in the list of predefined file filters
 241      * the user can choose from.
 242      */
 243     public static final String CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY = "ChoosableFileFilterChangedProperty";
 244 
 245     // ******************************
 246     // ***** instance variables *****
 247     // ******************************
 248 
 249     private String dialogTitle = null;
 250     private String approveButtonText = null;
 251     private String approveButtonToolTipText = null;
 252     private int approveButtonMnemonic = 0;
 253 
 254     private Vector<FileFilter> filters = new Vector<FileFilter>(5);
 255     private JDialog dialog = null;
 256     private int dialogType = OPEN_DIALOG;
 257     private int returnValue = ERROR_OPTION;
 258     private JComponent accessory = null;
 259 
 260     private FileView fileView = null;
 261 
 262     private boolean controlsShown = true;
 263 
 264     private boolean useFileHiding = true;
 265     private static final String SHOW_HIDDEN_PROP = "awt.file.showHiddenFiles";
 266 
 267     // Listens to changes in the native setting for showing hidden files.
 268     // The Listener is removed and the native setting is ignored if
 269     // setFileHidingEnabled() is ever called.
 270     private transient PropertyChangeListener showFilesListener = null;
 271 
 272     private int fileSelectionMode = FILES_ONLY;
 273 
 274     private boolean multiSelectionEnabled = false;
 275 
 276     private boolean useAcceptAllFileFilter = true;
 277 
 278     private boolean dragEnabled = false;
 279 
 280     private FileFilter fileFilter = null;
 281 
 282     private FileSystemView fileSystemView = null;
 283 
 284     private File currentDirectory = null;
 285     private File selectedFile = null;
 286     private File[] selectedFiles;
 287 
 288     // *************************************
 289     // ***** JFileChooser Constructors *****
 290     // *************************************
 291 
 292     /**
 293      * Constructs a <code>JFileChooser</code> pointing to the user's
 294      * default directory. This default depends on the operating system.
 295      * It is typically the "My Documents" folder on Windows, and the
 296      * user's home directory on Unix.
 297      */
 298     public JFileChooser() {
 299         this((File) null, (FileSystemView) null);
 300     }
 301 
 302     /**
 303      * Constructs a <code>JFileChooser</code> using the given path.
 304      * Passing in a <code>null</code>
 305      * string causes the file chooser to point to the user's default directory.
 306      * This default depends on the operating system. It is
 307      * typically the "My Documents" folder on Windows, and the user's
 308      * home directory on Unix.
 309      *
 310      * @param currentDirectoryPath  a <code>String</code> giving the path
 311      *                          to a file or directory
 312      */
 313     public JFileChooser(String currentDirectoryPath) {
 314         this(currentDirectoryPath, (FileSystemView) null);
 315     }
 316 
 317     /**
 318      * Constructs a <code>JFileChooser</code> using the given <code>File</code>
 319      * as the path. Passing in a <code>null</code> file
 320      * causes the file chooser to point to the user's default directory.
 321      * This default depends on the operating system. It is
 322      * typically the "My Documents" folder on Windows, and the user's
 323      * home directory on Unix.
 324      *
 325      * @param currentDirectory  a <code>File</code> object specifying
 326      *                          the path to a file or directory
 327      */
 328     public JFileChooser(File currentDirectory) {
 329         this(currentDirectory, (FileSystemView) null);
 330     }
 331 
 332     /**
 333      * Constructs a <code>JFileChooser</code> using the given
 334      * <code>FileSystemView</code>.
 335      *
 336      * @param fsv a {@code FileSystemView}
 337      */
 338     public JFileChooser(FileSystemView fsv) {
 339         this((File) null, fsv);
 340     }
 341 
 342 
 343     /**
 344      * Constructs a <code>JFileChooser</code> using the given current directory
 345      * and <code>FileSystemView</code>.
 346      *
 347      * @param currentDirectory a {@code File} object specifying the path to a
 348      *                         file or directory
 349      * @param fsv a {@code FileSystemView}
 350      */
 351     public JFileChooser(File currentDirectory, FileSystemView fsv) {
 352         setup(fsv);
 353         setCurrentDirectory(currentDirectory);
 354     }
 355 
 356     /**
 357      * Constructs a <code>JFileChooser</code> using the given current directory
 358      * path and <code>FileSystemView</code>.
 359      *
 360      * @param currentDirectoryPath a {@code String} specifying the path to a file
 361      *                             or directory
 362      * @param fsv a {@code FileSystemView}
 363      */
 364     public JFileChooser(String currentDirectoryPath, FileSystemView fsv) {
 365         setup(fsv);
 366         if(currentDirectoryPath == null) {
 367             setCurrentDirectory(null);
 368         } else {
 369             setCurrentDirectory(fileSystemView.createFileObject(currentDirectoryPath));
 370         }
 371     }
 372 
 373     /**
 374      * Performs common constructor initialization and setup.
 375      *
 376      * @param view the {@code FileSystemView} used for setup
 377      */
 378     protected void setup(FileSystemView view) {
 379         installShowFilesListener();
 380         installHierarchyListener();
 381 
 382         if(view == null) {
 383             view = FileSystemView.getFileSystemView();
 384         }
 385         setFileSystemView(view);
 386         updateUI();
 387         if(isAcceptAllFileFilterUsed()) {
 388             setFileFilter(getAcceptAllFileFilter());
 389         }
 390         enableEvents(AWTEvent.MOUSE_EVENT_MASK);
 391     }
 392 
 393     private void installHierarchyListener() {
 394         addHierarchyListener(new HierarchyListener() {
 395             @Override
 396             public void hierarchyChanged(HierarchyEvent e) {
 397                 if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED)
 398                         == HierarchyEvent.PARENT_CHANGED) {
 399                     JFileChooser fc = JFileChooser.this;
 400                     JRootPane rootPane = SwingUtilities.getRootPane(fc);
 401                     if (rootPane != null) {
 402                         rootPane.setDefaultButton(fc.getUI().getDefaultButton(fc));
 403                     }
 404                 }
 405             }
 406         });
 407     }
 408 
 409     private void installShowFilesListener() {
 410         // Track native setting for showing hidden files
 411         Toolkit tk = Toolkit.getDefaultToolkit();
 412         Object showHiddenProperty = tk.getDesktopProperty(SHOW_HIDDEN_PROP);
 413         if (showHiddenProperty instanceof Boolean) {
 414             useFileHiding = !((Boolean)showHiddenProperty).booleanValue();
 415             showFilesListener = new WeakPCL(this);
 416             tk.addPropertyChangeListener(SHOW_HIDDEN_PROP, showFilesListener);
 417         }
 418     }
 419 
 420     /**
 421      * Sets the <code>dragEnabled</code> property,
 422      * which must be <code>true</code> to enable
 423      * automatic drag handling (the first part of drag and drop)
 424      * on this component.
 425      * The <code>transferHandler</code> property needs to be set
 426      * to a non-<code>null</code> value for the drag to do
 427      * anything.  The default value of the <code>dragEnabled</code>
 428      * property
 429      * is <code>false</code>.
 430      *
 431      * <p>
 432      *
 433      * When automatic drag handling is enabled,
 434      * most look and feels begin a drag-and-drop operation
 435      * whenever the user presses the mouse button over an item
 436      * and then moves the mouse a few pixels.
 437      * Setting this property to <code>true</code>
 438      * can therefore have a subtle effect on
 439      * how selections behave.
 440      *
 441      * <p>
 442      *
 443      * Some look and feels might not support automatic drag and drop;
 444      * they will ignore this property.  You can work around such
 445      * look and feels by modifying the component
 446      * to directly call the <code>exportAsDrag</code> method of a
 447      * <code>TransferHandler</code>.
 448      *
 449      * @param b the value to set the <code>dragEnabled</code> property to
 450      * @exception HeadlessException if
 451      *            <code>b</code> is <code>true</code> and
 452      *            <code>GraphicsEnvironment.isHeadless()</code>
 453      *            returns <code>true</code>
 454      * @see java.awt.GraphicsEnvironment#isHeadless
 455      * @see #getDragEnabled
 456      * @see #setTransferHandler
 457      * @see TransferHandler
 458      * @since 1.4
 459      *
 460      * @beaninfo
 461      *  description: determines whether automatic drag handling is enabled
 462      *        bound: false
 463      */
 464     public void setDragEnabled(boolean b) {
 465         checkDragEnabled(b);
 466         dragEnabled = b;
 467     }
 468 
 469     private static void checkDragEnabled(boolean b) {
 470         if (b && GraphicsEnvironment.isHeadless()) {
 471             throw new HeadlessException();
 472         }
 473     }
 474 
 475     /**
 476      * Gets the value of the <code>dragEnabled</code> property.
 477      *
 478      * @return  the value of the <code>dragEnabled</code> property
 479      * @see #setDragEnabled
 480      * @since 1.4
 481      */
 482     public boolean getDragEnabled() {
 483         return dragEnabled;
 484     }
 485 
 486     // *****************************
 487     // ****** File Operations ******
 488     // *****************************
 489 
 490     /**
 491      * Returns the selected file. This can be set either by the
 492      * programmer via <code>setSelectedFile</code> or by a user action, such as
 493      * either typing the filename into the UI or selecting the
 494      * file from a list in the UI.
 495      *
 496      * @see #setSelectedFile
 497      * @return the selected file
 498      */
 499     public File getSelectedFile() {
 500         return selectedFile;
 501     }
 502 
 503     /**
 504      * Sets the selected file. If the file's parent directory is
 505      * not the current directory, changes the current directory
 506      * to be the file's parent directory.
 507      *
 508      * @beaninfo
 509      *   preferred: true
 510      *       bound: true
 511      *
 512      * @see #getSelectedFile
 513      *
 514      * @param file the selected file
 515      */
 516     public void setSelectedFile(File file) {
 517         File oldValue = selectedFile;
 518         selectedFile = file;
 519         if(selectedFile != null) {
 520             if (file.isAbsolute() && !getFileSystemView().isParent(getCurrentDirectory(), selectedFile)) {
 521                 setCurrentDirectory(selectedFile.getParentFile());
 522             }
 523             if (!isMultiSelectionEnabled() || selectedFiles == null || selectedFiles.length == 1) {
 524                 ensureFileIsVisible(selectedFile);
 525             }
 526         }
 527         firePropertyChange(SELECTED_FILE_CHANGED_PROPERTY, oldValue, selectedFile);
 528     }
 529 
 530     /**
 531      * Returns a list of selected files if the file chooser is
 532      * set to allow multiple selection.
 533      *
 534      * @return an array of selected {@code File}s
 535      */
 536     public File[] getSelectedFiles() {
 537         if(selectedFiles == null) {
 538             return new File[0];
 539         } else {
 540             return selectedFiles.clone();
 541         }
 542     }
 543 
 544     /**
 545      * Sets the list of selected files if the file chooser is
 546      * set to allow multiple selection.
 547      *
 548      * @param selectedFiles an array {@code File}s to be selected
 549      * @beaninfo
 550      *       bound: true
 551      * description: The list of selected files if the chooser is in multiple selection mode.
 552      */
 553     public void setSelectedFiles(File[] selectedFiles) {
 554         File[] oldValue = this.selectedFiles;
 555         if (selectedFiles == null || selectedFiles.length == 0) {
 556             selectedFiles = null;
 557             this.selectedFiles = null;
 558             setSelectedFile(null);
 559         } else {
 560             this.selectedFiles = selectedFiles.clone();
 561             setSelectedFile(this.selectedFiles[0]);
 562         }
 563         firePropertyChange(SELECTED_FILES_CHANGED_PROPERTY, oldValue, selectedFiles);
 564     }
 565 
 566     /**
 567      * Returns the current directory.
 568      *
 569      * @return the current directory
 570      * @see #setCurrentDirectory
 571      */
 572     public File getCurrentDirectory() {
 573         return currentDirectory;
 574     }
 575 
 576     /**
 577      * Sets the current directory. Passing in <code>null</code> sets the
 578      * file chooser to point to the user's default directory.
 579      * This default depends on the operating system. It is
 580      * typically the "My Documents" folder on Windows, and the user's
 581      * home directory on Unix.
 582      *
 583      * If the file passed in as <code>currentDirectory</code> is not a
 584      * directory, the parent of the file will be used as the currentDirectory.
 585      * If the parent is not traversable, then it will walk up the parent tree
 586      * until it finds a traversable directory, or hits the root of the
 587      * file system.
 588      *
 589      * @beaninfo
 590      *   preferred: true
 591      *       bound: true
 592      * description: The directory that the JFileChooser is showing files of.
 593      *
 594      * @param dir the current directory to point to
 595      * @see #getCurrentDirectory
 596      */
 597     public void setCurrentDirectory(File dir) {
 598         File oldValue = currentDirectory;
 599 
 600         if (dir != null && !dir.exists()) {
 601             dir = currentDirectory;
 602         }
 603         if (dir == null) {
 604             dir = getFileSystemView().getDefaultDirectory();
 605         }
 606         if (currentDirectory != null) {
 607             /* Verify the toString of object */
 608             if (this.currentDirectory.equals(dir)) {
 609                 return;
 610             }
 611         }
 612 
 613         File prev = null;
 614         while (!isTraversable(dir) && prev != dir) {
 615             prev = dir;
 616             dir = getFileSystemView().getParentDirectory(dir);
 617         }
 618         currentDirectory = dir;
 619 
 620         firePropertyChange(DIRECTORY_CHANGED_PROPERTY, oldValue, currentDirectory);
 621     }
 622 
 623     /**
 624      * Changes the directory to be set to the parent of the
 625      * current directory.
 626      *
 627      * @see #getCurrentDirectory
 628      */
 629     public void changeToParentDirectory() {
 630         selectedFile = null;
 631         File oldValue = getCurrentDirectory();
 632         setCurrentDirectory(getFileSystemView().getParentDirectory(oldValue));
 633     }
 634 
 635     /**
 636      * Tells the UI to rescan its files list from the current directory.
 637      */
 638     public void rescanCurrentDirectory() {
 639         getUI().rescanCurrentDirectory(this);
 640     }
 641 
 642     /**
 643      * Makes sure that the specified file is viewable, and
 644      * not hidden.
 645      *
 646      * @param f  a File object
 647      */
 648     public void ensureFileIsVisible(File f) {
 649         getUI().ensureFileIsVisible(this, f);
 650     }
 651 
 652     // **************************************
 653     // ***** JFileChooser Dialog methods *****
 654     // **************************************
 655 
 656     /**
 657      * Pops up an "Open File" file chooser dialog. Note that the
 658      * text that appears in the approve button is determined by
 659      * the L&amp;F.
 660      *
 661      * @param    parent  the parent component of the dialog,
 662      *                  can be <code>null</code>;
 663      *                  see <code>showDialog</code> for details
 664      * @return   the return state of the file chooser on popdown:
 665      * <ul>
 666      * <li>JFileChooser.CANCEL_OPTION
 667      * <li>JFileChooser.APPROVE_OPTION
 668      * <li>JFileChooser.ERROR_OPTION if an error occurs or the
 669      *                  dialog is dismissed
 670      * </ul>
 671      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
 672      * returns true.
 673      * @see java.awt.GraphicsEnvironment#isHeadless
 674      * @see #showDialog
 675      */
 676     public int showOpenDialog(Component parent) throws HeadlessException {
 677         setDialogType(OPEN_DIALOG);
 678         return showDialog(parent, null);
 679     }
 680 
 681     /**
 682      * Pops up a "Save File" file chooser dialog. Note that the
 683      * text that appears in the approve button is determined by
 684      * the L&amp;F.
 685      *
 686      * @param    parent  the parent component of the dialog,
 687      *                  can be <code>null</code>;
 688      *                  see <code>showDialog</code> for details
 689      * @return   the return state of the file chooser on popdown:
 690      * <ul>
 691      * <li>JFileChooser.CANCEL_OPTION
 692      * <li>JFileChooser.APPROVE_OPTION
 693      * <li>JFileChooser.ERROR_OPTION if an error occurs or the
 694      *                  dialog is dismissed
 695      * </ul>
 696      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
 697      * returns true.
 698      * @see java.awt.GraphicsEnvironment#isHeadless
 699      * @see #showDialog
 700      */
 701     public int showSaveDialog(Component parent) throws HeadlessException {
 702         setDialogType(SAVE_DIALOG);
 703         return showDialog(parent, null);
 704     }
 705 
 706     /**
 707      * Pops a custom file chooser dialog with a custom approve button.
 708      * For example, the following code
 709      * pops up a file chooser with a "Run Application" button
 710      * (instead of the normal "Save" or "Open" button):
 711      * <pre>
 712      * filechooser.showDialog(parentFrame, "Run Application");
 713      * </pre>
 714      *
 715      * Alternatively, the following code does the same thing:
 716      * <pre>
 717      *    JFileChooser chooser = new JFileChooser(null);
 718      *    chooser.setApproveButtonText("Run Application");
 719      *    chooser.showDialog(parentFrame, null);
 720      * </pre>
 721      *
 722      * <!--PENDING(jeff) - the following method should be added to the api:
 723      *      showDialog(Component parent);-->
 724      * <!--PENDING(kwalrath) - should specify modality and what
 725      *      "depends" means.-->
 726      *
 727      * <p>
 728      *
 729      * The <code>parent</code> argument determines two things:
 730      * the frame on which the open dialog depends and
 731      * the component whose position the look and feel
 732      * should consider when placing the dialog.  If the parent
 733      * is a <code>Frame</code> object (such as a <code>JFrame</code>)
 734      * then the dialog depends on the frame and
 735      * the look and feel positions the dialog
 736      * relative to the frame (for example, centered over the frame).
 737      * If the parent is a component, then the dialog
 738      * depends on the frame containing the component,
 739      * and is positioned relative to the component
 740      * (for example, centered over the component).
 741      * If the parent is <code>null</code>, then the dialog depends on
 742      * no visible window, and it's placed in a
 743      * look-and-feel-dependent position
 744      * such as the center of the screen.
 745      *
 746      * @param   parent  the parent component of the dialog;
 747      *                  can be <code>null</code>
 748      * @param   approveButtonText the text of the <code>ApproveButton</code>
 749      * @return  the return state of the file chooser on popdown:
 750      * <ul>
 751      * <li>JFileChooser.CANCEL_OPTION
 752      * <li>JFileChooser.APPROVE_OPTION
 753      * <li>JFileChooser.ERROR_OPTION if an error occurs or the
 754      *                  dialog is dismissed
 755      * </ul>
 756      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
 757      * returns true.
 758      * @see java.awt.GraphicsEnvironment#isHeadless
 759      */
 760     @SuppressWarnings("deprecation")
 761     public int showDialog(Component parent, String approveButtonText)
 762         throws HeadlessException {
 763         if (dialog != null) {
 764             // Prevent to show second instance of dialog if the previous one still exists
 765             return JFileChooser.ERROR_OPTION;
 766         }
 767 
 768         if(approveButtonText != null) {
 769             setApproveButtonText(approveButtonText);
 770             setDialogType(CUSTOM_DIALOG);
 771         }
 772         dialog = createDialog(parent);
 773         dialog.addWindowListener(new WindowAdapter() {
 774             public void windowClosing(WindowEvent e) {
 775                 returnValue = CANCEL_OPTION;
 776             }
 777         });
 778         returnValue = ERROR_OPTION;
 779         rescanCurrentDirectory();
 780 
 781         dialog.show();
 782         firePropertyChange("JFileChooserDialogIsClosingProperty", dialog, null);
 783 
 784         // Remove all components from dialog. The MetalFileChooserUI.installUI() method (and other LAFs)
 785         // registers AWT listener for dialogs and produces memory leaks. It happens when
 786         // installUI invoked after the showDialog method.
 787         dialog.getContentPane().removeAll();
 788         dialog.dispose();
 789         dialog = null;
 790         return returnValue;
 791     }
 792 
 793     /**
 794      * Creates and returns a new <code>JDialog</code> wrapping
 795      * <code>this</code> centered on the <code>parent</code>
 796      * in the <code>parent</code>'s frame.
 797      * This method can be overriden to further manipulate the dialog,
 798      * to disable resizing, set the location, etc. Example:
 799      * <pre>
 800      *     class MyFileChooser extends JFileChooser {
 801      *         protected JDialog createDialog(Component parent) throws HeadlessException {
 802      *             JDialog dialog = super.createDialog(parent);
 803      *             dialog.setLocation(300, 200);
 804      *             dialog.setResizable(false);
 805      *             return dialog;
 806      *         }
 807      *     }
 808      * </pre>
 809      *
 810      * @param   parent  the parent component of the dialog;
 811      *                  can be <code>null</code>
 812      * @return a new <code>JDialog</code> containing this instance
 813      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
 814      * returns true.
 815      * @see java.awt.GraphicsEnvironment#isHeadless
 816      * @since 1.4
 817      */
 818     protected JDialog createDialog(Component parent) throws HeadlessException {
 819         FileChooserUI ui = getUI();
 820         String title = ui.getDialogTitle(this);
 821         putClientProperty(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY,
 822                           title);
 823 
 824         JDialog dialog;
 825         Window window = JOptionPane.getWindowForComponent(parent);
 826         if (window instanceof Frame) {
 827             dialog = new JDialog((Frame)window, title, true);
 828         } else {
 829             dialog = new JDialog((Dialog)window, title, true);
 830         }
 831         dialog.setComponentOrientation(this.getComponentOrientation());
 832 
 833         Container contentPane = dialog.getContentPane();
 834         contentPane.setLayout(new BorderLayout());
 835         contentPane.add(this, BorderLayout.CENTER);
 836 
 837         if (JDialog.isDefaultLookAndFeelDecorated()) {
 838             boolean supportsWindowDecorations =
 839             UIManager.getLookAndFeel().getSupportsWindowDecorations();
 840             if (supportsWindowDecorations) {
 841                 dialog.getRootPane().setWindowDecorationStyle(JRootPane.FILE_CHOOSER_DIALOG);
 842             }
 843         }
 844         dialog.pack();
 845         dialog.setLocationRelativeTo(parent);
 846 
 847         return dialog;
 848     }
 849 
 850     // **************************
 851     // ***** Dialog Options *****
 852     // **************************
 853 
 854     /**
 855      * Returns the value of the <code>controlButtonsAreShown</code>
 856      * property.
 857      *
 858      * @return   the value of the <code>controlButtonsAreShown</code>
 859      *     property
 860      *
 861      * @see #setControlButtonsAreShown
 862      * @since 1.3
 863      */
 864     public boolean getControlButtonsAreShown() {
 865         return controlsShown;
 866     }
 867 
 868 
 869     /**
 870      * Sets the property
 871      * that indicates whether the <i>approve</i> and <i>cancel</i>
 872      * buttons are shown in the file chooser.  This property
 873      * is <code>true</code> by default.  Look and feels
 874      * that always show these buttons will ignore the value
 875      * of this property.
 876      * This method fires a property-changed event,
 877      * using the string value of
 878      * <code>CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY</code>
 879      * as the name of the property.
 880      *
 881      * @param b <code>false</code> if control buttons should not be
 882      *    shown; otherwise, <code>true</code>
 883      *
 884      * @beaninfo
 885      *   preferred: true
 886      *       bound: true
 887      * description: Sets whether the approve &amp; cancel buttons are shown.
 888      *
 889      * @see #getControlButtonsAreShown
 890      * @see #CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY
 891      * @since 1.3
 892      */
 893     public void setControlButtonsAreShown(boolean b) {
 894         if(controlsShown == b) {
 895             return;
 896         }
 897         boolean oldValue = controlsShown;
 898         controlsShown = b;
 899         firePropertyChange(CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY, oldValue, controlsShown);
 900     }
 901 
 902     /**
 903      * Returns the type of this dialog.  The default is
 904      * <code>JFileChooser.OPEN_DIALOG</code>.
 905      *
 906      * @return   the type of dialog to be displayed:
 907      * <ul>
 908      * <li>JFileChooser.OPEN_DIALOG
 909      * <li>JFileChooser.SAVE_DIALOG
 910      * <li>JFileChooser.CUSTOM_DIALOG
 911      * </ul>
 912      *
 913      * @see #setDialogType
 914      */
 915     public int getDialogType() {
 916         return dialogType;
 917     }
 918 
 919     /**
 920      * Sets the type of this dialog. Use <code>OPEN_DIALOG</code> when you
 921      * want to bring up a file chooser that the user can use to open a file.
 922      * Likewise, use <code>SAVE_DIALOG</code> for letting the user choose
 923      * a file for saving.
 924      * Use <code>CUSTOM_DIALOG</code> when you want to use the file
 925      * chooser in a context other than "Open" or "Save".
 926      * For instance, you might want to bring up a file chooser that allows
 927      * the user to choose a file to execute. Note that you normally would not
 928      * need to set the <code>JFileChooser</code> to use
 929      * <code>CUSTOM_DIALOG</code>
 930      * since a call to <code>setApproveButtonText</code> does this for you.
 931      * The default dialog type is <code>JFileChooser.OPEN_DIALOG</code>.
 932      *
 933      * @param dialogType the type of dialog to be displayed:
 934      * <ul>
 935      * <li>JFileChooser.OPEN_DIALOG
 936      * <li>JFileChooser.SAVE_DIALOG
 937      * <li>JFileChooser.CUSTOM_DIALOG
 938      * </ul>
 939      *
 940      * @exception IllegalArgumentException if <code>dialogType</code> is
 941      *                          not legal
 942      * @beaninfo
 943      *   preferred: true
 944      *       bound: true
 945      * description: The type (open, save, custom) of the JFileChooser.
 946      *        enum:
 947      *              OPEN_DIALOG JFileChooser.OPEN_DIALOG
 948      *              SAVE_DIALOG JFileChooser.SAVE_DIALOG
 949      *              CUSTOM_DIALOG JFileChooser.CUSTOM_DIALOG
 950      *
 951      * @see #getDialogType
 952      * @see #setApproveButtonText
 953      */
 954     // PENDING(jeff) - fire button text change property
 955     public void setDialogType(int dialogType) {
 956         if(this.dialogType == dialogType) {
 957             return;
 958         }
 959         checkDialogType(dialogType);
 960         int oldValue = this.dialogType;
 961         this.dialogType = dialogType;
 962         if(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG) {
 963             setApproveButtonText(null);
 964         }
 965         firePropertyChange(DIALOG_TYPE_CHANGED_PROPERTY, oldValue, dialogType);
 966     }
 967 
 968     private static void checkDialogType(int dialogType) {
 969         if (!(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG
 970                 || dialogType == CUSTOM_DIALOG)) {
 971             throw new IllegalArgumentException(
 972                     "Incorrect Dialog Type: " + dialogType);
 973         }
 974     }
 975 
 976     /**
 977      * Sets the string that goes in the <code>JFileChooser</code> window's
 978      * title bar.
 979      *
 980      * @param dialogTitle the new <code>String</code> for the title bar
 981      *
 982      * @beaninfo
 983      *   preferred: true
 984      *       bound: true
 985      * description: The title of the JFileChooser dialog window.
 986      *
 987      * @see #getDialogTitle
 988      *
 989      */
 990     public void setDialogTitle(String dialogTitle) {
 991         String oldValue = this.dialogTitle;
 992         this.dialogTitle = dialogTitle;
 993         if(dialog != null) {
 994             dialog.setTitle(dialogTitle);
 995         }
 996         firePropertyChange(DIALOG_TITLE_CHANGED_PROPERTY, oldValue, dialogTitle);
 997     }
 998 
 999     /**
1000      * Gets the string that goes in the <code>JFileChooser</code>'s titlebar.
1001      *
1002      * @return the string from the {@code JFileChooser} window's title bar
1003      * @see #setDialogTitle
1004      */
1005     public String getDialogTitle() {
1006         return dialogTitle;
1007     }
1008 
1009     // ************************************
1010     // ***** JFileChooser View Options *****
1011     // ************************************
1012 
1013 
1014 
1015     /**
1016      * Sets the tooltip text used in the <code>ApproveButton</code>.
1017      * If <code>null</code>, the UI object will determine the button's text.
1018      *
1019      * @beaninfo
1020      *   preferred: true
1021      *       bound: true
1022      * description: The tooltip text for the ApproveButton.
1023      *
1024      * @param toolTipText the tooltip text for the approve button
1025      * @see #setApproveButtonText
1026      * @see #setDialogType
1027      * @see #showDialog
1028      */
1029     public void setApproveButtonToolTipText(String toolTipText) {
1030         if(approveButtonToolTipText == toolTipText) {
1031             return;
1032         }
1033         String oldValue = approveButtonToolTipText;
1034         approveButtonToolTipText = toolTipText;
1035         firePropertyChange(APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY, oldValue, approveButtonToolTipText);
1036     }
1037 
1038 
1039     /**
1040      * Returns the tooltip text used in the <code>ApproveButton</code>.
1041      * If <code>null</code>, the UI object will determine the button's text.
1042      *
1043      * @return the tooltip text used for the approve button
1044      *
1045      * @see #setApproveButtonText
1046      * @see #setDialogType
1047      * @see #showDialog
1048      */
1049     public String getApproveButtonToolTipText() {
1050         return approveButtonToolTipText;
1051     }
1052 
1053     /**
1054      * Returns the approve button's mnemonic.
1055      * @return an integer value for the mnemonic key
1056      *
1057      * @see #setApproveButtonMnemonic
1058      */
1059     public int getApproveButtonMnemonic() {
1060         return approveButtonMnemonic;
1061     }
1062 
1063     /**
1064      * Sets the approve button's mnemonic using a numeric keycode.
1065      *
1066      * @param mnemonic  an integer value for the mnemonic key
1067      *
1068      * @beaninfo
1069      *   preferred: true
1070      *       bound: true
1071      * description: The mnemonic key accelerator for the ApproveButton.
1072      *
1073      * @see #getApproveButtonMnemonic
1074      */
1075     public void setApproveButtonMnemonic(int mnemonic) {
1076         if(approveButtonMnemonic == mnemonic) {
1077            return;
1078         }
1079         int oldValue = approveButtonMnemonic;
1080         approveButtonMnemonic = mnemonic;
1081         firePropertyChange(APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY, oldValue, approveButtonMnemonic);
1082     }
1083 
1084     /**
1085      * Sets the approve button's mnemonic using a character.
1086      * @param mnemonic  a character value for the mnemonic key
1087      *
1088      * @see #getApproveButtonMnemonic
1089      */
1090     public void setApproveButtonMnemonic(char mnemonic) {
1091         int vk = (int) mnemonic;
1092         if(vk >= 'a' && vk <='z') {
1093             vk -= ('a' - 'A');
1094         }
1095         setApproveButtonMnemonic(vk);
1096     }
1097 
1098 
1099     /**
1100      * Sets the text used in the <code>ApproveButton</code> in the
1101      * <code>FileChooserUI</code>.
1102      *
1103      * @beaninfo
1104      *   preferred: true
1105      *       bound: true
1106      * description: The text that goes in the ApproveButton.
1107      *
1108      * @param approveButtonText the text used in the <code>ApproveButton</code>
1109      *
1110      * @see #getApproveButtonText
1111      * @see #setDialogType
1112      * @see #showDialog
1113      */
1114     // PENDING(jeff) - have ui set this on dialog type change
1115     public void setApproveButtonText(String approveButtonText) {
1116         if(this.approveButtonText == approveButtonText) {
1117             return;
1118         }
1119         String oldValue = this.approveButtonText;
1120         this.approveButtonText = approveButtonText;
1121         firePropertyChange(APPROVE_BUTTON_TEXT_CHANGED_PROPERTY, oldValue, approveButtonText);
1122     }
1123 
1124     /**
1125      * Returns the text used in the <code>ApproveButton</code> in the
1126      * <code>FileChooserUI</code>.
1127      * If <code>null</code>, the UI object will determine the button's text.
1128      *
1129      * Typically, this would be "Open" or "Save".
1130      *
1131      * @return the text used in the <code>ApproveButton</code>
1132      *
1133      * @see #setApproveButtonText
1134      * @see #setDialogType
1135      * @see #showDialog
1136      */
1137     public String getApproveButtonText() {
1138         return approveButtonText;
1139     }
1140 
1141     /**
1142      * Gets the list of user choosable file filters.
1143      *
1144      * @return a <code>FileFilter</code> array containing all the choosable
1145      *         file filters
1146      *
1147      * @see #addChoosableFileFilter
1148      * @see #removeChoosableFileFilter
1149      * @see #resetChoosableFileFilters
1150      */
1151     public FileFilter[] getChoosableFileFilters() {
1152         FileFilter[] filterArray = new FileFilter[filters.size()];
1153         filters.copyInto(filterArray);
1154         return filterArray;
1155     }
1156 
1157     /**
1158      * Adds a filter to the list of user choosable file filters.
1159      * For information on setting the file selection mode, see
1160      * {@link #setFileSelectionMode setFileSelectionMode}.
1161      *
1162      * @param filter the <code>FileFilter</code> to add to the choosable file
1163      *               filter list
1164      *
1165      * @beaninfo
1166      *   preferred: true
1167      *       bound: true
1168      * description: Adds a filter to the list of user choosable file filters.
1169      *
1170      * @see #getChoosableFileFilters
1171      * @see #removeChoosableFileFilter
1172      * @see #resetChoosableFileFilters
1173      * @see #setFileSelectionMode
1174      */
1175     public void addChoosableFileFilter(FileFilter filter) {
1176         if(filter != null && !filters.contains(filter)) {
1177             FileFilter[] oldValue = getChoosableFileFilters();
1178             filters.addElement(filter);
1179             firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
1180             if (fileFilter == null && filters.size() == 1) {
1181                 setFileFilter(filter);
1182             }
1183         }
1184     }
1185 
1186     /**
1187      * Removes a filter from the list of user choosable file filters. Returns
1188      * true if the file filter was removed.
1189      *
1190      * @param f the file filter to be removed
1191      * @return true if the file filter was removed, false otherwise
1192      * @see #addChoosableFileFilter
1193      * @see #getChoosableFileFilters
1194      * @see #resetChoosableFileFilters
1195      */
1196     public boolean removeChoosableFileFilter(FileFilter f) {
1197         int index = filters.indexOf(f);
1198         if (index >= 0) {
1199             if(getFileFilter() == f) {
1200                 FileFilter aaff = getAcceptAllFileFilter();
1201                 if (isAcceptAllFileFilterUsed() && (aaff != f)) {
1202                     // choose default filter if it is used
1203                     setFileFilter(aaff);
1204                 }
1205                 else if (index > 0) {
1206                     // choose the first filter, because it is not removed
1207                     setFileFilter(filters.get(0));
1208                 }
1209                 else if (filters.size() > 1) {
1210                     // choose the second filter, because the first one is removed
1211                     setFileFilter(filters.get(1));
1212                 }
1213                 else {
1214                     // no more filters
1215                     setFileFilter(null);
1216                 }
1217             }
1218             FileFilter[] oldValue = getChoosableFileFilters();
1219             filters.removeElement(f);
1220             firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
1221             return true;
1222         } else {
1223             return false;
1224         }
1225     }
1226 
1227     /**
1228      * Resets the choosable file filter list to its starting state. Normally,
1229      * this removes all added file filters while leaving the
1230      * <code>AcceptAll</code> file filter.
1231      *
1232      * @see #addChoosableFileFilter
1233      * @see #getChoosableFileFilters
1234      * @see #removeChoosableFileFilter
1235      */
1236     public void resetChoosableFileFilters() {
1237         FileFilter[] oldValue = getChoosableFileFilters();
1238         setFileFilter(null);
1239         filters.removeAllElements();
1240         if(isAcceptAllFileFilterUsed()) {
1241            addChoosableFileFilter(getAcceptAllFileFilter());
1242         }
1243         firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
1244     }
1245 
1246     /**
1247      * Returns the <code>AcceptAll</code> file filter.
1248      * For example, on Microsoft Windows this would be All Files (*.*).
1249      *
1250      * @return the {@code AcceptAll} file filter
1251      */
1252     public FileFilter getAcceptAllFileFilter() {
1253         FileFilter filter = null;
1254         if(getUI() != null) {
1255             filter = getUI().getAcceptAllFileFilter(this);
1256         }
1257         return filter;
1258     }
1259 
1260    /**
1261     * Returns whether the <code>AcceptAll FileFilter</code> is used.
1262     * @return true if the <code>AcceptAll FileFilter</code> is used
1263     * @see #setAcceptAllFileFilterUsed
1264     * @since 1.3
1265     */
1266     public boolean isAcceptAllFileFilterUsed() {
1267         return useAcceptAllFileFilter;
1268     }
1269 
1270    /**
1271     * Determines whether the <code>AcceptAll FileFilter</code> is used
1272     * as an available choice in the choosable filter list.
1273     * If false, the <code>AcceptAll</code> file filter is removed from
1274     * the list of available file filters.
1275     * If true, the <code>AcceptAll</code> file filter will become the
1276     * actively used file filter.
1277     *
1278     * @param b a {@code boolean} which determines whether the {@code AcceptAll}
1279     *          file filter is an available choice in the choosable filter list
1280     * @beaninfo
1281     *   preferred: true
1282     *       bound: true
1283     * description: Sets whether the AcceptAll FileFilter is used as an available choice in the choosable filter list.
1284     *
1285     * @see #isAcceptAllFileFilterUsed
1286     * @see #getAcceptAllFileFilter
1287     * @see #setFileFilter
1288     * @since 1.3
1289     */
1290     public void setAcceptAllFileFilterUsed(boolean b) {
1291         boolean oldValue = useAcceptAllFileFilter;
1292         useAcceptAllFileFilter = b;
1293         if(!b) {
1294             removeChoosableFileFilter(getAcceptAllFileFilter());
1295         } else {
1296             removeChoosableFileFilter(getAcceptAllFileFilter());
1297             addChoosableFileFilter(getAcceptAllFileFilter());
1298         }
1299         firePropertyChange(ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY, oldValue, useAcceptAllFileFilter);
1300     }
1301 
1302     /**
1303      * Returns the accessory component.
1304      *
1305      * @return this JFileChooser's accessory component, or null
1306      * @see #setAccessory
1307      */
1308     public JComponent getAccessory() {
1309         return accessory;
1310     }
1311 
1312     /**
1313      * Sets the accessory component. An accessory is often used to show a
1314      * preview image of the selected file; however, it can be used for anything
1315      * that the programmer wishes, such as extra custom file chooser controls.
1316      *
1317      * <p>
1318      * Note: if there was a previous accessory, you should unregister
1319      * any listeners that the accessory might have registered with the
1320      * file chooser.
1321      *
1322      * @param newAccessory the accessory component to be set
1323      * @beaninfo
1324      *   preferred: true
1325      *       bound: true
1326      * description: Sets the accessory component on the JFileChooser.
1327      */
1328     public void setAccessory(JComponent newAccessory) {
1329         JComponent oldValue = accessory;
1330         accessory = newAccessory;
1331         firePropertyChange(ACCESSORY_CHANGED_PROPERTY, oldValue, accessory);
1332     }
1333 
1334     /**
1335      * Sets the <code>JFileChooser</code> to allow the user to just
1336      * select files, just select
1337      * directories, or select both files and directories.  The default is
1338      * <code>JFilesChooser.FILES_ONLY</code>.
1339      *
1340      * @param mode the type of files to be displayed:
1341      * <ul>
1342      * <li>JFileChooser.FILES_ONLY
1343      * <li>JFileChooser.DIRECTORIES_ONLY
1344      * <li>JFileChooser.FILES_AND_DIRECTORIES
1345      * </ul>
1346      *
1347      * @exception IllegalArgumentException  if <code>mode</code> is an
1348      *                          illegal file selection mode
1349      * @beaninfo
1350      *   preferred: true
1351      *       bound: true
1352      * description: Sets the types of files that the JFileChooser can choose.
1353      *        enum: FILES_ONLY JFileChooser.FILES_ONLY
1354      *              DIRECTORIES_ONLY JFileChooser.DIRECTORIES_ONLY
1355      *              FILES_AND_DIRECTORIES JFileChooser.FILES_AND_DIRECTORIES
1356      *
1357      *
1358      * @see #getFileSelectionMode
1359      */
1360     public void setFileSelectionMode(int mode) {
1361         if(fileSelectionMode == mode) {
1362             return;
1363         }
1364 
1365         checkFileSelectionMode(mode);
1366            int oldValue = fileSelectionMode;
1367            fileSelectionMode = mode;
1368            firePropertyChange(FILE_SELECTION_MODE_CHANGED_PROPERTY, oldValue, fileSelectionMode);
1369     }
1370 
1371     private static void checkFileSelectionMode(int mode) {
1372         if ((mode != FILES_ONLY) && (mode != DIRECTORIES_ONLY)
1373                 && (mode != FILES_AND_DIRECTORIES)) {
1374             throw new IllegalArgumentException(
1375                     "Incorrect Mode for file selection: " + mode);
1376         }
1377     }
1378 
1379     /**
1380      * Returns the current file-selection mode.  The default is
1381      * <code>JFilesChooser.FILES_ONLY</code>.
1382      *
1383      * @return the type of files to be displayed, one of the following:
1384      * <ul>
1385      * <li>JFileChooser.FILES_ONLY
1386      * <li>JFileChooser.DIRECTORIES_ONLY
1387      * <li>JFileChooser.FILES_AND_DIRECTORIES
1388      * </ul>
1389      * @see #setFileSelectionMode
1390      */
1391     public int getFileSelectionMode() {
1392         return fileSelectionMode;
1393     }
1394 
1395     /**
1396      * Convenience call that determines if files are selectable based on the
1397      * current file selection mode.
1398      *
1399      * @return true if files are selectable, false otherwise
1400      * @see #setFileSelectionMode
1401      * @see #getFileSelectionMode
1402      */
1403     public boolean isFileSelectionEnabled() {
1404         return ((fileSelectionMode == FILES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES));
1405     }
1406 
1407     /**
1408      * Convenience call that determines if directories are selectable based
1409      * on the current file selection mode.
1410      *
1411      * @return true if directories are selectable, false otherwise
1412      * @see #setFileSelectionMode
1413      * @see #getFileSelectionMode
1414      */
1415     public boolean isDirectorySelectionEnabled() {
1416         return ((fileSelectionMode == DIRECTORIES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES));
1417     }
1418 
1419     /**
1420      * Sets the file chooser to allow multiple file selections.
1421      *
1422      * @param b true if multiple files may be selected
1423      * @beaninfo
1424      *       bound: true
1425      * description: Sets multiple file selection mode.
1426      *
1427      * @see #isMultiSelectionEnabled
1428      */
1429     public void setMultiSelectionEnabled(boolean b) {
1430         if(multiSelectionEnabled == b) {
1431             return;
1432         }
1433         boolean oldValue = multiSelectionEnabled;
1434         multiSelectionEnabled = b;
1435         firePropertyChange(MULTI_SELECTION_ENABLED_CHANGED_PROPERTY, oldValue, multiSelectionEnabled);
1436     }
1437 
1438     /**
1439      * Returns true if multiple files can be selected.
1440      * @return true if multiple files can be selected
1441      * @see #setMultiSelectionEnabled
1442      */
1443     public boolean isMultiSelectionEnabled() {
1444         return multiSelectionEnabled;
1445     }
1446 
1447 
1448     /**
1449      * Returns true if hidden files are not shown in the file chooser;
1450      * otherwise, returns false.
1451      *
1452      * @return the status of the file hiding property
1453      * @see #setFileHidingEnabled
1454      */
1455     public boolean isFileHidingEnabled() {
1456         return useFileHiding;
1457     }
1458 
1459     /**
1460      * Sets file hiding on or off. If true, hidden files are not shown
1461      * in the file chooser. The job of determining which files are
1462      * shown is done by the <code>FileView</code>.
1463      *
1464      * @beaninfo
1465      *   preferred: true
1466      *       bound: true
1467      * description: Sets file hiding on or off.
1468      *
1469      * @param b the boolean value that determines whether file hiding is
1470      *          turned on
1471      * @see #isFileHidingEnabled
1472      */
1473     public void setFileHidingEnabled(boolean b) {
1474         // Dump showFilesListener since we'll ignore it from now on
1475         if (showFilesListener != null) {
1476             Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, showFilesListener);
1477             showFilesListener = null;
1478         }
1479         boolean oldValue = useFileHiding;
1480         useFileHiding = b;
1481         firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, useFileHiding);
1482     }
1483 
1484     /**
1485      * Sets the current file filter. The file filter is used by the
1486      * file chooser to filter out files from the user's view.
1487      *
1488      * @beaninfo
1489      *   preferred: true
1490      *       bound: true
1491      * description: Sets the File Filter used to filter out files of type.
1492      *
1493      * @param filter the new current file filter to use
1494      * @see #getFileFilter
1495      */
1496     public void setFileFilter(FileFilter filter) {
1497         FileFilter oldValue = fileFilter;
1498         fileFilter = filter;
1499         if (filter != null) {
1500             if (isMultiSelectionEnabled() && selectedFiles != null && selectedFiles.length > 0) {
1501                 Vector<File> fList = new Vector<File>();
1502                 boolean failed = false;
1503                 for (File file : selectedFiles) {
1504                     if (filter.accept(file)) {
1505                         fList.add(file);
1506                     } else {
1507                         failed = true;
1508                     }
1509                 }
1510                 if (failed) {
1511                     setSelectedFiles((fList.size() == 0) ? null : fList.toArray(new File[fList.size()]));
1512                 }
1513             } else if (selectedFile != null && !filter.accept(selectedFile)) {
1514                 setSelectedFile(null);
1515             }
1516         }
1517         firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, oldValue, fileFilter);
1518     }
1519 
1520 
1521     /**
1522      * Returns the currently selected file filter.
1523      *
1524      * @return the current file filter
1525      * @see #setFileFilter
1526      * @see #addChoosableFileFilter
1527      */
1528     public FileFilter getFileFilter() {
1529         return fileFilter;
1530     }
1531 
1532     /**
1533      * Sets the file view to be used to retrieve UI information, such as
1534      * the icon that represents a file or the type description of a file.
1535      *
1536      * @param fileView a {@code FileView} to be used to retrieve UI information
1537      * @beaninfo
1538      *   preferred: true
1539      *       bound: true
1540      * description: Sets the File View used to get file type information.
1541      *
1542      * @see #getFileView
1543      */
1544     public void setFileView(FileView fileView) {
1545         FileView oldValue = this.fileView;
1546         this.fileView = fileView;
1547         firePropertyChange(FILE_VIEW_CHANGED_PROPERTY, oldValue, fileView);
1548     }
1549 
1550     /**
1551      * Returns the current file view.
1552      *
1553      * @return the current file view
1554      * @see #setFileView
1555      */
1556     public FileView getFileView() {
1557         return fileView;
1558     }
1559 
1560     // ******************************
1561     // *****FileView delegation *****
1562     // ******************************
1563 
1564     // NOTE: all of the following methods attempt to delegate
1565     // first to the client set fileView, and if <code>null</code> is returned
1566     // (or there is now client defined fileView) then calls the
1567     // UI's default fileView.
1568 
1569     /**
1570      * Returns the filename.
1571      * @param f the <code>File</code>
1572      * @return the <code>String</code> containing the filename for
1573      *          <code>f</code>
1574      * @see FileView#getName
1575      */
1576     public String getName(File f) {
1577         String filename = null;
1578         if(f != null) {
1579             if(getFileView() != null) {
1580                 filename = getFileView().getName(f);
1581             }
1582 
1583             FileView uiFileView = getUI().getFileView(this);
1584 
1585             if(filename == null && uiFileView != null) {
1586                 filename = uiFileView.getName(f);
1587             }
1588         }
1589         return filename;
1590     }
1591 
1592     /**
1593      * Returns the file description.
1594      * @param f the <code>File</code>
1595      * @return the <code>String</code> containing the file description for
1596      *          <code>f</code>
1597      * @see FileView#getDescription
1598      */
1599     public String getDescription(File f) {
1600         String description = null;
1601         if(f != null) {
1602             if(getFileView() != null) {
1603                 description = getFileView().getDescription(f);
1604             }
1605 
1606             FileView uiFileView = getUI().getFileView(this);
1607 
1608             if(description == null && uiFileView != null) {
1609                 description = uiFileView.getDescription(f);
1610             }
1611         }
1612         return description;
1613     }
1614 
1615     /**
1616      * Returns the file type.
1617      * @param f the <code>File</code>
1618      * @return the <code>String</code> containing the file type description for
1619      *          <code>f</code>
1620      * @see FileView#getTypeDescription
1621      */
1622     public String getTypeDescription(File f) {
1623         String typeDescription = null;
1624         if(f != null) {
1625             if(getFileView() != null) {
1626                 typeDescription = getFileView().getTypeDescription(f);
1627             }
1628 
1629             FileView uiFileView = getUI().getFileView(this);
1630 
1631             if(typeDescription == null && uiFileView != null) {
1632                 typeDescription = uiFileView.getTypeDescription(f);
1633             }
1634         }
1635         return typeDescription;
1636     }
1637 
1638     /**
1639      * Returns the icon for this file or type of file, depending
1640      * on the system.
1641      * @param f the <code>File</code>
1642      * @return the <code>Icon</code> for this file, or type of file
1643      * @see FileView#getIcon
1644      */
1645     public Icon getIcon(File f) {
1646         Icon icon = null;
1647         if (f != null) {
1648             if(getFileView() != null) {
1649                 icon = getFileView().getIcon(f);
1650             }
1651 
1652             FileView uiFileView = getUI().getFileView(this);
1653 
1654             if(icon == null && uiFileView != null) {
1655                 icon = uiFileView.getIcon(f);
1656             }
1657         }
1658         return icon;
1659     }
1660 
1661     /**
1662      * Returns true if the file (directory) can be visited.
1663      * Returns false if the directory cannot be traversed.
1664      * @param f the <code>File</code>
1665      * @return true if the file/directory can be traversed, otherwise false
1666      * @see FileView#isTraversable
1667      */
1668     public boolean isTraversable(File f) {
1669         Boolean traversable = null;
1670         if (f != null) {
1671             if (getFileView() != null) {
1672                 traversable = getFileView().isTraversable(f);
1673             }
1674 
1675             FileView uiFileView = getUI().getFileView(this);
1676 
1677             if (traversable == null && uiFileView != null) {
1678                 traversable = uiFileView.isTraversable(f);
1679             }
1680             if (traversable == null) {
1681                 traversable = getFileSystemView().isTraversable(f);
1682             }
1683         }
1684         return (traversable != null && traversable.booleanValue());
1685     }
1686 
1687     /**
1688      * Returns true if the file should be displayed.
1689      * @param f the <code>File</code>
1690      * @return true if the file should be displayed, otherwise false
1691      * @see FileFilter#accept
1692      */
1693     public boolean accept(File f) {
1694         boolean shown = true;
1695         if(f != null && fileFilter != null) {
1696             shown = fileFilter.accept(f);
1697         }
1698         return shown;
1699     }
1700 
1701     /**
1702      * Sets the file system view that the <code>JFileChooser</code> uses for
1703      * accessing and creating file system resources, such as finding
1704      * the floppy drive and getting a list of root drives.
1705      * @param fsv  the new <code>FileSystemView</code>
1706      *
1707      * @beaninfo
1708      *      expert: true
1709      *       bound: true
1710      * description: Sets the FileSytemView used to get filesystem information.
1711      *
1712      * @see FileSystemView
1713      */
1714     public void setFileSystemView(FileSystemView fsv) {
1715         FileSystemView oldValue = fileSystemView;
1716         fileSystemView = fsv;
1717         firePropertyChange(FILE_SYSTEM_VIEW_CHANGED_PROPERTY, oldValue, fileSystemView);
1718     }
1719 
1720     /**
1721      * Returns the file system view.
1722      * @return the <code>FileSystemView</code> object
1723      * @see #setFileSystemView
1724      */
1725     public FileSystemView getFileSystemView() {
1726         return fileSystemView;
1727     }
1728 
1729     // **************************
1730     // ***** Event Handling *****
1731     // **************************
1732 
1733     /**
1734      * Called by the UI when the user hits the Approve button
1735      * (labeled "Open" or "Save", by default). This can also be
1736      * called by the programmer.
1737      * This method causes an action event to fire
1738      * with the command string equal to
1739      * <code>APPROVE_SELECTION</code>.
1740      *
1741      * @see #APPROVE_SELECTION
1742      */
1743     public void approveSelection() {
1744         returnValue = APPROVE_OPTION;
1745         if(dialog != null) {
1746             dialog.setVisible(false);
1747         }
1748         fireActionPerformed(APPROVE_SELECTION);
1749     }
1750 
1751     /**
1752      * Called by the UI when the user chooses the Cancel button.
1753      * This can also be called by the programmer.
1754      * This method causes an action event to fire
1755      * with the command string equal to
1756      * <code>CANCEL_SELECTION</code>.
1757      *
1758      * @see #CANCEL_SELECTION
1759      */
1760     public void cancelSelection() {
1761         returnValue = CANCEL_OPTION;
1762         if(dialog != null) {
1763             dialog.setVisible(false);
1764         }
1765         fireActionPerformed(CANCEL_SELECTION);
1766     }
1767 
1768     /**
1769      * Adds an <code>ActionListener</code> to the file chooser.
1770      *
1771      * @param l  the listener to be added
1772      *
1773      * @see #approveSelection
1774      * @see #cancelSelection
1775      */
1776     public void addActionListener(ActionListener l) {
1777         listenerList.add(ActionListener.class, l);
1778     }
1779 
1780     /**
1781      * Removes an <code>ActionListener</code> from the file chooser.
1782      *
1783      * @param l  the listener to be removed
1784      *
1785      * @see #addActionListener
1786      */
1787     public void removeActionListener(ActionListener l) {
1788         listenerList.remove(ActionListener.class, l);
1789     }
1790 
1791     /**
1792      * Returns an array of all the action listeners
1793      * registered on this file chooser.
1794      *
1795      * @return all of this file chooser's <code>ActionListener</code>s
1796      *         or an empty
1797      *         array if no action listeners are currently registered
1798      *
1799      * @see #addActionListener
1800      * @see #removeActionListener
1801      *
1802      * @since 1.4
1803      */
1804     public ActionListener[] getActionListeners() {
1805         return listenerList.getListeners(ActionListener.class);
1806     }
1807 
1808     /**
1809      * Notifies all listeners that have registered interest for
1810      * notification on this event type. The event instance
1811      * is lazily created using the <code>command</code> parameter.
1812      *
1813      * @param command a string that may specify a command associated with
1814      *                the event
1815      * @see EventListenerList
1816      */
1817     protected void fireActionPerformed(String command) {
1818         // Guaranteed to return a non-null array
1819         Object[] listeners = listenerList.getListenerList();
1820         long mostRecentEventTime = EventQueue.getMostRecentEventTime();
1821         int modifiers = 0;
1822         AWTEvent currentEvent = EventQueue.getCurrentEvent();
1823         if (currentEvent instanceof InputEvent) {
1824             modifiers = ((InputEvent)currentEvent).getModifiers();
1825         } else if (currentEvent instanceof ActionEvent) {
1826             modifiers = ((ActionEvent)currentEvent).getModifiers();
1827         }
1828         ActionEvent e = null;
1829         // Process the listeners last to first, notifying
1830         // those that are interested in this event
1831         for (int i = listeners.length-2; i>=0; i-=2) {
1832             if (listeners[i]==ActionListener.class) {
1833                 // Lazily create the event:
1834                 if (e == null) {
1835                     e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
1836                                         command, mostRecentEventTime,
1837                                         modifiers);
1838                 }
1839                 ((ActionListener)listeners[i+1]).actionPerformed(e);
1840             }
1841         }
1842     }
1843 
1844     private static class WeakPCL implements PropertyChangeListener {
1845         WeakReference<JFileChooser> jfcRef;
1846 
1847         public WeakPCL(JFileChooser jfc) {
1848             jfcRef = new WeakReference<JFileChooser>(jfc);
1849         }
1850         public void propertyChange(PropertyChangeEvent ev) {
1851             assert ev.getPropertyName().equals(SHOW_HIDDEN_PROP);
1852             JFileChooser jfc = jfcRef.get();
1853             if (jfc == null) {
1854                 // Our JFileChooser is no longer around, so we no longer need to
1855                 // listen for PropertyChangeEvents.
1856                 Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, this);
1857             }
1858             else {
1859                 boolean oldValue = jfc.useFileHiding;
1860                 jfc.useFileHiding = !((Boolean)ev.getNewValue()).booleanValue();
1861                 jfc.firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, jfc.useFileHiding);
1862             }
1863         }
1864     }
1865 
1866     // *********************************
1867     // ***** Pluggable L&F methods *****
1868     // *********************************
1869 
1870     /**
1871      * Resets the UI property to a value from the current look and feel.
1872      *
1873      * @see JComponent#updateUI
1874      */
1875     public void updateUI() {
1876         if (isAcceptAllFileFilterUsed()) {
1877             removeChoosableFileFilter(getAcceptAllFileFilter());
1878         }
1879         FileChooserUI ui = ((FileChooserUI)UIManager.getUI(this));
1880         if (fileSystemView == null) {
1881             // We were probably deserialized
1882             setFileSystemView(FileSystemView.getFileSystemView());
1883         }
1884         setUI(ui);
1885 
1886         if(isAcceptAllFileFilterUsed()) {
1887             addChoosableFileFilter(getAcceptAllFileFilter());
1888         }
1889     }
1890 
1891     /**
1892      * Returns a string that specifies the name of the L&amp;F class
1893      * that renders this component.
1894      *
1895      * @return the string "FileChooserUI"
1896      * @see JComponent#getUIClassID
1897      * @see UIDefaults#getUI
1898      * @beaninfo
1899      *        expert: true
1900      *   description: A string that specifies the name of the L&amp;F class.
1901      */
1902     public String getUIClassID() {
1903         return uiClassID;
1904     }
1905 
1906     /**
1907      * Gets the UI object which implements the L&amp;F for this component.
1908      *
1909      * @return the FileChooserUI object that implements the FileChooserUI L&amp;F
1910      */
1911     public FileChooserUI getUI() {
1912         return (FileChooserUI) ui;
1913     }
1914 
1915     /**
1916      * See <code>readObject</code> and <code>writeObject</code> in
1917      * <code>JComponent</code> for more
1918      * information about serialization in Swing.
1919      */
1920     private void readObject(java.io.ObjectInputStream in)
1921             throws IOException, ClassNotFoundException {
1922         ObjectInputStream.GetField f = in.readFields();
1923 
1924         dialogTitle = (String) f.get("dialogTitle", null);
1925         approveButtonText = (String) f.get("approveButtonText", null);
1926         approveButtonToolTipText =
1927                 (String) f.get("approveButtonToolTipText", null);
1928         approveButtonMnemonic = f.get("approveButtonMnemonic", 0);
1929         @SuppressWarnings("unchecked")
1930         Vector<FileFilter> newFilters = (Vector<FileFilter>) f.get("filters", null);
1931         if (newFilters == null) {
1932             throw new InvalidObjectException("Null filters");
1933         }
1934         filters = newFilters;
1935         dialog = (JDialog) f.get("dialog", null);
1936         int newDialogType = f.get("dialogType", OPEN_DIALOG);
1937         checkDialogType(newDialogType);
1938         dialogType = newDialogType;
1939         returnValue = f.get("returnValue", 0);
1940         accessory = (JComponent) f.get("accessory", null);
1941         fileView = (FileView) f.get("fileView", null);
1942         controlsShown = f.get("controlsShown", false);
1943         useFileHiding = f.get("useFileHiding", false);
1944         int newFileSelectionMode = f.get("fileSelectionMode", FILES_ONLY);
1945         checkFileSelectionMode(newFileSelectionMode);
1946         fileSelectionMode = newFileSelectionMode;
1947         multiSelectionEnabled = f.get("multiSelectionEnabled", false);
1948         useAcceptAllFileFilter = f.get("useAcceptAllFileFilter", false);
1949         boolean newDragEnabled = f.get("dragEnabled", false);
1950         checkDragEnabled(newDragEnabled);
1951         dragEnabled = newDragEnabled;
1952         fileFilter = (FileFilter) f.get("fileFilter", null);
1953         fileSystemView = (FileSystemView) f.get("fileSystemView", null);
1954         currentDirectory = (File) f.get("currentDirectory", null);
1955         selectedFile = (File) f.get("selectedFile", null);
1956         selectedFiles = (File[]) f.get("selectedFiles", null);
1957         accessibleContext = (AccessibleContext) f.get("accessibleContext", null);
1958 
1959         installShowFilesListener();
1960     }
1961 
1962     /**
1963      * See <code>readObject</code> and <code>writeObject</code> in
1964      * <code>JComponent</code> for more
1965      * information about serialization in Swing.
1966      */
1967     private void writeObject(ObjectOutputStream s) throws IOException {
1968         FileSystemView fsv = null;
1969 
1970         if (isAcceptAllFileFilterUsed()) {
1971             //The AcceptAllFileFilter is UI specific, it will be reset by
1972             //updateUI() after deserialization
1973             removeChoosableFileFilter(getAcceptAllFileFilter());
1974         }
1975         if (fileSystemView.equals(FileSystemView.getFileSystemView())) {
1976             //The default FileSystemView is platform specific, it will be
1977             //reset by updateUI() after deserialization
1978             fsv = fileSystemView;
1979             fileSystemView = null;
1980         }
1981         s.defaultWriteObject();
1982         if (fsv != null) {
1983             fileSystemView = fsv;
1984         }
1985         if (isAcceptAllFileFilterUsed()) {
1986             addChoosableFileFilter(getAcceptAllFileFilter());
1987         }
1988         if (getUIClassID().equals(uiClassID)) {
1989             byte count = JComponent.getWriteObjCounter(this);
1990             JComponent.setWriteObjCounter(this, --count);
1991             if (count == 0 && ui != null) {
1992                 ui.installUI(this);
1993             }
1994         }
1995     }
1996 
1997 
1998     /**
1999      * Returns a string representation of this <code>JFileChooser</code>.
2000      * This method
2001      * is intended to be used only for debugging purposes, and the
2002      * content and format of the returned string may vary between
2003      * implementations. The returned string may be empty but may not
2004      * be <code>null</code>.
2005      *
2006      * @return  a string representation of this <code>JFileChooser</code>
2007      */
2008     protected String paramString() {
2009         String approveButtonTextString = (approveButtonText != null ?
2010                                           approveButtonText: "");
2011         String dialogTitleString = (dialogTitle != null ?
2012                                     dialogTitle: "");
2013         String dialogTypeString;
2014         if (dialogType == OPEN_DIALOG) {
2015             dialogTypeString = "OPEN_DIALOG";
2016         } else if (dialogType == SAVE_DIALOG) {
2017             dialogTypeString = "SAVE_DIALOG";
2018         } else if (dialogType == CUSTOM_DIALOG) {
2019             dialogTypeString = "CUSTOM_DIALOG";
2020         } else dialogTypeString = "";
2021         String returnValueString;
2022         if (returnValue == CANCEL_OPTION) {
2023             returnValueString = "CANCEL_OPTION";
2024         } else if (returnValue == APPROVE_OPTION) {
2025             returnValueString = "APPROVE_OPTION";
2026         } else if (returnValue == ERROR_OPTION) {
2027             returnValueString = "ERROR_OPTION";
2028         } else returnValueString = "";
2029         String useFileHidingString = (useFileHiding ?
2030                                     "true" : "false");
2031         String fileSelectionModeString;
2032         if (fileSelectionMode == FILES_ONLY) {
2033             fileSelectionModeString = "FILES_ONLY";
2034         } else if (fileSelectionMode == DIRECTORIES_ONLY) {
2035             fileSelectionModeString = "DIRECTORIES_ONLY";
2036         } else if (fileSelectionMode == FILES_AND_DIRECTORIES) {
2037             fileSelectionModeString = "FILES_AND_DIRECTORIES";
2038         } else fileSelectionModeString = "";
2039         String currentDirectoryString = (currentDirectory != null ?
2040                                          currentDirectory.toString() : "");
2041         String selectedFileString = (selectedFile != null ?
2042                                      selectedFile.toString() : "");
2043 
2044         return super.paramString() +
2045         ",approveButtonText=" + approveButtonTextString +
2046         ",currentDirectory=" + currentDirectoryString +
2047         ",dialogTitle=" + dialogTitleString +
2048         ",dialogType=" + dialogTypeString +
2049         ",fileSelectionMode=" + fileSelectionModeString +
2050         ",returnValue=" + returnValueString +
2051         ",selectedFile=" + selectedFileString +
2052         ",useFileHiding=" + useFileHidingString;
2053     }
2054 
2055 /////////////////
2056 // Accessibility support
2057 ////////////////
2058 
2059     /**
2060      * {@code AccessibleContext} associated with this {@code JFileChooser}
2061      */
2062     protected AccessibleContext accessibleContext = null;
2063 
2064     /**
2065      * Gets the AccessibleContext associated with this JFileChooser.
2066      * For file choosers, the AccessibleContext takes the form of an
2067      * AccessibleJFileChooser.
2068      * A new AccessibleJFileChooser instance is created if necessary.
2069      *
2070      * @return an AccessibleJFileChooser that serves as the
2071      *         AccessibleContext of this JFileChooser
2072      */
2073     public AccessibleContext getAccessibleContext() {
2074         if (accessibleContext == null) {
2075             accessibleContext = new AccessibleJFileChooser();
2076         }
2077         return accessibleContext;
2078     }
2079 
2080     /**
2081      * This class implements accessibility support for the
2082      * <code>JFileChooser</code> class.  It provides an implementation of the
2083      * Java Accessibility API appropriate to file chooser user-interface
2084      * elements.
2085      */
2086     @SuppressWarnings("serial") // Superclass is not serializable across versions
2087     protected class AccessibleJFileChooser extends AccessibleJComponent {
2088 
2089         /**
2090          * Gets the role of this object.
2091          *
2092          * @return an instance of AccessibleRole describing the role of the
2093          * object
2094          * @see AccessibleRole
2095          */
2096         public AccessibleRole getAccessibleRole() {
2097             return AccessibleRole.FILE_CHOOSER;
2098         }
2099 
2100     } // inner class AccessibleJFileChooser
2101 
2102 }