001/* JFileChooser.java --
002   Copyright (C) 2002, 2004, 2005, 2006,  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038package javax.swing;
039
040import gnu.java.lang.CPStringBuilder;
041
042import java.awt.Component;
043import java.awt.Frame;
044import java.awt.GraphicsEnvironment;
045import java.awt.HeadlessException;
046import java.awt.event.ActionEvent;
047import java.awt.event.ActionListener;
048import java.awt.event.WindowEvent;
049import java.awt.event.WindowAdapter;
050import java.beans.PropertyChangeEvent;
051import java.io.File;
052import java.util.ArrayList;
053
054import javax.accessibility.Accessible;
055import javax.accessibility.AccessibleContext;
056import javax.accessibility.AccessibleRole;
057import javax.swing.filechooser.FileFilter;
058import javax.swing.filechooser.FileSystemView;
059import javax.swing.filechooser.FileView;
060import javax.swing.plaf.FileChooserUI;
061
062
063/**
064 * A component that provides the user a dialog box to browse through a
065 * filesystem and choose one or more files or directories.
066 *
067 * A JFileChooser can be configured to filter the displayed file list
068 * by adding a {@link FileFilter} instance using
069 * {@link #addChoosableFileFilter(FileFilter)}. Additional components can
070 * be embedded in the file chooser using {@link #setAccessory(JComponent)}.
071 * The JFileChooser properties also provide mechanisms to customize the
072 * behaviour of the file chooser.
073 *
074 * @author Kim Ho (kho@luxsci.net)
075 */
076public class JFileChooser extends JComponent implements Accessible
077{
078  private static final long serialVersionUID = 3162921138695327837L;
079
080  /** 
081   * A dialog type for selecting a file to open. 
082   * @see #setDialogType(int)
083   */
084  public static final int OPEN_DIALOG = 0;
085
086  /** 
087   * A dialog type for selecting a file to save.  
088   * @see #setDialogType(int)
089   */
090  public static final int SAVE_DIALOG = 1;
091
092  /** 
093   * A dialog type for some custom purpose.
094   * @see #setDialogType(int)
095   */
096  public static final int CUSTOM_DIALOG = 2;
097
098  /** 
099   * A return value indicating the file chooser has been closed by cancelling.
100   * 
101   * @see #showOpenDialog(Component)
102   * @see #showSaveDialog(Component) 
103   */
104  public static final int CANCEL_OPTION = 1;
105
106  /** 
107   * A return value indicating the file chooser has been closed by approving
108   * the selection.
109   * @see #showOpenDialog(Component)
110   * @see #showSaveDialog(Component) 
111   */
112  public static final int APPROVE_OPTION = 0;
113
114  /** 
115   * A return value indicating the file chooser has been closed by some error.
116   * @see #showOpenDialog(Component)
117   * @see #showSaveDialog(Component) 
118   */
119  public static final int ERROR_OPTION = -1;
120
121  /** 
122   * A selection mode constant indicating acceptance of files only.
123   * @see #setFileSelectionMode(int)
124   */
125  public static final int FILES_ONLY = 0;
126
127  /** 
128   * A selection mode constant indicating acceptance of directories only. 
129   * @see #setFileSelectionMode(int)
130   */
131  public static final int DIRECTORIES_ONLY = 1;
132
133  /** 
134   * A selection mode constant indicating acceptance of files and directories.
135   * @see #setFileSelectionMode(int)
136   */
137  public static final int FILES_AND_DIRECTORIES = 2;
138
139  /** 
140   * Action command string for cancelling the current selection.
141   * @see #cancelSelection()
142   */
143  public static final String CANCEL_SELECTION = "CancelSelection";
144
145  /** 
146   * Action command string for approving the current selection.
147   * @see #cancelSelection()
148   */
149  public static final String APPROVE_SELECTION = "ApproveSelection";
150
151  /**
152   * The name of the property for the approve button text.
153   * @see #setApproveButtonText(String) 
154   */
155  public static final String APPROVE_BUTTON_TEXT_CHANGED_PROPERTY =
156    "ApproveButtonTextChangedProperty";
157
158  /**
159   * The name of the property for the approve button tool tip text.
160   * @see #setApproveButtonToolTipText(String)
161   */
162  public static final String APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY =
163    "ApproveButtonToolTipTextChangedProperty";
164
165  /**
166   * The name of the property for the approve button mnemonic.
167   * @see #setApproveButtonMnemonic(int)
168   */
169  public static final String APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY =
170    "ApproveButtonMnemonicChangedProperty";
171
172  /**
173   * The name of the property for control button visibility.
174   * @see #setControlButtonsAreShown(boolean)
175   */
176  public static final String CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY =
177    "ControlButtonsAreShownChangedProperty";
178
179  /**
180   * The name of the property for the current directory.
181   * @see #setCurrentDirectory(File)  
182   */
183  public static final String DIRECTORY_CHANGED_PROPERTY = "directoryChanged";
184
185  /**
186   * The name of the property for the selected file.
187   * @see #setSelectedFile(File)
188   */
189  public static final String SELECTED_FILE_CHANGED_PROPERTY =
190    "SelectedFileChangedProperty";
191
192  /**
193   * The name of the property for the selected files.
194   * @see #setSelectedFiles(File[])
195   */
196  public static final String SELECTED_FILES_CHANGED_PROPERTY =
197    "SelectedFilesChangedProperty";
198
199  /** 
200   * The name of the property for multi-selection.
201   * @see #setMultiSelectionEnabled(boolean) 
202   */
203  public static final String MULTI_SELECTION_ENABLED_CHANGED_PROPERTY =
204    "MultiSelectionEnabledChangedProperty";
205
206  /**
207   * The name of the 'file system view' property.
208   * @see #setFileSystemView(FileSystemView) 
209   */
210  public static final String FILE_SYSTEM_VIEW_CHANGED_PROPERTY =
211    "FileSystemViewChanged";
212
213  /**
214   * The name of the 'file view' property.
215   * @see #setFileView(FileView) 
216   */
217  public static final String FILE_VIEW_CHANGED_PROPERTY = "fileViewChanged";
218
219  /**
220   * The name of the 'file hiding enabled' property.
221   * @see #setFileHidingEnabled(boolean)
222   */
223  public static final String FILE_HIDING_CHANGED_PROPERTY =
224    "FileHidingChanged";
225
226  /**
227   * The name of the 'file filter' property.
228   * @see #setFileFilter(FileFilter)
229   */
230  public static final String FILE_FILTER_CHANGED_PROPERTY =
231    "fileFilterChanged";
232
233  /**
234   * The name of the 'file selection mode' property.
235   * @see #setFileSelectionMode(int)
236   */
237  public static final String FILE_SELECTION_MODE_CHANGED_PROPERTY =
238    "fileSelectionChanged";
239
240  /**
241   * The name of the 'accessory' property.
242   * @see #setAccessory(JComponent)
243   */
244  public static final String ACCESSORY_CHANGED_PROPERTY =
245    "AccessoryChangedProperty";
246
247  /**
248   * The name of the 'accept all file filter used' property.
249   * @see #setAcceptAllFileFilterUsed(boolean)
250   */
251  public static final String ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY =
252    "acceptAllFileFilterUsedChanged";
253
254  /**
255   * The name of the 'dialog title' property.
256   * @see #setDialogTitle(String)
257   */
258  public static final String DIALOG_TITLE_CHANGED_PROPERTY =
259    "DialogTitleChangedProperty";
260
261  /**
262   * The name of the 'dialog type' property.
263   * @see #setDialogType(int)
264   */
265  public static final String DIALOG_TYPE_CHANGED_PROPERTY =
266    "DialogTypeChangedProperty";
267
268  /**
269   * The name of the 'choosable file filters' property.
270   * @see #addChoosableFileFilter(FileFilter)
271   */
272  public static final String CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY =
273    "ChoosableFileFilterChangedProperty";
274
275  /** 
276   * The accessible context. 
277   * @see #getAccessibleContext()
278   */
279  protected AccessibleContext accessibleContext;
280
281  /** 
282   * The file system view.
283   * @see #setFileSystemView(FileSystemView)
284   */
285  private FileSystemView fsv;
286
287  /**
288   * The accessory component.
289   * @see #setAccessory(JComponent)
290   */
291  private JComponent accessory;
292
293  /**
294   * The approve button mnemonic.
295   * @see #setApproveButtonMnemonic(int)
296   */
297  private int approveButtonMnemonic = 0;
298
299  /**
300   * The approve button text.
301   * @see #setApproveButtonText(String)
302   */
303  private String approveButtonText;
304
305  /**
306   * The approve button tool tip text.
307   * @see #setApproveButtonToolTipText(String)
308   */
309  private String approveButtonToolTipText;
310
311  /**
312   * The choosable file filters.
313   * @see #addChoosableFileFilter(FileFilter)
314   */
315  private ArrayList choosableFilters = new ArrayList();
316
317  /**
318   * A flag controlling whether the accept all file filter is used.
319   * @see #setAcceptAllFileFilterUsed(boolean)
320   */
321  private boolean isAcceptAll = true;
322
323  /**
324   * The dialog title.
325   * @see #setDialogTitle(String)
326   */
327  private String dialogTitle;
328
329  /**
330   * The dialog type.
331   * @see #setDialogType(int)
332   */
333  private int dialogType = OPEN_DIALOG;
334
335  /**
336   * The return value for the dialog.
337   * @see #showOpenDialog(Component)
338   * @see #showSaveDialog(Component)
339   */
340  private int retval = ERROR_OPTION;
341
342  /**
343   * A flag indicating whether the file chooser allows multiple selection.
344   * @see #isMultiSelectionEnabled()
345   */
346  private boolean multiSelection = false;
347
348  /**
349   * A flag indicating whether file hiding is enabled.
350   * @see #isFileHidingEnabled()
351   */
352  private boolean fileHiding = true;
353
354  /**
355   * The file selection mode.
356   * @see #setFileSelectionMode(int) 
357   */
358  private int fileSelectionMode = FILES_ONLY;
359
360  /** 
361   * The file view.
362   * @see #setFileView(FileView)
363   */
364  private FileView fv = null;
365
366  /** 
367   * A flag controlling whether or not the control buttons are visible. 
368   * @see #setControlButtonsAreShown(boolean) 
369   */
370  private boolean controlButtonsShown = true;
371
372  /** 
373   * The current directory. 
374   * @see #setCurrentDirectory(File)
375   */
376  private File currentDir = null;
377
378  /** 
379   * The current file filter.
380   * @see #setFileFilter(FileFilter)
381   */
382  private FileFilter currentFilter = null;
383
384  /** 
385   * An array of selected files.
386   * @see #setSelectedFiles(File[]) 
387   */
388  private File[] selectedFiles;
389
390  /** 
391   * The selected file. 
392   * @see #setSelectedFile(File)
393   */
394  private File selectedFile;
395  
396  /**
397   * The drag enabled property.
398   * @see #setDragEnabled(boolean)
399   * @see #getDragEnabled()
400   */
401  private boolean dragEnabled;
402
403  /**
404   * Creates a new <code>JFileChooser</code> object.
405   */
406  public JFileChooser()
407  {
408    setup(null);
409    setCurrentDirectory(null);
410  }
411
412  /**
413   * Creates a new <code>JFileChooser</code> object.
414   *
415   * @param currentDirectoryPath the directory that should initially be
416   *        shown in the filechooser (if <code>null</code>, the user's home 
417   *        directory is used).
418   */
419  public JFileChooser(String currentDirectoryPath)
420  {
421    this(currentDirectoryPath, null);
422  }
423
424  /**
425   * Creates a new <code>JFileChooser</code> object with the specified 
426   * directory and {@link FileSystemView}.
427   *
428   * @param currentDirectoryPath  the directory that should initially be
429   *        shown in the filechooser (if <code>null</code>, the user's home 
430   *        directory is used).
431   * @param fsv  the file system view (if <code>null</code>, the default file
432   *             system view is used).
433   */
434  public JFileChooser(String currentDirectoryPath, FileSystemView fsv)
435  {
436    setup(fsv);
437    File dir = null;
438    if (currentDirectoryPath != null)
439      dir = getFileSystemView().createFileObject(currentDirectoryPath);
440    setCurrentDirectory(dir);
441  }
442
443  /**
444   * Creates a new <code>JFileChooser</code> object.
445   *
446   * @param currentDirectory  the directory that should initially be
447   *        shown in the filechooser (if <code>null</code>, the user's home 
448   *        directory is used).
449   */
450  public JFileChooser(File currentDirectory)
451  {
452    setup(null);
453    setCurrentDirectory(currentDirectory);
454  }
455
456  /**
457   * Creates a new <code>JFileChooser</code> object.
458   *
459   * @param fsv  the file system view (if <code>null</code>, the default file
460   *             system view is used).
461   */
462  public JFileChooser(FileSystemView fsv)
463  {
464    setup(fsv);
465    setCurrentDirectory(null);
466  }
467
468  /**
469   * Creates a new <code>JFileChooser</code> object.
470   *
471   * @param currentDirectory  the directory that should initially be
472   *        shown in the filechooser (if <code>null</code>, the user's home 
473   *        directory is used).
474   * @param fsv  the file system view (if <code>null</code>, the default file
475   *             system view is used).
476   */
477  public JFileChooser(File currentDirectory, FileSystemView fsv)
478  {
479    setup(fsv);
480    setCurrentDirectory(currentDirectory);
481  }
482
483  /**
484   * Sets up the file chooser.  This method is called by all the constructors.
485   *
486   * @param view  the file system view (if <code>null</code>, the default file
487   *              system view is used).
488   * 
489   * @see FileSystemView#getFileSystemView()
490   */
491  protected void setup(FileSystemView view)
492  {
493    if (view == null)
494      view = FileSystemView.getFileSystemView();
495    setFileSystemView(view);
496    updateUI();
497  }
498
499  /**
500   * Sets the dragEnabled property, this disables/enables automatic drag
501   * handling (drag and drop) on this component. The default value of the
502   * dragEnabled property is false. 
503   * 
504   * Some look and feels might not support automatic drag and drop; they
505   * will ignore this property.
506   * 
507   * @param b - the new dragEnabled value
508   */
509  public void setDragEnabled(boolean b)
510  {
511    if (b && GraphicsEnvironment.isHeadless())
512      throw new HeadlessException();
513    
514    dragEnabled = b;
515  }
516
517  /**
518   * Returns true if dragging is enabled.
519   *
520   * @return true if dragging is enabled.
521   */
522  public boolean getDragEnabled()
523  {
524    return dragEnabled;
525  }
526
527  /**
528   * Returns the selected file, if there is one.
529   *
530   * @return The selected file (possibly <code>null</code>).
531   * 
532   * @see #setSelectedFile(File)
533   */
534  public File getSelectedFile()
535  {
536    return selectedFile;
537  }
538
539  /**
540   * Sets the selected file and sends a {@link PropertyChangeEvent} to all
541   * registered listeners.  The property name is 
542   * {@link #SELECTED_FILE_CHANGED_PROPERTY}.
543   *
544   * @param file  the file (<code>null</code> permitted).
545   */
546  public void setSelectedFile(File file)
547  {
548    if (selectedFile == null || !selectedFile.equals(file))
549      {
550        File old = selectedFile;
551        selectedFile = file;
552        firePropertyChange(SELECTED_FILE_CHANGED_PROPERTY, old, selectedFile);
553      }
554  }
555
556  /**
557   * Returns the selected file or files in an array.  If no files are selected,
558   * an empty array is returned.
559   *
560   * @return An array of the selected files (possibly empty).
561   */
562  public File[] getSelectedFiles()
563  {
564    if (selectedFiles != null)
565      return selectedFiles;
566    if (selectedFile != null)
567      return new File[] { selectedFile };
568    return new File[0];
569  }
570
571  /**
572   * Sets the selected files and sends a {@link PropertyChangeEvent} (with the 
573   * name {@link #SELECTED_FILES_CHANGED_PROPERTY}) to all registered 
574   * listeners.  
575   *
576   * @param selectedFiles  the selected files (<code>null</code> permitted).
577   */
578  public void setSelectedFiles(File[] selectedFiles)
579  {
580    if (selectedFiles == null)
581      selectedFiles = new File[0];
582    if (selectedFiles.length > 0)
583      setSelectedFile(selectedFiles[0]);
584    else
585      setSelectedFile(null);
586    if (this.selectedFiles != selectedFiles)
587      {
588        File[] old = this.selectedFiles;
589        this.selectedFiles = selectedFiles;
590        firePropertyChange(SELECTED_FILES_CHANGED_PROPERTY, old, selectedFiles);
591      }
592
593  }
594
595  /**
596   * Returns the current directory.
597   *
598   * @return The current directory.
599   */
600  public File getCurrentDirectory()
601  {
602    return currentDir;
603  }
604
605  /**
606   * Sets the current directory and fires a {@link PropertyChangeEvent} (with 
607   * the property name {@link #DIRECTORY_CHANGED_PROPERTY}) to all registered 
608   * listeners.  If <code>dir</code> is <code>null</code>, the current 
609   * directory is set to the default directory returned by the file system
610   * view.
611   *
612   * @param dir  the new directory (<code>null</code> permitted).
613   * 
614   * @see FileSystemView#getDefaultDirectory()
615   */
616  public void setCurrentDirectory(File dir)
617  {
618    if (currentDir != dir || dir == null)
619      {
620        if (dir == null)
621          dir = fsv.getDefaultDirectory();
622
623        File old = currentDir;
624        currentDir = dir;
625        firePropertyChange(DIRECTORY_CHANGED_PROPERTY, old, currentDir);
626      }
627  }
628
629  /**
630   * Called by the UI delegate when the parent directory is changed.
631   */
632  public void changeToParentDirectory()
633  {
634    setCurrentDirectory(fsv.getParentDirectory(currentDir));
635  }
636
637  /**
638   * Rescans the current directory (this is handled by the UI delegate).
639   */
640  public void rescanCurrentDirectory()
641  {
642    getUI().rescanCurrentDirectory(this);
643  }
644
645  /**
646   * Ensures the the specified file is visible (this is handled by the 
647   * UI delegate).
648   *
649   * @param f  the file.
650   */
651  public void ensureFileIsVisible(File f)
652  {
653    getUI().ensureFileIsVisible(this, f);
654  }
655
656  /**
657   * Displays the file chooser in a modal dialog using the 
658   * {@link #OPEN_DIALOG} type.
659   *
660   * @param parent  the parent component.
661   *
662   * @return A return value indicating how the dialog was closed (one of 
663   *         {@link #APPROVE_OPTION}, {@link #CANCEL_OPTION} and 
664   *         {@link #ERROR_OPTION}).
665   *
666   * @throws HeadlessException DOCUMENT ME!
667   */
668  public int showOpenDialog(Component parent) throws HeadlessException
669  {
670    JDialog d = createDialog(parent);
671
672    // FIXME: Remove when we get ancestor property
673    d.setTitle("Open");
674    setDialogType(OPEN_DIALOG);
675
676    retval = ERROR_OPTION;
677
678    d.pack();
679    d.show();
680    return retval;
681  }
682
683  /**
684   * Displays the file chooser in a modal dialog using the 
685   * {@link #SAVE_DIALOG} type.
686   *
687   * @param parent  the parent component.
688   *
689   * @return A return value indicating how the dialog was closed (one of 
690   *         {@link #APPROVE_OPTION}, {@link #CANCEL_OPTION} and 
691   *         {@link #ERROR_OPTION}).
692   *
693   * @throws HeadlessException DOCUMENT ME!
694   */
695  public int showSaveDialog(Component parent) throws HeadlessException
696  {
697    JDialog d = createDialog(parent);
698    setDialogType(SAVE_DIALOG);
699
700    retval = ERROR_OPTION;
701
702    d.pack();
703    d.show();
704    return retval;
705  }
706
707  /**
708   * Displays the file chooser in a modal dialog using the 
709   * {@link #CUSTOM_DIALOG} type.
710   *
711   * @param parent  the parent component.
712   *
713   * @return A return value indicating how the dialog was closed (one of 
714   *         {@link #APPROVE_OPTION}, {@link #CANCEL_OPTION} and 
715   *         {@link #ERROR_OPTION}).
716   *
717   * @throws HeadlessException DOCUMENT ME!
718   */
719  public int showDialog(Component parent, String approveButtonText)
720                 throws HeadlessException
721  {
722    JDialog d = createDialog(parent);
723    setApproveButtonText(approveButtonText);
724    setDialogType(CUSTOM_DIALOG);
725
726    retval = ERROR_OPTION;
727
728    d.pack();
729    d.show();
730    return retval;
731  }
732
733  /**
734   * Creates a modal dialog in which to display the file chooser.
735   *
736   * @param parent  the parent component.
737   *
738   * @return The dialog.
739   *
740   * @throws HeadlessException DOCUMENT ME!
741   */
742  protected JDialog createDialog(Component parent) throws HeadlessException
743  {
744    Frame toUse = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, parent);
745    if (toUse == null)
746      toUse = (Frame) SwingUtilities.getOwnerFrame(null);
747
748    JDialog dialog = new JDialog(toUse);
749    setSelectedFile(null);
750    dialog.getContentPane().add(this);
751    dialog.addWindowListener( new WindowAdapter()
752      {
753        public void windowClosing(WindowEvent e)
754        {
755          cancelSelection();
756        }
757      });
758    dialog.setModal(true);
759    dialog.invalidate();
760    dialog.repaint();
761    return dialog;
762  }
763
764  /**
765   * Returns the flag that controls whether or not the control buttons are
766   * shown on the file chooser.
767   *
768   * @return A boolean.
769   * 
770   * @see #setControlButtonsAreShown(boolean)
771   */
772  public boolean getControlButtonsAreShown()
773  {
774    return controlButtonsShown;
775  }
776
777  /**
778   * Sets the flag that controls whether or not the control buttons are
779   * shown and, if it changes, sends a {@link PropertyChangeEvent} (with the
780   * property name {@link #CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY}) to
781   * all registered listeners.
782   *
783   * @param b  the new value for the flag.
784   */
785  public void setControlButtonsAreShown(boolean b)
786  {
787    if (controlButtonsShown != b)
788      {
789        controlButtonsShown = b;
790        firePropertyChange(CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY,
791                           ! controlButtonsShown, controlButtonsShown);
792      }
793  }
794
795  /**
796   * Returns the type of file chooser.
797   *
798   * @return {@link #OPEN_DIALOG}, {@link #SAVE_DIALOG} or 
799   * {@link #CUSTOM_DIALOG}.
800   * 
801   * @see #setDialogType(int)
802   */
803  public int getDialogType()
804  {
805    return dialogType;
806  }
807
808  /**
809   * Sets the dialog type and fires a {@link PropertyChangeEvent} (with the
810   * property name {@link #DIALOG_TYPE_CHANGED_PROPERTY}) to all 
811   * registered listeners.
812   *
813   * @param dialogType  the dialog type (one of: {@link #OPEN_DIALOG},
814   * {@link #SAVE_DIALOG}, {@link #CUSTOM_DIALOG}).
815   * 
816   * @throws IllegalArgumentException if <code>dialogType</code> is not valid.
817   */
818  public void setDialogType(int dialogType)
819  {
820    if (dialogType != OPEN_DIALOG && dialogType != SAVE_DIALOG
821        && dialogType != CUSTOM_DIALOG)
822      throw new IllegalArgumentException("Choose allowable dialogType.");
823
824    if (this.dialogType != dialogType)
825      {
826        int old = this.dialogType;
827        this.dialogType = dialogType;
828        firePropertyChange(DIALOG_TYPE_CHANGED_PROPERTY, old, this.dialogType);
829      }
830  }
831
832  /**
833   * Sets the dialog title and sends a {@link PropertyChangeEvent} (with the 
834   * property name {@link #DIALOG_TITLE_CHANGED_PROPERTY}) to all 
835   * registered listeners.
836   *
837   * @param dialogTitle  the dialog title (<code>null</code> permitted).
838   * 
839   * @see #getDialogTitle()
840   */
841  public void setDialogTitle(String dialogTitle)
842  {
843    if (this.dialogTitle != dialogTitle)
844      {
845        String old = this.dialogTitle;
846        this.dialogTitle = dialogTitle;
847        firePropertyChange(DIALOG_TITLE_CHANGED_PROPERTY, old, this.dialogTitle);
848      }
849  }
850
851  /**
852   * Returns the dialog title.
853   *
854   * @return The dialog title (possibly <code>null</code>).
855   * 
856   * @see #setDialogTitle(String)
857   */
858  public String getDialogTitle()
859  {
860    return dialogTitle;
861  }
862
863  /**
864   * Sets the tool tip text for the approve button and sends a 
865   * {@link PropertyChangeEvent} (with the property name
866   * {@link #APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY}) to all 
867   * registered listeners.
868   *
869   * @param toolTipText  the text.
870   */
871  public void setApproveButtonToolTipText(String toolTipText)
872  {
873    if (approveButtonToolTipText != toolTipText)
874      {
875        String oldText = approveButtonToolTipText;
876        approveButtonToolTipText = toolTipText;
877        firePropertyChange(APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY,
878                           oldText, approveButtonToolTipText);
879      }
880  }
881
882  /**
883   * Returns the tool tip text for the approve button.
884   *
885   * @return The tool tip text for the approve button.
886   * 
887   * @see #setApproveButtonToolTipText(String)
888   */
889  public String getApproveButtonToolTipText()
890  {
891    return approveButtonToolTipText;
892  }
893
894  /**
895   * Returns the approve button mnemonic, or zero if no mnemonic has been set.
896   *
897   * @return The approve button mnemonic.
898   * 
899   * @see #setApproveButtonMnemonic(int)
900   */
901  public int getApproveButtonMnemonic()
902  {
903    return approveButtonMnemonic;
904  }
905
906  /**
907   * Sets the mnemonic for the approve button and sends a 
908   * {@link PropertyChangeEvent} (with the property name 
909   * {@link #APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY}) to all registered 
910   * listeners.
911   *
912   * @param mnemonic  the mnemonic.
913   * 
914   * @see #setApproveButtonMnemonic(char)
915   */
916  public void setApproveButtonMnemonic(int mnemonic)
917  {
918    if (approveButtonMnemonic != mnemonic)
919      {
920        int oldMnemonic = approveButtonMnemonic;
921        approveButtonMnemonic = mnemonic;
922        firePropertyChange(APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY,
923                           oldMnemonic, approveButtonMnemonic);
924      }
925  }
926
927  /**
928   * Sets the mnemonic for the approve button and sends a 
929   * {@link PropertyChangeEvent} (with the property name 
930   * {@link #APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY}) to all registered 
931   * listeners.
932   *
933   * @param mnemonic  the mnemonic.
934   * 
935   * @see #setApproveButtonMnemonic(int)
936   */
937  public void setApproveButtonMnemonic(char mnemonic)
938  {
939    setApproveButtonMnemonic((int) Character.toUpperCase(mnemonic));
940  }
941
942  /**
943   * Sets the approve button text and fires a {@link PropertyChangeEvent} 
944   * (with the property name {@link #APPROVE_BUTTON_TEXT_CHANGED_PROPERTY}) to 
945   * all registered listeners.
946   *
947   * @param approveButtonText  the text (<code>null</code> permitted).
948   * 
949   * @see #getApproveButtonText()
950   */
951  public void setApproveButtonText(String approveButtonText)
952  {
953    if (this.approveButtonText != approveButtonText)
954      {
955        String oldText = this.approveButtonText;
956        this.approveButtonText = approveButtonText;
957        firePropertyChange(APPROVE_BUTTON_TEXT_CHANGED_PROPERTY, oldText,
958                           this.approveButtonText);
959      }
960  }
961
962  /**
963   * Returns the approve button text.
964   *
965   * @return The approve button text (possibly <code>null</code>).
966   * 
967   * @see #setApproveButtonText(String)
968   */
969  public String getApproveButtonText()
970  {
971    return approveButtonText;
972  }
973
974  /**
975   * Returns the available file filters for this file chooser.
976   *
977   * @return The available file filters.
978   */
979  public FileFilter[] getChoosableFileFilters()
980  {
981    return (FileFilter[]) choosableFilters.toArray(new FileFilter[choosableFilters.size()]);
982  }
983
984  /**
985   * Adds a file filter to the list of available filters and sends a 
986   * {@link PropertyChangeEvent} (with the property name 
987   * {@link #CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY}) to all registered 
988   * listeners.
989   *
990   * @param filter  the filter (<code>null</code> permitted).
991   */
992  public void addChoosableFileFilter(FileFilter filter)
993  {
994    if (filter != null)
995      {
996        FileFilter[] old = getChoosableFileFilters();
997        choosableFilters.add(filter);
998        FileFilter[] newFilters = getChoosableFileFilters();
999        firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, old, 
1000              newFilters);
1001      }
1002    setFileFilter(filter);
1003  }
1004
1005  /**
1006   * Removes a file filter from the list of available filters and sends a 
1007   * {@link PropertyChangeEvent} (with the property name 
1008   * {@link #CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY}) to all registered 
1009   * listeners.
1010   *
1011   * @param f  the file filter.
1012   *
1013   * @return <code>true</code> if the filter was removed and 
1014   *         <code>false</code> otherwise.
1015   */
1016  public boolean removeChoosableFileFilter(FileFilter f)
1017  {
1018    if (f == currentFilter)
1019      setFileFilter(null);
1020    FileFilter[] old = getChoosableFileFilters();
1021    if (! choosableFilters.remove(f))
1022      return false;
1023    FileFilter[] newFilters = getChoosableFileFilters();
1024    firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, old, newFilters);
1025    return true;
1026  }
1027
1028  /**
1029   * Clears the list of choosable file filters and installs the 'accept all'
1030   * filter from the UI delegate.
1031   */
1032  public void resetChoosableFileFilters()
1033  {
1034    choosableFilters.clear();
1035    choosableFilters.add(getUI().getAcceptAllFileFilter(this));
1036    setFileFilter((FileFilter) choosableFilters.get(0));
1037  }
1038
1039  /**
1040   * Returns the 'accept all' file filter from the UI delegate.
1041   *
1042   * @return The 'accept all' file filter.
1043   */
1044  public FileFilter getAcceptAllFileFilter()
1045  {
1046    return getUI().getAcceptAllFileFilter(this);
1047  }
1048
1049  /**
1050   * Returns the flag that controls whether or not the 'accept all' file 
1051   * filter is included in the list of filters.
1052   *
1053   * @return A boolean.
1054   * 
1055   * @see #setAcceptAllFileFilterUsed(boolean)
1056   */
1057  public boolean isAcceptAllFileFilterUsed()
1058  {
1059    return isAcceptAll;
1060  }
1061
1062  /**
1063   * Sets the flag that controls whether or not the 'accept all' file filter
1064   * is included in the list of filters, and sends a 
1065   * {@link PropertyChangeEvent} (with the property name 
1066   * {@link #ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY}) to all registered 
1067   * listeners.
1068   *
1069   * @param b  the new value of the flag.
1070   */
1071  public void setAcceptAllFileFilterUsed(boolean b)
1072  {
1073    if (isAcceptAll != b)
1074      {
1075        isAcceptAll = b;
1076        if (b)
1077          addChoosableFileFilter(getAcceptAllFileFilter());
1078        else 
1079          removeChoosableFileFilter(getAcceptAllFileFilter());
1080        firePropertyChange(ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY,
1081                           ! isAcceptAll, isAcceptAll);
1082      }
1083  }
1084
1085  /**
1086   * Returns the accessory component for the file chooser.  The default
1087   * value is <code>null</code>.
1088   *
1089   * @return The accessory component (possibly <code>null</code>).
1090   * 
1091   * @see #setAccessory(JComponent)
1092   */
1093  public JComponent getAccessory()
1094  {
1095    return accessory;
1096  }
1097
1098  /**
1099   * Sets the accessory component for the file chooser and sends a 
1100   * {@link PropertyChangeEvent} to all registered listeners.  The property
1101   * name is {@link #ACCESSORY_CHANGED_PROPERTY}.
1102   *
1103   * @param newAccessory  the accessory component.
1104   */
1105  public void setAccessory(JComponent newAccessory)
1106  {
1107    if (accessory != newAccessory)
1108      {
1109        JComponent old = accessory;
1110        accessory = newAccessory;
1111        firePropertyChange(ACCESSORY_CHANGED_PROPERTY, old, accessory);
1112      }
1113  }
1114
1115  /**
1116   * Sets the file selection mode and sends a {@link PropertyChangeEvent}
1117   * to all registered listeners.  The property name is 
1118   * {@link #FILE_SELECTION_MODE_CHANGED_PROPERTY}.
1119   *
1120   * @param mode  the mode ({@link #FILES_ONLY}, {@link #DIRECTORIES_ONLY} or
1121   *              {@link #FILES_AND_DIRECTORIES}).
1122   * 
1123   * @throws IllegalArgumentException if the mode is invalid.
1124   */
1125  public void setFileSelectionMode(int mode)
1126  {
1127    if (mode != FILES_ONLY && mode != DIRECTORIES_ONLY
1128        && mode != FILES_AND_DIRECTORIES)
1129      throw new IllegalArgumentException("Choose a correct file selection mode.");
1130    if (fileSelectionMode != mode)
1131      {
1132        int old = fileSelectionMode;
1133        fileSelectionMode = mode;
1134        firePropertyChange(FILE_SELECTION_MODE_CHANGED_PROPERTY, old,
1135                           fileSelectionMode);
1136      }
1137  }
1138
1139  /**
1140   * Returns the file selection mode, one of: {@link #FILES_ONLY}, 
1141   * {@link #DIRECTORIES_ONLY} or {@link #FILES_AND_DIRECTORIES}.  The
1142   * default is {@link #FILES_ONLY}.
1143   *
1144   * @return The file selection mode.
1145   * 
1146   * @see #setFileSelectionMode(int)
1147   */
1148  public int getFileSelectionMode()
1149  {
1150    return fileSelectionMode;
1151  }
1152
1153  /**
1154   * Returns <code>true</code> if file selection is enabled, and 
1155   * <code>false</code> otherwise.  File selection is enabled when the
1156   * file selection mode is {@link #FILES_ONLY} or 
1157   * {@link #FILES_AND_DIRECTORIES}.
1158   *
1159   * @return <code>true</code> if file selection is enabled.
1160   * 
1161   * @see #getFileSelectionMode()
1162   */
1163  public boolean isFileSelectionEnabled()
1164  {
1165    return (fileSelectionMode == FILES_ONLY
1166           || fileSelectionMode == FILES_AND_DIRECTORIES);
1167  }
1168
1169  /**
1170   * Returns <code>true</code> if directory selection is enabled, and 
1171   * <code>false</code> otherwise.  Directory selection is enabled when the
1172   * file selection mode is {@link #DIRECTORIES_ONLY} or 
1173   * {@link #FILES_AND_DIRECTORIES}.
1174   *
1175   * @return <code>true</code> if file selection is enabled.
1176   * 
1177   * @see #getFileSelectionMode()
1178   */
1179  public boolean isDirectorySelectionEnabled()
1180  {
1181    return (fileSelectionMode == DIRECTORIES_ONLY
1182           || fileSelectionMode == FILES_AND_DIRECTORIES);
1183  }
1184
1185  /**
1186   * Sets the flag that controls whether multiple selections are allowed in 
1187   * this filechooser and sends a {@link PropertyChangeEvent} (with the 
1188   * property name {@link #MULTI_SELECTION_ENABLED_CHANGED_PROPERTY}) to all 
1189   * registered listeners.
1190   *
1191   * @param b  the new value of the flag.
1192   */
1193  public void setMultiSelectionEnabled(boolean b)
1194  {
1195    if (multiSelection != b)
1196      {
1197        multiSelection = b;
1198        firePropertyChange(MULTI_SELECTION_ENABLED_CHANGED_PROPERTY,
1199                           ! multiSelection, multiSelection);
1200      }
1201  }
1202
1203  /**
1204   * Returns <code>true</code> if multiple selections are allowed within this
1205   * file chooser, and <code>false</code> otherwise.
1206   *
1207   * @return A boolean.
1208   * 
1209   * @see #setMultiSelectionEnabled(boolean)
1210   */
1211  public boolean isMultiSelectionEnabled()
1212  {
1213    return multiSelection;
1214  }
1215
1216  /**
1217   * Returns <code>true</code> if hidden files are to be hidden, and 
1218   * <code>false</code> otherwise.
1219   *
1220   * @return A boolean.
1221   * 
1222   * @see #setFileHidingEnabled(boolean)
1223   */
1224  public boolean isFileHidingEnabled()
1225  {
1226    return fileHiding;
1227  }
1228
1229  /**
1230   * Sets the flag that controls whether or not hidden files are displayed,
1231   * and sends a {@link PropertyChangeEvent} (with the property name
1232   * {@link #FILE_HIDING_CHANGED_PROPERTY}) to all registered listeners.
1233   *
1234   * @param b  the new value of the flag.
1235   */
1236  public void setFileHidingEnabled(boolean b)
1237  {
1238    if (fileHiding != b)
1239      {
1240        fileHiding = b;
1241        firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, ! fileHiding,
1242                           fileHiding);
1243      }
1244  }
1245
1246  /**
1247   * Sets the file filter and sends a {@link PropertyChangeEvent} (with the
1248   * property name {@link #FILE_FILTER_CHANGED_PROPERTY}) to all registered 
1249   * listeners.
1250   *
1251   * @param filter  the filter (<code>null</code> permitted).
1252   */
1253  public void setFileFilter(FileFilter filter)
1254  {
1255    if (currentFilter != filter)
1256      {
1257        if (filter != null && !choosableFilters.contains(filter))
1258          addChoosableFileFilter(filter);
1259        FileFilter old = currentFilter;
1260        currentFilter = filter;
1261        firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, old, currentFilter);
1262      }
1263  }
1264
1265  /**
1266   * Returns the file filter.
1267   *
1268   * @return The file filter.
1269   * 
1270   * @see #setFileFilter(FileFilter)
1271   */
1272  public FileFilter getFileFilter()
1273  {
1274    return currentFilter;
1275  }
1276
1277  /**
1278   * Sets a custom {@link FileView} for the file chooser and sends a 
1279   * {@link PropertyChangeEvent} to all registered listeners.  The property
1280   * name is {@link #FILE_VIEW_CHANGED_PROPERTY}.
1281   *
1282   * @param fileView  the file view (<code>null</code> permitted).
1283   *
1284   * @see #getFileView()
1285   */
1286  public void setFileView(FileView fileView)
1287  {
1288    if (fv != fileView)
1289      {
1290        FileView old = fv;
1291        fv = fileView;
1292        firePropertyChange(FILE_VIEW_CHANGED_PROPERTY, old, fv);
1293      }
1294  }
1295
1296  /**
1297   * Returns the custom {@link FileView} for the file chooser.
1298   *
1299   * @return The file view (possibly <code>null</code>).
1300   */
1301  public FileView getFileView()
1302  {
1303    return fv;
1304  }
1305
1306  /**
1307   * Returns the name of the file, generated by the current (or default)
1308   * {@link FileView}.
1309   *
1310   * @param f  the file.
1311   *
1312   * @return The file name.
1313   */
1314  public String getName(File f)
1315  {
1316    String name = null;
1317    if (fv != null)
1318      name = fv.getName(f);
1319    if (name == null)
1320      name = getUI().getFileView(this).getName(f);
1321    return name;
1322  }
1323
1324  /**
1325   * Returns the description of the file, generated by the current (or default)
1326   * {@link FileView}.
1327   *
1328   * @param f  the file.
1329   *
1330   * @return The file description.
1331   */
1332  public String getDescription(File f)
1333  {
1334    String result = null;
1335    if (fv != null)
1336      result = fv.getDescription(f);
1337    if (result == null)
1338      result = getUI().getFileView(this).getDescription(f);
1339    return result;
1340  }
1341
1342  /**
1343   * Returns the type description for the file, generated by the current (or 
1344   * default) {@link FileView}.
1345   *
1346   * @param f  the file.
1347   *
1348   * @return The file type description.
1349   */
1350  public String getTypeDescription(File f)
1351  {
1352    String result = null;
1353    if (fv != null)
1354      result = getFileView().getTypeDescription(f);
1355    if (result == null)
1356      result = getUI().getFileView(this).getTypeDescription(f);
1357    return result;
1358  }
1359
1360  /**
1361   * Returns the icon provided by the current (or default) {@link FileView}.
1362   *
1363   * @param f  the file.
1364   *
1365   * @return An icon representing the file.
1366   */
1367  public Icon getIcon(File f)
1368  {
1369    Icon result = null;
1370    if (fv != null)
1371      result = fv.getIcon(f);
1372    if (result == null)
1373      result = getUI().getFileView(this).getIcon(f);
1374    return result;
1375  }
1376
1377  /**
1378   * Returns <code>true</code> if the file is traversable, and 
1379   * <code>false</code> otherwise.
1380   *
1381   * @param f  the file or directory.
1382   *
1383   * @return A boolean.
1384   */
1385  public boolean isTraversable(File f)
1386  {
1387    return getFileSystemView().isTraversable(f).booleanValue();
1388  }
1389
1390  /**
1391   * Returns <code>true</code> if the file is accepted by the current
1392   * file filter.
1393   *
1394   * @param f  the file.
1395   *
1396   * @return A boolean.
1397   */
1398  public boolean accept(File f)
1399  {
1400    if (f == null)
1401      return true;
1402    FileFilter ff = getFileFilter();
1403    if (ff != null) 
1404      return ff.accept(f);
1405    else
1406      return true;
1407  }
1408
1409  /**
1410   * Sets the file system view for the file chooser and sends a 
1411   * {@link PropertyChangeEvent} to all registered listeners.
1412   *
1413   * @param fsv  the file system view.
1414   */
1415  public void setFileSystemView(FileSystemView fsv)
1416  {
1417    if (this.fsv != fsv)
1418      {
1419        FileSystemView old = this.fsv;
1420        this.fsv = fsv;
1421        firePropertyChange(FILE_SYSTEM_VIEW_CHANGED_PROPERTY, old, this.fsv);
1422      }
1423  }
1424
1425  /**
1426   * Returns the file system view being used by this file chooser.
1427   *
1428   * @return The file system view.
1429   * 
1430   * @see #setFileSystemView(FileSystemView)
1431   */
1432  public FileSystemView getFileSystemView()
1433  {
1434    return fsv;
1435  }
1436
1437  /**
1438   * Approves the selection.  An {@link ActionEvent} is sent to all registered
1439   * listeners.
1440   */
1441  public void approveSelection()
1442  {
1443    retval = APPROVE_OPTION;
1444    fireActionPerformed(APPROVE_SELECTION);
1445  }
1446
1447  /**
1448   * Cancels the selection. An {@link ActionEvent} is sent to all registered
1449   * listeners.
1450   */
1451  public void cancelSelection()
1452  {
1453    retval = CANCEL_OPTION;
1454    fireActionPerformed(CANCEL_SELECTION);
1455  }
1456
1457  /**
1458   * Adds an {@link ActionListener} to the file chooser.
1459   *
1460   * @param l  the listener.
1461   */
1462  public void addActionListener(ActionListener l)
1463  {
1464    listenerList.add(ActionListener.class, l);
1465  }
1466
1467  /**
1468   * Removes an {@link ActionListener} from this file chooser.
1469   *
1470   * @param l  the listener.
1471   */
1472  public void removeActionListener(ActionListener l)
1473  {
1474    try
1475      {
1476        listenerList.remove(ActionListener.class, l);
1477      }
1478    catch (IllegalArgumentException e)
1479      {
1480        e.printStackTrace();
1481      }
1482  }
1483
1484  /**
1485   * Returns the action listeners registered with this file chooser.
1486   *
1487   * @return An array of listeners.
1488   */
1489  public ActionListener[] getActionListeners()
1490  {
1491    return (ActionListener[]) getListeners(ActionListener.class);
1492  }
1493
1494  /**
1495   * Sends an @link {ActionEvent} to all registered listeners.
1496   *
1497   * @param command  the action command.
1498   */
1499  protected void fireActionPerformed(String command)
1500  {
1501    ActionListener[] list = getActionListeners();
1502    ActionEvent event = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
1503                                        command);
1504
1505    for (int i = 0; i < list.length; i++)
1506      list[i].actionPerformed(event);
1507  }
1508
1509  /**
1510   * Installs the UI delegate for the current look and feel.
1511   */
1512  public void updateUI()
1513  {
1514    setUI((FileChooserUI) UIManager.getUI(this));
1515  }
1516
1517  /**
1518   * Returns the UI delegate class identifier.
1519   *
1520   * @return <code>FileChooserUI</code>.
1521   */
1522  public String getUIClassID()
1523  {
1524    return "FileChooserUI";
1525  }
1526
1527  /**
1528   * Returns the UI delegate for the component.
1529   *
1530   * @return The UI delegate.
1531   */
1532  public FileChooserUI getUI()
1533  {
1534    return (FileChooserUI) ui;
1535  }
1536
1537  /**
1538   * Returns a string describing the attributes for the 
1539   * <code>JFileChooser</code> component, for use in debugging.  The return 
1540   * value is guaranteed to be non-<code>null</code>, but the format of the 
1541   * string may vary between implementations.
1542   *
1543   * @return A string describing the attributes of the 
1544   *     <code>JFileChooser</code>.
1545   */
1546  protected String paramString()
1547  {
1548    CPStringBuilder sb = new CPStringBuilder(super.paramString());
1549    sb.append(",approveButtonText=");
1550    if (approveButtonText != null)
1551      sb.append(approveButtonText);
1552    sb.append(",currentDirectory=");
1553    if (currentDir != null)
1554      sb.append(currentDir);
1555    sb.append(",dialogTitle=");
1556    if (dialogTitle != null)
1557      sb.append(dialogTitle);
1558    sb.append(",dialogType=");
1559    if (dialogType == OPEN_DIALOG)
1560      sb.append("OPEN_DIALOG");
1561    if (dialogType == SAVE_DIALOG)
1562      sb.append("SAVE_DIALOG");
1563    if (dialogType == CUSTOM_DIALOG)
1564      sb.append("CUSTOM_DIALOG");
1565    sb.append(",fileSelectionMode=");
1566    if (fileSelectionMode == FILES_ONLY)
1567      sb.append("FILES_ONLY");
1568    if (fileSelectionMode == DIRECTORIES_ONLY)
1569      sb.append("DIRECTORIES_ONLY");
1570    if (fileSelectionMode == FILES_AND_DIRECTORIES)
1571      sb.append("FILES_AND_DIRECTORIES");
1572    sb.append(",returnValue=");
1573    if (retval == APPROVE_OPTION)
1574      sb.append("APPROVE_OPTION");
1575    if (retval == CANCEL_OPTION)
1576      sb.append("CANCEL_OPTION");
1577    if (retval == ERROR_OPTION)
1578      sb.append("ERROR_OPTION");
1579    sb.append(",selectedFile=");
1580    if (selectedFile != null)
1581      sb.append(selectedFile);
1582    sb.append(",useFileHiding=").append(fileHiding);
1583    return sb.toString();
1584  }
1585
1586  /**
1587   * Returns the object that provides accessibility features for this
1588   * <code>JFileChooser</code> component.
1589   *
1590   * @return The accessible context (an instance of 
1591   *     {@link AccessibleJFileChooser}).
1592   */
1593  public AccessibleContext getAccessibleContext()
1594  {
1595    if (accessibleContext == null)
1596      accessibleContext = new AccessibleJFileChooser();
1597    return accessibleContext;
1598  }
1599
1600  /**
1601   * Provides the accessibility features for the <code>JFileChooser</code>
1602   * component.
1603   */
1604  protected class AccessibleJFileChooser 
1605    extends JComponent.AccessibleJComponent
1606  {
1607    /**
1608     * Creates a new instance of <code>AccessibleJFileChooser</code>.
1609     */
1610    protected AccessibleJFileChooser()
1611    {
1612      // Nothing to do here.
1613    }
1614    
1615    /**
1616     * Returns the accessible role for the <code>JFileChooser</code> 
1617     * component.
1618     *
1619     * @return {@link AccessibleRole#FILE_CHOOSER}.
1620     */
1621    public AccessibleRole getAccessibleRole()
1622    {
1623      return AccessibleRole.FILE_CHOOSER;
1624    }
1625  }
1626}