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     public int showDialog(Component parent, String approveButtonText)
 761         throws HeadlessException {
 762         if (dialog != null) {
 763             // Prevent to show second instance of dialog if the previous one still exists
 764             return JFileChooser.ERROR_OPTION;
 765         }
 766 
 767         if(approveButtonText != null) {
 768             setApproveButtonText(approveButtonText);
 769             setDialogType(CUSTOM_DIALOG);
 770         }
 771         dialog = createDialog(parent);
 772         dialog.addWindowListener(new WindowAdapter() {
 773             public void windowClosing(WindowEvent e) {
 774                 returnValue = CANCEL_OPTION;
 775             }
 776         });
 777         returnValue = ERROR_OPTION;
 778         rescanCurrentDirectory();
 779 
 780         dialog.show();
 781         firePropertyChange("JFileChooserDialogIsClosingProperty", dialog, null);
 782 
 783         // Remove all components from dialog. The MetalFileChooserUI.installUI() method (and other LAFs)
 784         // registers AWT listener for dialogs and produces memory leaks. It happens when
 785         // installUI invoked after the showDialog method.
 786         dialog.getContentPane().removeAll();
 787         dialog.dispose();
 788         dialog = null;
 789         return returnValue;
 790     }
 791 
 792     /**
 793      * Creates and returns a new <code>JDialog</code> wrapping
 794      * <code>this</code> centered on the <code>parent</code>
 795      * in the <code>parent</code>'s frame.
 796      * This method can be overriden to further manipulate the dialog,
 797      * to disable resizing, set the location, etc. Example:
 798      * <pre>
 799      *     class MyFileChooser extends JFileChooser {
 800      *         protected JDialog createDialog(Component parent) throws HeadlessException {
 801      *             JDialog dialog = super.createDialog(parent);
 802      *             dialog.setLocation(300, 200);
 803      *             dialog.setResizable(false);
 804      *             return dialog;
 805      *         }
 806      *     }
 807      * </pre>
 808      *
 809      * @param   parent  the parent component of the dialog;
 810      *                  can be <code>null</code>
 811      * @return a new <code>JDialog</code> containing this instance
 812      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
 813      * returns true.
 814      * @see java.awt.GraphicsEnvironment#isHeadless
 815      * @since 1.4
 816      */
 817     protected JDialog createDialog(Component parent) throws HeadlessException {
 818         FileChooserUI ui = getUI();
 819         String title = ui.getDialogTitle(this);
 820         putClientProperty(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY,
 821                           title);
 822 
 823         JDialog dialog;
 824         Window window = JOptionPane.getWindowForComponent(parent);
 825         if (window instanceof Frame) {
 826             dialog = new JDialog((Frame)window, title, true);
 827         } else {
 828             dialog = new JDialog((Dialog)window, title, true);
 829         }
 830         dialog.setComponentOrientation(this.getComponentOrientation());
 831 
 832         Container contentPane = dialog.getContentPane();
 833         contentPane.setLayout(new BorderLayout());
 834         contentPane.add(this, BorderLayout.CENTER);
 835 
 836         if (JDialog.isDefaultLookAndFeelDecorated()) {
 837             boolean supportsWindowDecorations =
 838             UIManager.getLookAndFeel().getSupportsWindowDecorations();
 839             if (supportsWindowDecorations) {
 840                 dialog.getRootPane().setWindowDecorationStyle(JRootPane.FILE_CHOOSER_DIALOG);
 841             }
 842         }
 843         dialog.pack();
 844         dialog.setLocationRelativeTo(parent);
 845 
 846         return dialog;
 847     }
 848 
 849     // **************************
 850     // ***** Dialog Options *****
 851     // **************************
 852 
 853     /**
 854      * Returns the value of the <code>controlButtonsAreShown</code>
 855      * property.
 856      *
 857      * @return   the value of the <code>controlButtonsAreShown</code>
 858      *     property
 859      *
 860      * @see #setControlButtonsAreShown
 861      * @since 1.3
 862      */
 863     public boolean getControlButtonsAreShown() {
 864         return controlsShown;
 865     }
 866 
 867 
 868     /**
 869      * Sets the property
 870      * that indicates whether the <i>approve</i> and <i>cancel</i>
 871      * buttons are shown in the file chooser.  This property
 872      * is <code>true</code> by default.  Look and feels
 873      * that always show these buttons will ignore the value
 874      * of this property.
 875      * This method fires a property-changed event,
 876      * using the string value of
 877      * <code>CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY</code>
 878      * as the name of the property.
 879      *
 880      * @param b <code>false</code> if control buttons should not be
 881      *    shown; otherwise, <code>true</code>
 882      *
 883      * @beaninfo
 884      *   preferred: true
 885      *       bound: true
 886      * description: Sets whether the approve &amp; cancel buttons are shown.
 887      *
 888      * @see #getControlButtonsAreShown
 889      * @see #CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY
 890      * @since 1.3
 891      */
 892     public void setControlButtonsAreShown(boolean b) {
 893         if(controlsShown == b) {
 894             return;
 895         }
 896         boolean oldValue = controlsShown;
 897         controlsShown = b;
 898         firePropertyChange(CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY, oldValue, controlsShown);
 899     }
 900 
 901     /**
 902      * Returns the type of this dialog.  The default is
 903      * <code>JFileChooser.OPEN_DIALOG</code>.
 904      *
 905      * @return   the type of dialog to be displayed:
 906      * <ul>
 907      * <li>JFileChooser.OPEN_DIALOG
 908      * <li>JFileChooser.SAVE_DIALOG
 909      * <li>JFileChooser.CUSTOM_DIALOG
 910      * </ul>
 911      *
 912      * @see #setDialogType
 913      */
 914     public int getDialogType() {
 915         return dialogType;
 916     }
 917 
 918     /**
 919      * Sets the type of this dialog. Use <code>OPEN_DIALOG</code> when you
 920      * want to bring up a file chooser that the user can use to open a file.
 921      * Likewise, use <code>SAVE_DIALOG</code> for letting the user choose
 922      * a file for saving.
 923      * Use <code>CUSTOM_DIALOG</code> when you want to use the file
 924      * chooser in a context other than "Open" or "Save".
 925      * For instance, you might want to bring up a file chooser that allows
 926      * the user to choose a file to execute. Note that you normally would not
 927      * need to set the <code>JFileChooser</code> to use
 928      * <code>CUSTOM_DIALOG</code>
 929      * since a call to <code>setApproveButtonText</code> does this for you.
 930      * The default dialog type is <code>JFileChooser.OPEN_DIALOG</code>.
 931      *
 932      * @param dialogType the type of dialog to be displayed:
 933      * <ul>
 934      * <li>JFileChooser.OPEN_DIALOG
 935      * <li>JFileChooser.SAVE_DIALOG
 936      * <li>JFileChooser.CUSTOM_DIALOG
 937      * </ul>
 938      *
 939      * @exception IllegalArgumentException if <code>dialogType</code> is
 940      *                          not legal
 941      * @beaninfo
 942      *   preferred: true
 943      *       bound: true
 944      * description: The type (open, save, custom) of the JFileChooser.
 945      *        enum:
 946      *              OPEN_DIALOG JFileChooser.OPEN_DIALOG
 947      *              SAVE_DIALOG JFileChooser.SAVE_DIALOG
 948      *              CUSTOM_DIALOG JFileChooser.CUSTOM_DIALOG
 949      *
 950      * @see #getDialogType
 951      * @see #setApproveButtonText
 952      */
 953     // PENDING(jeff) - fire button text change property
 954     public void setDialogType(int dialogType) {
 955         if(this.dialogType == dialogType) {
 956             return;
 957         }
 958         checkDialogType(dialogType);
 959         int oldValue = this.dialogType;
 960         this.dialogType = dialogType;
 961         if(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG) {
 962             setApproveButtonText(null);
 963         }
 964         firePropertyChange(DIALOG_TYPE_CHANGED_PROPERTY, oldValue, dialogType);
 965     }
 966 
 967     private static void checkDialogType(int dialogType) {
 968         if (!(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG
 969                 || dialogType == CUSTOM_DIALOG)) {
 970             throw new IllegalArgumentException(
 971                     "Incorrect Dialog Type: " + dialogType);
 972         }
 973     }
 974 
 975     /**
 976      * Sets the string that goes in the <code>JFileChooser</code> window's
 977      * title bar.
 978      *
 979      * @param dialogTitle the new <code>String</code> for the title bar
 980      *
 981      * @beaninfo
 982      *   preferred: true
 983      *       bound: true
 984      * description: The title of the JFileChooser dialog window.
 985      *
 986      * @see #getDialogTitle
 987      *
 988      */
 989     public void setDialogTitle(String dialogTitle) {
 990         String oldValue = this.dialogTitle;
 991         this.dialogTitle = dialogTitle;
 992         if(dialog != null) {
 993             dialog.setTitle(dialogTitle);
 994         }
 995         firePropertyChange(DIALOG_TITLE_CHANGED_PROPERTY, oldValue, dialogTitle);
 996     }
 997 
 998     /**
 999      * Gets the string that goes in the <code>JFileChooser</code>'s titlebar.
1000      *
1001      * @return the string from the {@code JFileChooser} window's title bar
1002      * @see #setDialogTitle
1003      */
1004     public String getDialogTitle() {
1005         return dialogTitle;
1006     }
1007 
1008     // ************************************
1009     // ***** JFileChooser View Options *****
1010     // ************************************
1011 
1012 
1013 
1014     /**
1015      * Sets the tooltip text used in the <code>ApproveButton</code>.
1016      * If <code>null</code>, the UI object will determine the button's text.
1017      *
1018      * @beaninfo
1019      *   preferred: true
1020      *       bound: true
1021      * description: The tooltip text for the ApproveButton.
1022      *
1023      * @param toolTipText the tooltip text for the approve button
1024      * @see #setApproveButtonText
1025      * @see #setDialogType
1026      * @see #showDialog
1027      */
1028     public void setApproveButtonToolTipText(String toolTipText) {
1029         if(approveButtonToolTipText == toolTipText) {
1030             return;
1031         }
1032         String oldValue = approveButtonToolTipText;
1033         approveButtonToolTipText = toolTipText;
1034         firePropertyChange(APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY, oldValue, approveButtonToolTipText);
1035     }
1036 
1037 
1038     /**
1039      * Returns the tooltip text used in the <code>ApproveButton</code>.
1040      * If <code>null</code>, the UI object will determine the button's text.
1041      *
1042      * @return the tooltip text used for the approve button
1043      *
1044      * @see #setApproveButtonText
1045      * @see #setDialogType
1046      * @see #showDialog
1047      */
1048     public String getApproveButtonToolTipText() {
1049         return approveButtonToolTipText;
1050     }
1051 
1052     /**
1053      * Returns the approve button's mnemonic.
1054      * @return an integer value for the mnemonic key
1055      *
1056      * @see #setApproveButtonMnemonic
1057      */
1058     public int getApproveButtonMnemonic() {
1059         return approveButtonMnemonic;
1060     }
1061 
1062     /**
1063      * Sets the approve button's mnemonic using a numeric keycode.
1064      *
1065      * @param mnemonic  an integer value for the mnemonic key
1066      *
1067      * @beaninfo
1068      *   preferred: true
1069      *       bound: true
1070      * description: The mnemonic key accelerator for the ApproveButton.
1071      *
1072      * @see #getApproveButtonMnemonic
1073      */
1074     public void setApproveButtonMnemonic(int mnemonic) {
1075         if(approveButtonMnemonic == mnemonic) {
1076            return;
1077         }
1078         int oldValue = approveButtonMnemonic;
1079         approveButtonMnemonic = mnemonic;
1080         firePropertyChange(APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY, oldValue, approveButtonMnemonic);
1081     }
1082 
1083     /**
1084      * Sets the approve button's mnemonic using a character.
1085      * @param mnemonic  a character value for the mnemonic key
1086      *
1087      * @see #getApproveButtonMnemonic
1088      */
1089     public void setApproveButtonMnemonic(char mnemonic) {
1090         int vk = (int) mnemonic;
1091         if(vk >= 'a' && vk <='z') {
1092             vk -= ('a' - 'A');
1093         }
1094         setApproveButtonMnemonic(vk);
1095     }
1096 
1097 
1098     /**
1099      * Sets the text used in the <code>ApproveButton</code> in the
1100      * <code>FileChooserUI</code>.
1101      *
1102      * @beaninfo
1103      *   preferred: true
1104      *       bound: true
1105      * description: The text that goes in the ApproveButton.
1106      *
1107      * @param approveButtonText the text used in the <code>ApproveButton</code>
1108      *
1109      * @see #getApproveButtonText
1110      * @see #setDialogType
1111      * @see #showDialog
1112      */
1113     // PENDING(jeff) - have ui set this on dialog type change
1114     public void setApproveButtonText(String approveButtonText) {
1115         if(this.approveButtonText == approveButtonText) {
1116             return;
1117         }
1118         String oldValue = this.approveButtonText;
1119         this.approveButtonText = approveButtonText;
1120         firePropertyChange(APPROVE_BUTTON_TEXT_CHANGED_PROPERTY, oldValue, approveButtonText);
1121     }
1122 
1123     /**
1124      * Returns the text used in the <code>ApproveButton</code> in the
1125      * <code>FileChooserUI</code>.
1126      * If <code>null</code>, the UI object will determine the button's text.
1127      *
1128      * Typically, this would be "Open" or "Save".
1129      *
1130      * @return the text used in the <code>ApproveButton</code>
1131      *
1132      * @see #setApproveButtonText
1133      * @see #setDialogType
1134      * @see #showDialog
1135      */
1136     public String getApproveButtonText() {
1137         return approveButtonText;
1138     }
1139 
1140     /**
1141      * Gets the list of user choosable file filters.
1142      *
1143      * @return a <code>FileFilter</code> array containing all the choosable
1144      *         file filters
1145      *
1146      * @see #addChoosableFileFilter
1147      * @see #removeChoosableFileFilter
1148      * @see #resetChoosableFileFilters
1149      */
1150     public FileFilter[] getChoosableFileFilters() {
1151         FileFilter[] filterArray = new FileFilter[filters.size()];
1152         filters.copyInto(filterArray);
1153         return filterArray;
1154     }
1155 
1156     /**
1157      * Adds a filter to the list of user choosable file filters.
1158      * For information on setting the file selection mode, see
1159      * {@link #setFileSelectionMode setFileSelectionMode}.
1160      *
1161      * @param filter the <code>FileFilter</code> to add to the choosable file
1162      *               filter list
1163      *
1164      * @beaninfo
1165      *   preferred: true
1166      *       bound: true
1167      * description: Adds a filter to the list of user choosable file filters.
1168      *
1169      * @see #getChoosableFileFilters
1170      * @see #removeChoosableFileFilter
1171      * @see #resetChoosableFileFilters
1172      * @see #setFileSelectionMode
1173      */
1174     public void addChoosableFileFilter(FileFilter filter) {
1175         if(filter != null && !filters.contains(filter)) {
1176             FileFilter[] oldValue = getChoosableFileFilters();
1177             filters.addElement(filter);
1178             firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
1179             if (fileFilter == null && filters.size() == 1) {
1180                 setFileFilter(filter);
1181             }
1182         }
1183     }
1184 
1185     /**
1186      * Removes a filter from the list of user choosable file filters. Returns
1187      * true if the file filter was removed.
1188      *
1189      * @param f the file filter to be removed
1190      * @return true if the file filter was removed, false otherwise
1191      * @see #addChoosableFileFilter
1192      * @see #getChoosableFileFilters
1193      * @see #resetChoosableFileFilters
1194      */
1195     public boolean removeChoosableFileFilter(FileFilter f) {
1196         int index = filters.indexOf(f);
1197         if (index >= 0) {
1198             if(getFileFilter() == f) {
1199                 FileFilter aaff = getAcceptAllFileFilter();
1200                 if (isAcceptAllFileFilterUsed() && (aaff != f)) {
1201                     // choose default filter if it is used
1202                     setFileFilter(aaff);
1203                 }
1204                 else if (index > 0) {
1205                     // choose the first filter, because it is not removed
1206                     setFileFilter(filters.get(0));
1207                 }
1208                 else if (filters.size() > 1) {
1209                     // choose the second filter, because the first one is removed
1210                     setFileFilter(filters.get(1));
1211                 }
1212                 else {
1213                     // no more filters
1214                     setFileFilter(null);
1215                 }
1216             }
1217             FileFilter[] oldValue = getChoosableFileFilters();
1218             filters.removeElement(f);
1219             firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
1220             return true;
1221         } else {
1222             return false;
1223         }
1224     }
1225 
1226     /**
1227      * Resets the choosable file filter list to its starting state. Normally,
1228      * this removes all added file filters while leaving the
1229      * <code>AcceptAll</code> file filter.
1230      *
1231      * @see #addChoosableFileFilter
1232      * @see #getChoosableFileFilters
1233      * @see #removeChoosableFileFilter
1234      */
1235     public void resetChoosableFileFilters() {
1236         FileFilter[] oldValue = getChoosableFileFilters();
1237         setFileFilter(null);
1238         filters.removeAllElements();
1239         if(isAcceptAllFileFilterUsed()) {
1240            addChoosableFileFilter(getAcceptAllFileFilter());
1241         }
1242         firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
1243     }
1244 
1245     /**
1246      * Returns the <code>AcceptAll</code> file filter.
1247      * For example, on Microsoft Windows this would be All Files (*.*).
1248      *
1249      * @return the {@code AcceptAll} file filter
1250      */
1251     public FileFilter getAcceptAllFileFilter() {
1252         FileFilter filter = null;
1253         if(getUI() != null) {
1254             filter = getUI().getAcceptAllFileFilter(this);
1255         }
1256         return filter;
1257     }
1258 
1259    /**
1260     * Returns whether the <code>AcceptAll FileFilter</code> is used.
1261     * @return true if the <code>AcceptAll FileFilter</code> is used
1262     * @see #setAcceptAllFileFilterUsed
1263     * @since 1.3
1264     */
1265     public boolean isAcceptAllFileFilterUsed() {
1266         return useAcceptAllFileFilter;
1267     }
1268 
1269    /**
1270     * Determines whether the <code>AcceptAll FileFilter</code> is used
1271     * as an available choice in the choosable filter list.
1272     * If false, the <code>AcceptAll</code> file filter is removed from
1273     * the list of available file filters.
1274     * If true, the <code>AcceptAll</code> file filter will become the
1275     * actively used file filter.
1276     *
1277     * @param b a {@code boolean} which determines whether the {@code AcceptAll}
1278     *          file filter is an available choice in the choosable filter list
1279     * @beaninfo
1280     *   preferred: true
1281     *       bound: true
1282     * description: Sets whether the AcceptAll FileFilter is used as an available choice in the choosable filter list.
1283     *
1284     * @see #isAcceptAllFileFilterUsed
1285     * @see #getAcceptAllFileFilter
1286     * @see #setFileFilter
1287     * @since 1.3
1288     */
1289     public void setAcceptAllFileFilterUsed(boolean b) {
1290         boolean oldValue = useAcceptAllFileFilter;
1291         useAcceptAllFileFilter = b;
1292         if(!b) {
1293             removeChoosableFileFilter(getAcceptAllFileFilter());
1294         } else {
1295             removeChoosableFileFilter(getAcceptAllFileFilter());
1296             addChoosableFileFilter(getAcceptAllFileFilter());
1297         }
1298         firePropertyChange(ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY, oldValue, useAcceptAllFileFilter);
1299     }
1300 
1301     /**
1302      * Returns the accessory component.
1303      *
1304      * @return this JFileChooser's accessory component, or null
1305      * @see #setAccessory
1306      */
1307     public JComponent getAccessory() {
1308         return accessory;
1309     }
1310 
1311     /**
1312      * Sets the accessory component. An accessory is often used to show a
1313      * preview image of the selected file; however, it can be used for anything
1314      * that the programmer wishes, such as extra custom file chooser controls.
1315      *
1316      * <p>
1317      * Note: if there was a previous accessory, you should unregister
1318      * any listeners that the accessory might have registered with the
1319      * file chooser.
1320      *
1321      * @param newAccessory the accessory component to be set
1322      * @beaninfo
1323      *   preferred: true
1324      *       bound: true
1325      * description: Sets the accessory component on the JFileChooser.
1326      */
1327     public void setAccessory(JComponent newAccessory) {
1328         JComponent oldValue = accessory;
1329         accessory = newAccessory;
1330         firePropertyChange(ACCESSORY_CHANGED_PROPERTY, oldValue, accessory);
1331     }
1332 
1333     /**
1334      * Sets the <code>JFileChooser</code> to allow the user to just
1335      * select files, just select
1336      * directories, or select both files and directories.  The default is
1337      * <code>JFilesChooser.FILES_ONLY</code>.
1338      *
1339      * @param mode the type of files to be displayed:
1340      * <ul>
1341      * <li>JFileChooser.FILES_ONLY
1342      * <li>JFileChooser.DIRECTORIES_ONLY
1343      * <li>JFileChooser.FILES_AND_DIRECTORIES
1344      * </ul>
1345      *
1346      * @exception IllegalArgumentException  if <code>mode</code> is an
1347      *                          illegal file selection mode
1348      * @beaninfo
1349      *   preferred: true
1350      *       bound: true
1351      * description: Sets the types of files that the JFileChooser can choose.
1352      *        enum: FILES_ONLY JFileChooser.FILES_ONLY
1353      *              DIRECTORIES_ONLY JFileChooser.DIRECTORIES_ONLY
1354      *              FILES_AND_DIRECTORIES JFileChooser.FILES_AND_DIRECTORIES
1355      *
1356      *
1357      * @see #getFileSelectionMode
1358      */
1359     public void setFileSelectionMode(int mode) {
1360         if(fileSelectionMode == mode) {
1361             return;
1362         }
1363 
1364         checkFileSelectionMode(mode);
1365            int oldValue = fileSelectionMode;
1366            fileSelectionMode = mode;
1367            firePropertyChange(FILE_SELECTION_MODE_CHANGED_PROPERTY, oldValue, fileSelectionMode);
1368     }
1369 
1370     private static void checkFileSelectionMode(int mode) {
1371         if ((mode != FILES_ONLY) && (mode != DIRECTORIES_ONLY)
1372                 && (mode != FILES_AND_DIRECTORIES)) {
1373             throw new IllegalArgumentException(
1374                     "Incorrect Mode for file selection: " + mode);
1375         }
1376     }
1377 
1378     /**
1379      * Returns the current file-selection mode.  The default is
1380      * <code>JFilesChooser.FILES_ONLY</code>.
1381      *
1382      * @return the type of files to be displayed, one of the following:
1383      * <ul>
1384      * <li>JFileChooser.FILES_ONLY
1385      * <li>JFileChooser.DIRECTORIES_ONLY
1386      * <li>JFileChooser.FILES_AND_DIRECTORIES
1387      * </ul>
1388      * @see #setFileSelectionMode
1389      */
1390     public int getFileSelectionMode() {
1391         return fileSelectionMode;
1392     }
1393 
1394     /**
1395      * Convenience call that determines if files are selectable based on the
1396      * current file selection mode.
1397      *
1398      * @return true if files are selectable, false otherwise
1399      * @see #setFileSelectionMode
1400      * @see #getFileSelectionMode
1401      */
1402     public boolean isFileSelectionEnabled() {
1403         return ((fileSelectionMode == FILES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES));
1404     }
1405 
1406     /**
1407      * Convenience call that determines if directories are selectable based
1408      * on the current file selection mode.
1409      *
1410      * @return true if directories are selectable, false otherwise
1411      * @see #setFileSelectionMode
1412      * @see #getFileSelectionMode
1413      */
1414     public boolean isDirectorySelectionEnabled() {
1415         return ((fileSelectionMode == DIRECTORIES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES));
1416     }
1417 
1418     /**
1419      * Sets the file chooser to allow multiple file selections.
1420      *
1421      * @param b true if multiple files may be selected
1422      * @beaninfo
1423      *       bound: true
1424      * description: Sets multiple file selection mode.
1425      *
1426      * @see #isMultiSelectionEnabled
1427      */
1428     public void setMultiSelectionEnabled(boolean b) {
1429         if(multiSelectionEnabled == b) {
1430             return;
1431         }
1432         boolean oldValue = multiSelectionEnabled;
1433         multiSelectionEnabled = b;
1434         firePropertyChange(MULTI_SELECTION_ENABLED_CHANGED_PROPERTY, oldValue, multiSelectionEnabled);
1435     }
1436 
1437     /**
1438      * Returns true if multiple files can be selected.
1439      * @return true if multiple files can be selected
1440      * @see #setMultiSelectionEnabled
1441      */
1442     public boolean isMultiSelectionEnabled() {
1443         return multiSelectionEnabled;
1444     }
1445 
1446 
1447     /**
1448      * Returns true if hidden files are not shown in the file chooser;
1449      * otherwise, returns false.
1450      *
1451      * @return the status of the file hiding property
1452      * @see #setFileHidingEnabled
1453      */
1454     public boolean isFileHidingEnabled() {
1455         return useFileHiding;
1456     }
1457 
1458     /**
1459      * Sets file hiding on or off. If true, hidden files are not shown
1460      * in the file chooser. The job of determining which files are
1461      * shown is done by the <code>FileView</code>.
1462      *
1463      * @beaninfo
1464      *   preferred: true
1465      *       bound: true
1466      * description: Sets file hiding on or off.
1467      *
1468      * @param b the boolean value that determines whether file hiding is
1469      *          turned on
1470      * @see #isFileHidingEnabled
1471      */
1472     public void setFileHidingEnabled(boolean b) {
1473         // Dump showFilesListener since we'll ignore it from now on
1474         if (showFilesListener != null) {
1475             Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, showFilesListener);
1476             showFilesListener = null;
1477         }
1478         boolean oldValue = useFileHiding;
1479         useFileHiding = b;
1480         firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, useFileHiding);
1481     }
1482 
1483     /**
1484      * Sets the current file filter. The file filter is used by the
1485      * file chooser to filter out files from the user's view.
1486      *
1487      * @beaninfo
1488      *   preferred: true
1489      *       bound: true
1490      * description: Sets the File Filter used to filter out files of type.
1491      *
1492      * @param filter the new current file filter to use
1493      * @see #getFileFilter
1494      */
1495     public void setFileFilter(FileFilter filter) {
1496         FileFilter oldValue = fileFilter;
1497         fileFilter = filter;
1498         if (filter != null) {
1499             if (isMultiSelectionEnabled() && selectedFiles != null && selectedFiles.length > 0) {
1500                 Vector<File> fList = new Vector<File>();
1501                 boolean failed = false;
1502                 for (File file : selectedFiles) {
1503                     if (filter.accept(file)) {
1504                         fList.add(file);
1505                     } else {
1506                         failed = true;
1507                     }
1508                 }
1509                 if (failed) {
1510                     setSelectedFiles((fList.size() == 0) ? null : fList.toArray(new File[fList.size()]));
1511                 }
1512             } else if (selectedFile != null && !filter.accept(selectedFile)) {
1513                 setSelectedFile(null);
1514             }
1515         }
1516         firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, oldValue, fileFilter);
1517     }
1518 
1519 
1520     /**
1521      * Returns the currently selected file filter.
1522      *
1523      * @return the current file filter
1524      * @see #setFileFilter
1525      * @see #addChoosableFileFilter
1526      */
1527     public FileFilter getFileFilter() {
1528         return fileFilter;
1529     }
1530 
1531     /**
1532      * Sets the file view to be used to retrieve UI information, such as
1533      * the icon that represents a file or the type description of a file.
1534      *
1535      * @param fileView a {@code FileView} to be used to retrieve UI information
1536      * @beaninfo
1537      *   preferred: true
1538      *       bound: true
1539      * description: Sets the File View used to get file type information.
1540      *
1541      * @see #getFileView
1542      */
1543     public void setFileView(FileView fileView) {
1544         FileView oldValue = this.fileView;
1545         this.fileView = fileView;
1546         firePropertyChange(FILE_VIEW_CHANGED_PROPERTY, oldValue, fileView);
1547     }
1548 
1549     /**
1550      * Returns the current file view.
1551      *
1552      * @return the current file view
1553      * @see #setFileView
1554      */
1555     public FileView getFileView() {
1556         return fileView;
1557     }
1558 
1559     // ******************************
1560     // *****FileView delegation *****
1561     // ******************************
1562 
1563     // NOTE: all of the following methods attempt to delegate
1564     // first to the client set fileView, and if <code>null</code> is returned
1565     // (or there is now client defined fileView) then calls the
1566     // UI's default fileView.
1567 
1568     /**
1569      * Returns the filename.
1570      * @param f the <code>File</code>
1571      * @return the <code>String</code> containing the filename for
1572      *          <code>f</code>
1573      * @see FileView#getName
1574      */
1575     public String getName(File f) {
1576         String filename = null;
1577         if(f != null) {
1578             if(getFileView() != null) {
1579                 filename = getFileView().getName(f);
1580             }
1581 
1582             FileView uiFileView = getUI().getFileView(this);
1583 
1584             if(filename == null && uiFileView != null) {
1585                 filename = uiFileView.getName(f);
1586             }
1587         }
1588         return filename;
1589     }
1590 
1591     /**
1592      * Returns the file description.
1593      * @param f the <code>File</code>
1594      * @return the <code>String</code> containing the file description for
1595      *          <code>f</code>
1596      * @see FileView#getDescription
1597      */
1598     public String getDescription(File f) {
1599         String description = null;
1600         if(f != null) {
1601             if(getFileView() != null) {
1602                 description = getFileView().getDescription(f);
1603             }
1604 
1605             FileView uiFileView = getUI().getFileView(this);
1606 
1607             if(description == null && uiFileView != null) {
1608                 description = uiFileView.getDescription(f);
1609             }
1610         }
1611         return description;
1612     }
1613 
1614     /**
1615      * Returns the file type.
1616      * @param f the <code>File</code>
1617      * @return the <code>String</code> containing the file type description for
1618      *          <code>f</code>
1619      * @see FileView#getTypeDescription
1620      */
1621     public String getTypeDescription(File f) {
1622         String typeDescription = null;
1623         if(f != null) {
1624             if(getFileView() != null) {
1625                 typeDescription = getFileView().getTypeDescription(f);
1626             }
1627 
1628             FileView uiFileView = getUI().getFileView(this);
1629 
1630             if(typeDescription == null && uiFileView != null) {
1631                 typeDescription = uiFileView.getTypeDescription(f);
1632             }
1633         }
1634         return typeDescription;
1635     }
1636 
1637     /**
1638      * Returns the icon for this file or type of file, depending
1639      * on the system.
1640      * @param f the <code>File</code>
1641      * @return the <code>Icon</code> for this file, or type of file
1642      * @see FileView#getIcon
1643      */
1644     public Icon getIcon(File f) {
1645         Icon icon = null;
1646         if (f != null) {
1647             if(getFileView() != null) {
1648                 icon = getFileView().getIcon(f);
1649             }
1650 
1651             FileView uiFileView = getUI().getFileView(this);
1652 
1653             if(icon == null && uiFileView != null) {
1654                 icon = uiFileView.getIcon(f);
1655             }
1656         }
1657         return icon;
1658     }
1659 
1660     /**
1661      * Returns true if the file (directory) can be visited.
1662      * Returns false if the directory cannot be traversed.
1663      * @param f the <code>File</code>
1664      * @return true if the file/directory can be traversed, otherwise false
1665      * @see FileView#isTraversable
1666      */
1667     public boolean isTraversable(File f) {
1668         Boolean traversable = null;
1669         if (f != null) {
1670             if (getFileView() != null) {
1671                 traversable = getFileView().isTraversable(f);
1672             }
1673 
1674             FileView uiFileView = getUI().getFileView(this);
1675 
1676             if (traversable == null && uiFileView != null) {
1677                 traversable = uiFileView.isTraversable(f);
1678             }
1679             if (traversable == null) {
1680                 traversable = getFileSystemView().isTraversable(f);
1681             }
1682         }
1683         return (traversable != null && traversable.booleanValue());
1684     }
1685 
1686     /**
1687      * Returns true if the file should be displayed.
1688      * @param f the <code>File</code>
1689      * @return true if the file should be displayed, otherwise false
1690      * @see FileFilter#accept
1691      */
1692     public boolean accept(File f) {
1693         boolean shown = true;
1694         if(f != null && fileFilter != null) {
1695             shown = fileFilter.accept(f);
1696         }
1697         return shown;
1698     }
1699 
1700     /**
1701      * Sets the file system view that the <code>JFileChooser</code> uses for
1702      * accessing and creating file system resources, such as finding
1703      * the floppy drive and getting a list of root drives.
1704      * @param fsv  the new <code>FileSystemView</code>
1705      *
1706      * @beaninfo
1707      *      expert: true
1708      *       bound: true
1709      * description: Sets the FileSytemView used to get filesystem information.
1710      *
1711      * @see FileSystemView
1712      */
1713     public void setFileSystemView(FileSystemView fsv) {
1714         FileSystemView oldValue = fileSystemView;
1715         fileSystemView = fsv;
1716         firePropertyChange(FILE_SYSTEM_VIEW_CHANGED_PROPERTY, oldValue, fileSystemView);
1717     }
1718 
1719     /**
1720      * Returns the file system view.
1721      * @return the <code>FileSystemView</code> object
1722      * @see #setFileSystemView
1723      */
1724     public FileSystemView getFileSystemView() {
1725         return fileSystemView;
1726     }
1727 
1728     // **************************
1729     // ***** Event Handling *****
1730     // **************************
1731 
1732     /**
1733      * Called by the UI when the user hits the Approve button
1734      * (labeled "Open" or "Save", by default). This can also be
1735      * called by the programmer.
1736      * This method causes an action event to fire
1737      * with the command string equal to
1738      * <code>APPROVE_SELECTION</code>.
1739      *
1740      * @see #APPROVE_SELECTION
1741      */
1742     public void approveSelection() {
1743         returnValue = APPROVE_OPTION;
1744         if(dialog != null) {
1745             dialog.setVisible(false);
1746         }
1747         fireActionPerformed(APPROVE_SELECTION);
1748     }
1749 
1750     /**
1751      * Called by the UI when the user chooses the Cancel button.
1752      * This can also be called by the programmer.
1753      * This method causes an action event to fire
1754      * with the command string equal to
1755      * <code>CANCEL_SELECTION</code>.
1756      *
1757      * @see #CANCEL_SELECTION
1758      */
1759     public void cancelSelection() {
1760         returnValue = CANCEL_OPTION;
1761         if(dialog != null) {
1762             dialog.setVisible(false);
1763         }
1764         fireActionPerformed(CANCEL_SELECTION);
1765     }
1766 
1767     /**
1768      * Adds an <code>ActionListener</code> to the file chooser.
1769      *
1770      * @param l  the listener to be added
1771      *
1772      * @see #approveSelection
1773      * @see #cancelSelection
1774      */
1775     public void addActionListener(ActionListener l) {
1776         listenerList.add(ActionListener.class, l);
1777     }
1778 
1779     /**
1780      * Removes an <code>ActionListener</code> from the file chooser.
1781      *
1782      * @param l  the listener to be removed
1783      *
1784      * @see #addActionListener
1785      */
1786     public void removeActionListener(ActionListener l) {
1787         listenerList.remove(ActionListener.class, l);
1788     }
1789 
1790     /**
1791      * Returns an array of all the action listeners
1792      * registered on this file chooser.
1793      *
1794      * @return all of this file chooser's <code>ActionListener</code>s
1795      *         or an empty
1796      *         array if no action listeners are currently registered
1797      *
1798      * @see #addActionListener
1799      * @see #removeActionListener
1800      *
1801      * @since 1.4
1802      */
1803     public ActionListener[] getActionListeners() {
1804         return listenerList.getListeners(ActionListener.class);
1805     }
1806 
1807     /**
1808      * Notifies all listeners that have registered interest for
1809      * notification on this event type. The event instance
1810      * is lazily created using the <code>command</code> parameter.
1811      *
1812      * @param command a string that may specify a command associated with
1813      *                the event
1814      * @see EventListenerList
1815      */
1816     protected void fireActionPerformed(String command) {
1817         // Guaranteed to return a non-null array
1818         Object[] listeners = listenerList.getListenerList();
1819         long mostRecentEventTime = EventQueue.getMostRecentEventTime();
1820         int modifiers = 0;
1821         AWTEvent currentEvent = EventQueue.getCurrentEvent();
1822         if (currentEvent instanceof InputEvent) {
1823             modifiers = ((InputEvent)currentEvent).getModifiers();
1824         } else if (currentEvent instanceof ActionEvent) {
1825             modifiers = ((ActionEvent)currentEvent).getModifiers();
1826         }
1827         ActionEvent e = null;
1828         // Process the listeners last to first, notifying
1829         // those that are interested in this event
1830         for (int i = listeners.length-2; i>=0; i-=2) {
1831             if (listeners[i]==ActionListener.class) {
1832                 // Lazily create the event:
1833                 if (e == null) {
1834                     e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
1835                                         command, mostRecentEventTime,
1836                                         modifiers);
1837                 }
1838                 ((ActionListener)listeners[i+1]).actionPerformed(e);
1839             }
1840         }
1841     }
1842 
1843     private static class WeakPCL implements PropertyChangeListener {
1844         WeakReference<JFileChooser> jfcRef;
1845 
1846         public WeakPCL(JFileChooser jfc) {
1847             jfcRef = new WeakReference<JFileChooser>(jfc);
1848         }
1849         public void propertyChange(PropertyChangeEvent ev) {
1850             assert ev.getPropertyName().equals(SHOW_HIDDEN_PROP);
1851             JFileChooser jfc = jfcRef.get();
1852             if (jfc == null) {
1853                 // Our JFileChooser is no longer around, so we no longer need to
1854                 // listen for PropertyChangeEvents.
1855                 Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, this);
1856             }
1857             else {
1858                 boolean oldValue = jfc.useFileHiding;
1859                 jfc.useFileHiding = !((Boolean)ev.getNewValue()).booleanValue();
1860                 jfc.firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, jfc.useFileHiding);
1861             }
1862         }
1863     }
1864 
1865     // *********************************
1866     // ***** Pluggable L&F methods *****
1867     // *********************************
1868 
1869     /**
1870      * Resets the UI property to a value from the current look and feel.
1871      *
1872      * @see JComponent#updateUI
1873      */
1874     public void updateUI() {
1875         if (isAcceptAllFileFilterUsed()) {
1876             removeChoosableFileFilter(getAcceptAllFileFilter());
1877         }
1878         FileChooserUI ui = ((FileChooserUI)UIManager.getUI(this));
1879         if (fileSystemView == null) {
1880             // We were probably deserialized
1881             setFileSystemView(FileSystemView.getFileSystemView());
1882         }
1883         setUI(ui);
1884 
1885         if(isAcceptAllFileFilterUsed()) {
1886             addChoosableFileFilter(getAcceptAllFileFilter());
1887         }
1888     }
1889 
1890     /**
1891      * Returns a string that specifies the name of the L&amp;F class
1892      * that renders this component.
1893      *
1894      * @return the string "FileChooserUI"
1895      * @see JComponent#getUIClassID
1896      * @see UIDefaults#getUI
1897      * @beaninfo
1898      *        expert: true
1899      *   description: A string that specifies the name of the L&amp;F class.
1900      */
1901     public String getUIClassID() {
1902         return uiClassID;
1903     }
1904 
1905     /**
1906      * Gets the UI object which implements the L&amp;F for this component.
1907      *
1908      * @return the FileChooserUI object that implements the FileChooserUI L&amp;F
1909      */
1910     public FileChooserUI getUI() {
1911         return (FileChooserUI) ui;
1912     }
1913 
1914     /**
1915      * See <code>readObject</code> and <code>writeObject</code> in
1916      * <code>JComponent</code> for more
1917      * information about serialization in Swing.
1918      */
1919     private void readObject(java.io.ObjectInputStream in)
1920             throws IOException, ClassNotFoundException {
1921         ObjectInputStream.GetField f = in.readFields();
1922 
1923         dialogTitle = (String) f.get("dialogTitle", null);
1924         approveButtonText = (String) f.get("approveButtonText", null);
1925         approveButtonToolTipText =
1926                 (String) f.get("approveButtonToolTipText", null);
1927         approveButtonMnemonic = f.get("approveButtonMnemonic", 0);
1928         @SuppressWarnings("unchecked")
1929         Vector<FileFilter> newFilters = (Vector<FileFilter>) f.get("filters", null);
1930         if (newFilters == null) {
1931             throw new InvalidObjectException("Null filters");
1932         }
1933         filters = newFilters;
1934         dialog = (JDialog) f.get("dialog", null);
1935         int newDialogType = f.get("dialogType", OPEN_DIALOG);
1936         checkDialogType(newDialogType);
1937         dialogType = newDialogType;
1938         returnValue = f.get("returnValue", 0);
1939         accessory = (JComponent) f.get("accessory", null);
1940         fileView = (FileView) f.get("fileView", null);
1941         controlsShown = f.get("controlsShown", false);
1942         useFileHiding = f.get("useFileHiding", false);
1943         int newFileSelectionMode = f.get("fileSelectionMode", FILES_ONLY);
1944         checkFileSelectionMode(newFileSelectionMode);
1945         fileSelectionMode = newFileSelectionMode;
1946         multiSelectionEnabled = f.get("multiSelectionEnabled", false);
1947         useAcceptAllFileFilter = f.get("useAcceptAllFileFilter", false);
1948         boolean newDragEnabled = f.get("dragEnabled", false);
1949         checkDragEnabled(newDragEnabled);
1950         dragEnabled = newDragEnabled;
1951         fileFilter = (FileFilter) f.get("fileFilter", null);
1952         fileSystemView = (FileSystemView) f.get("fileSystemView", null);
1953         currentDirectory = (File) f.get("currentDirectory", null);
1954         selectedFile = (File) f.get("selectedFile", null);
1955         selectedFiles = (File[]) f.get("selectedFiles", null);
1956         accessibleContext = (AccessibleContext) f.get("accessibleContext", null);
1957 
1958         installShowFilesListener();
1959     }
1960 
1961     /**
1962      * See <code>readObject</code> and <code>writeObject</code> in
1963      * <code>JComponent</code> for more
1964      * information about serialization in Swing.
1965      */
1966     private void writeObject(ObjectOutputStream s) throws IOException {
1967         FileSystemView fsv = null;
1968 
1969         if (isAcceptAllFileFilterUsed()) {
1970             //The AcceptAllFileFilter is UI specific, it will be reset by
1971             //updateUI() after deserialization
1972             removeChoosableFileFilter(getAcceptAllFileFilter());
1973         }
1974         if (fileSystemView.equals(FileSystemView.getFileSystemView())) {
1975             //The default FileSystemView is platform specific, it will be
1976             //reset by updateUI() after deserialization
1977             fsv = fileSystemView;
1978             fileSystemView = null;
1979         }
1980         s.defaultWriteObject();
1981         if (fsv != null) {
1982             fileSystemView = fsv;
1983         }
1984         if (isAcceptAllFileFilterUsed()) {
1985             addChoosableFileFilter(getAcceptAllFileFilter());
1986         }
1987         if (getUIClassID().equals(uiClassID)) {
1988             byte count = JComponent.getWriteObjCounter(this);
1989             JComponent.setWriteObjCounter(this, --count);
1990             if (count == 0 && ui != null) {
1991                 ui.installUI(this);
1992             }
1993         }
1994     }
1995 
1996 
1997     /**
1998      * Returns a string representation of this <code>JFileChooser</code>.
1999      * This method
2000      * is intended to be used only for debugging purposes, and the
2001      * content and format of the returned string may vary between
2002      * implementations. The returned string may be empty but may not
2003      * be <code>null</code>.
2004      *
2005      * @return  a string representation of this <code>JFileChooser</code>
2006      */
2007     protected String paramString() {
2008         String approveButtonTextString = (approveButtonText != null ?
2009                                           approveButtonText: "");
2010         String dialogTitleString = (dialogTitle != null ?
2011                                     dialogTitle: "");
2012         String dialogTypeString;
2013         if (dialogType == OPEN_DIALOG) {
2014             dialogTypeString = "OPEN_DIALOG";
2015         } else if (dialogType == SAVE_DIALOG) {
2016             dialogTypeString = "SAVE_DIALOG";
2017         } else if (dialogType == CUSTOM_DIALOG) {
2018             dialogTypeString = "CUSTOM_DIALOG";
2019         } else dialogTypeString = "";
2020         String returnValueString;
2021         if (returnValue == CANCEL_OPTION) {
2022             returnValueString = "CANCEL_OPTION";
2023         } else if (returnValue == APPROVE_OPTION) {
2024             returnValueString = "APPROVE_OPTION";
2025         } else if (returnValue == ERROR_OPTION) {
2026             returnValueString = "ERROR_OPTION";
2027         } else returnValueString = "";
2028         String useFileHidingString = (useFileHiding ?
2029                                     "true" : "false");
2030         String fileSelectionModeString;
2031         if (fileSelectionMode == FILES_ONLY) {
2032             fileSelectionModeString = "FILES_ONLY";
2033         } else if (fileSelectionMode == DIRECTORIES_ONLY) {
2034             fileSelectionModeString = "DIRECTORIES_ONLY";
2035         } else if (fileSelectionMode == FILES_AND_DIRECTORIES) {
2036             fileSelectionModeString = "FILES_AND_DIRECTORIES";
2037         } else fileSelectionModeString = "";
2038         String currentDirectoryString = (currentDirectory != null ?
2039                                          currentDirectory.toString() : "");
2040         String selectedFileString = (selectedFile != null ?
2041                                      selectedFile.toString() : "");
2042 
2043         return super.paramString() +
2044         ",approveButtonText=" + approveButtonTextString +
2045         ",currentDirectory=" + currentDirectoryString +
2046         ",dialogTitle=" + dialogTitleString +
2047         ",dialogType=" + dialogTypeString +
2048         ",fileSelectionMode=" + fileSelectionModeString +
2049         ",returnValue=" + returnValueString +
2050         ",selectedFile=" + selectedFileString +
2051         ",useFileHiding=" + useFileHidingString;
2052     }
2053 
2054 /////////////////
2055 // Accessibility support
2056 ////////////////
2057 
2058     /**
2059      * {@code AccessibleContext} associated with this {@code JFileChooser}
2060      */
2061     protected AccessibleContext accessibleContext = null;
2062 
2063     /**
2064      * Gets the AccessibleContext associated with this JFileChooser.
2065      * For file choosers, the AccessibleContext takes the form of an
2066      * AccessibleJFileChooser.
2067      * A new AccessibleJFileChooser instance is created if necessary.
2068      *
2069      * @return an AccessibleJFileChooser that serves as the
2070      *         AccessibleContext of this JFileChooser
2071      */
2072     public AccessibleContext getAccessibleContext() {
2073         if (accessibleContext == null) {
2074             accessibleContext = new AccessibleJFileChooser();
2075         }
2076         return accessibleContext;
2077     }
2078 
2079     /**
2080      * This class implements accessibility support for the
2081      * <code>JFileChooser</code> class.  It provides an implementation of the
2082      * Java Accessibility API appropriate to file chooser user-interface
2083      * elements.
2084      */
2085     @SuppressWarnings("serial") // Superclass is not serializable across versions
2086     protected class AccessibleJFileChooser extends AccessibleJComponent {
2087 
2088         /**
2089          * Gets the role of this object.
2090          *
2091          * @return an instance of AccessibleRole describing the role of the
2092          * object
2093          * @see AccessibleRole
2094          */
2095         public AccessibleRole getAccessibleRole() {
2096             return AccessibleRole.FILE_CHOOSER;
2097         }
2098 
2099     } // inner class AccessibleJFileChooser
2100 
2101 }